From ceed8a2f688f48dc561762b7638a04022a706963 Mon Sep 17 00:00:00 2001 From: Eugene Zagidullin Date: Wed, 7 Aug 2024 22:57:26 +0300 Subject: [PATCH 1/6] migrate to aws-sdk-go-v2 --- go.mod | 14 ++++++++++++++ go.sum | 28 +++++++++++++++++++++++++++ pkg/vault/aws/awskms.go | 42 +++++++++++++++++++++++------------------ 3 files changed, 66 insertions(+), 18 deletions(-) diff --git a/go.mod b/go.mod index af1ac739..54e29baa 100644 --- a/go.mod +++ b/go.mod @@ -31,6 +31,20 @@ require ( cloud.google.com/go/compute v1.23.3 // indirect cloud.google.com/go/compute/metadata v0.2.3 // indirect cloud.google.com/go/iam v1.1.5 // indirect + github.com/aws/aws-sdk-go-v2 v1.30.3 // indirect + github.com/aws/aws-sdk-go-v2/config v1.27.27 // indirect + github.com/aws/aws-sdk-go-v2/credentials v1.17.27 // indirect + github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.11 // indirect + github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.15 // indirect + github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.15 // indirect + github.com/aws/aws-sdk-go-v2/internal/ini v1.8.0 // indirect + github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.11.3 // indirect + github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.11.17 // indirect + github.com/aws/aws-sdk-go-v2/service/kms v1.35.3 // indirect + github.com/aws/aws-sdk-go-v2/service/sso v1.22.4 // indirect + github.com/aws/aws-sdk-go-v2/service/ssooidc v1.26.4 // indirect + github.com/aws/aws-sdk-go-v2/service/sts v1.30.3 // indirect + github.com/aws/smithy-go v1.20.3 // indirect github.com/cenkalti/backoff/v3 v3.2.2 // indirect github.com/cespare/xxhash/v2 v2.2.0 // indirect github.com/ecadlabs/pretty v0.0.0-20230412124801-f948fc689a04 // indirect diff --git a/go.sum b/go.sum index 9ed84589..44a32377 100644 --- a/go.sum +++ b/go.sum @@ -13,6 +13,34 @@ github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03 github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= github.com/aws/aws-sdk-go v1.48.11 h1:9YbiSbaF/jWi+qLRl+J5dEhr2mcbDYHmKg2V7RBcD5M= github.com/aws/aws-sdk-go v1.48.11/go.mod h1:LF8svs817+Nz+DmiMQKTO3ubZ/6IaTpq3TjupRn3Eqk= +github.com/aws/aws-sdk-go-v2 v1.30.3 h1:jUeBtG0Ih+ZIFH0F4UkmL9w3cSpaMv9tYYDbzILP8dY= +github.com/aws/aws-sdk-go-v2 v1.30.3/go.mod h1:nIQjQVp5sfpQcTc9mPSr1B0PaWK5ByX9MOoDadSN4lc= +github.com/aws/aws-sdk-go-v2/config v1.27.27 h1:HdqgGt1OAP0HkEDDShEl0oSYa9ZZBSOmKpdpsDMdO90= +github.com/aws/aws-sdk-go-v2/config v1.27.27/go.mod h1:MVYamCg76dFNINkZFu4n4RjDixhVr51HLj4ErWzrVwg= +github.com/aws/aws-sdk-go-v2/credentials v1.17.27 h1:2raNba6gr2IfA0eqqiP2XiQ0UVOpGPgDSi0I9iAP+UI= +github.com/aws/aws-sdk-go-v2/credentials v1.17.27/go.mod h1:gniiwbGahQByxan6YjQUMcW4Aov6bLC3m+evgcoN4r4= +github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.11 h1:KreluoV8FZDEtI6Co2xuNk/UqI9iwMrOx/87PBNIKqw= +github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.11/go.mod h1:SeSUYBLsMYFoRvHE0Tjvn7kbxaUhl75CJi1sbfhMxkU= +github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.15 h1:SoNJ4RlFEQEbtDcCEt+QG56MY4fm4W8rYirAmq+/DdU= +github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.15/go.mod h1:U9ke74k1n2bf+RIgoX1SXFed1HLs51OgUSs+Ph0KJP8= +github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.15 h1:C6WHdGnTDIYETAm5iErQUiVNsclNx9qbJVPIt03B6bI= +github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.15/go.mod h1:ZQLZqhcu+JhSrA9/NXRm8SkDvsycE+JkV3WGY41e+IM= +github.com/aws/aws-sdk-go-v2/internal/ini v1.8.0 h1:hT8rVHwugYE2lEfdFE0QWVo81lF7jMrYJVDWI+f+VxU= +github.com/aws/aws-sdk-go-v2/internal/ini v1.8.0/go.mod h1:8tu/lYfQfFe6IGnaOdrpVgEL2IrrDOf6/m9RQum4NkY= +github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.11.3 h1:dT3MqvGhSoaIhRseqw2I0yH81l7wiR2vjs57O51EAm8= +github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.11.3/go.mod h1:GlAeCkHwugxdHaueRr4nhPuY+WW+gR8UjlcqzPr1SPI= +github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.11.17 h1:HGErhhrxZlQ044RiM+WdoZxp0p+EGM62y3L6pwA4olE= +github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.11.17/go.mod h1:RkZEx4l0EHYDJpWppMJ3nD9wZJAa8/0lq9aVC+r2UII= +github.com/aws/aws-sdk-go-v2/service/kms v1.35.3 h1:UPTdlTOwWUX49fVi7cymEN6hDqCwe3LNv1vi7TXUutk= +github.com/aws/aws-sdk-go-v2/service/kms v1.35.3/go.mod h1:gjDP16zn+WWalyaUqwCCioQ8gU8lzttCCc9jYsiQI/8= +github.com/aws/aws-sdk-go-v2/service/sso v1.22.4 h1:BXx0ZIxvrJdSgSvKTZ+yRBeSqqgPM89VPlulEcl37tM= +github.com/aws/aws-sdk-go-v2/service/sso v1.22.4/go.mod h1:ooyCOXjvJEsUw7x+ZDHeISPMhtwI3ZCB7ggFMcFfWLU= +github.com/aws/aws-sdk-go-v2/service/ssooidc v1.26.4 h1:yiwVzJW2ZxZTurVbYWA7QOrAaCYQR72t0wrSBfoesUE= +github.com/aws/aws-sdk-go-v2/service/ssooidc v1.26.4/go.mod h1:0oxfLkpz3rQ/CHlx5hB7H69YUpFiI1tql6Q6Ne+1bCw= +github.com/aws/aws-sdk-go-v2/service/sts v1.30.3 h1:ZsDKRLXGWHk8WdtyYMoGNO7bTudrvuKpDKgMVRlepGE= +github.com/aws/aws-sdk-go-v2/service/sts v1.30.3/go.mod h1:zwySh8fpFyXp9yOr/KVzxOl8SRqgf/IDw5aUt9UKFcQ= +github.com/aws/smithy-go v1.20.3 h1:ryHwveWzPV5BIof6fyDvor6V3iUL7nTfiTKXHiW05nE= +github.com/aws/smithy-go v1.20.3/go.mod h1:krry+ya/rV9RDcV/Q16kpu6ypI4K2czasz0NC3qS14E= github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= diff --git a/pkg/vault/aws/awskms.go b/pkg/vault/aws/awskms.go index f7dae4ee..1a8505c5 100644 --- a/pkg/vault/aws/awskms.go +++ b/pkg/vault/aws/awskms.go @@ -6,10 +6,10 @@ import ( "fmt" "os" - "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/aws/awserr" - "github.com/aws/aws-sdk-go/aws/session" - "github.com/aws/aws-sdk-go/service/kms" + awsconfig "github.com/aws/aws-sdk-go-v2/config" + "github.com/aws/aws-sdk-go-v2/service/kms" + "github.com/aws/aws-sdk-go-v2/service/kms/types" + "github.com/aws/smithy-go" "github.com/ecadlabs/gotez/v2/crypt" "github.com/ecadlabs/signatory/pkg/config" "github.com/ecadlabs/signatory/pkg/cryptoutils" @@ -27,7 +27,7 @@ type Config struct { } type Vault struct { - kmsapi *kms.KMS + client *kms.Client config Config } @@ -40,7 +40,7 @@ type awsKMSKey struct { type awsKMSIterator struct { ctx context.Context v *Vault - kmsapi *kms.KMS + client *kms.Client lko *kms.ListKeysOutput index int } @@ -56,14 +56,14 @@ func (c *awsKMSKey) ID() string { } func (v *Vault) GetPublicKey(ctx context.Context, keyID string) (vault.StoredKey, error) { - pkresp, err := v.kmsapi.GetPublicKeyWithContext(ctx, &kms.GetPublicKeyInput{ + pkresp, err := v.client.GetPublicKey(ctx, &kms.GetPublicKeyInput{ KeyId: &keyID, }) if err != nil { return nil, err } - if *pkresp.KeyUsage != kms.KeyUsageTypeSignVerify { + if pkresp.KeyUsage != types.KeyUsageTypeSignVerify { return nil, errors.New("key usage must be SIGN_VERIFY") } @@ -97,7 +97,8 @@ func (i *awsKMSIterator) Next() (key vault.StoredKey, err error) { Marker: i.lko.NextMarker, } } // otherwise leave it nil - i.lko, err = i.kmsapi.ListKeys(lkin) + + i.lko, err = i.client.ListKeys(i.ctx, lkin) if err != nil { return nil, err } @@ -106,10 +107,11 @@ func (i *awsKMSIterator) Next() (key vault.StoredKey, err error) { key, err = i.v.GetPublicKey(i.ctx, *i.lko.Keys[i.index].KeyId) i.index += 1 + var kmserr smithy.APIError if err == nil { return key, nil - } else if awsErr, ok := err.(awserr.Error); ok { - if awsErr.Code() != "AccessDeniedException" { + } else if errors.As(err, &kmserr) { + if kmserr.ErrorCode() != "AccessDeniedException" { return nil, err } } else if err != crypt.ErrUnsupportedKeyType { @@ -123,7 +125,7 @@ func (v *Vault) ListPublicKeys(ctx context.Context) vault.StoredKeysIterator { return &awsKMSIterator{ ctx: ctx, v: v, - kmsapi: v.kmsapi, + client: v.client, } } @@ -135,11 +137,11 @@ func (v *Vault) Name() string { func (v *Vault) SignMessage(ctx context.Context, message []byte, key vault.StoredKey) (crypt.Signature, error) { digest := crypt.DigestFunc(message) kid := key.ID() - sout, err := v.kmsapi.Sign(&kms.SignInput{ + sout, err := v.client.Sign(ctx, &kms.SignInput{ KeyId: &kid, Message: digest[:], - MessageType: aws.String(kms.MessageTypeDigest), - SigningAlgorithm: aws.String(kms.SigningAlgorithmSpecEcdsaSha256), + MessageType: types.MessageTypeDigest, + SigningAlgorithm: types.SigningAlgorithmSpecEcdsaSha256, }) if err != nil { return nil, err @@ -160,11 +162,15 @@ func New(ctx context.Context, config *Config) (*Vault, error) { os.Setenv("AWS_SECRET_ACCESS_KEY", config.AccessKey) } os.Setenv("AWS_REGION", config.Region) - sess := session.Must(session.NewSession()) - api := kms.New(sess) + cfg, err := awsconfig.LoadDefaultConfig(ctx) + if err != nil { + return nil, err + } + + client := kms.NewFromConfig(cfg) return &Vault{ - kmsapi: api, + client: client, config: *config, }, nil } From 5845ddca6c60cfb01cf1ce0bafaad864fbb011b4 Mon Sep 17 00:00:00 2001 From: Eugene Zagidullin Date: Wed, 7 Aug 2024 22:57:45 +0300 Subject: [PATCH 2/6] mod tidy --- go.mod | 8 +++----- go.sum | 19 ------------------- 2 files changed, 3 insertions(+), 24 deletions(-) diff --git a/go.mod b/go.mod index 54e29baa..67bdb659 100644 --- a/go.mod +++ b/go.mod @@ -4,6 +4,9 @@ go 1.21 require ( cloud.google.com/go/kms v1.15.5 + github.com/aws/aws-sdk-go-v2/config v1.27.27 + github.com/aws/aws-sdk-go-v2/service/kms v1.35.3 + github.com/aws/smithy-go v1.20.3 github.com/certusone/yubihsm-go v0.3.0 github.com/decred/dcrd/dcrec/secp256k1/v4 v4.2.0 github.com/ecadlabs/goblst v1.0.0 @@ -32,7 +35,6 @@ require ( cloud.google.com/go/compute/metadata v0.2.3 // indirect cloud.google.com/go/iam v1.1.5 // indirect github.com/aws/aws-sdk-go-v2 v1.30.3 // indirect - github.com/aws/aws-sdk-go-v2/config v1.27.27 // indirect github.com/aws/aws-sdk-go-v2/credentials v1.17.27 // indirect github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.11 // indirect github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.15 // indirect @@ -40,11 +42,9 @@ require ( github.com/aws/aws-sdk-go-v2/internal/ini v1.8.0 // indirect github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.11.3 // indirect github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.11.17 // indirect - github.com/aws/aws-sdk-go-v2/service/kms v1.35.3 // indirect github.com/aws/aws-sdk-go-v2/service/sso v1.22.4 // indirect github.com/aws/aws-sdk-go-v2/service/ssooidc v1.26.4 // indirect github.com/aws/aws-sdk-go-v2/service/sts v1.30.3 // indirect - github.com/aws/smithy-go v1.20.3 // indirect github.com/cenkalti/backoff/v3 v3.2.2 // indirect github.com/cespare/xxhash/v2 v2.2.0 // indirect github.com/ecadlabs/pretty v0.0.0-20230412124801-f948fc689a04 // indirect @@ -61,7 +61,6 @@ require ( github.com/hashicorp/go-secure-stdlib/strutil v0.1.2 // indirect github.com/hashicorp/go-sockaddr v1.0.6 // indirect github.com/hashicorp/hcl v1.0.0 // indirect - github.com/jmespath/go-jmespath v0.4.0 // indirect github.com/kr/text v0.2.0 // indirect github.com/matttproud/golang_protobuf_extensions/v2 v2.0.0 // indirect github.com/mitchellh/go-homedir v1.1.0 // indirect @@ -76,7 +75,6 @@ require ( ) require ( - github.com/aws/aws-sdk-go v1.48.11 github.com/beorn7/perks v1.0.1 // indirect github.com/davecgh/go-spew v1.1.1 // indirect github.com/enceve/crypto v0.0.0-20160707101852-34d48bb93815 // indirect diff --git a/go.sum b/go.sum index 44a32377..28ad594d 100644 --- a/go.sum +++ b/go.sum @@ -11,8 +11,6 @@ cloud.google.com/go/kms v1.15.5 h1:pj1sRfut2eRbD9pFRjNnPNg/CzJPuQAzUujMIM1vVeM= cloud.google.com/go/kms v1.15.5/go.mod h1:cU2H5jnp6G2TDpUGZyqTCoy1n16fbubHZjmVXSMtwDI= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= -github.com/aws/aws-sdk-go v1.48.11 h1:9YbiSbaF/jWi+qLRl+J5dEhr2mcbDYHmKg2V7RBcD5M= -github.com/aws/aws-sdk-go v1.48.11/go.mod h1:LF8svs817+Nz+DmiMQKTO3ubZ/6IaTpq3TjupRn3Eqk= github.com/aws/aws-sdk-go-v2 v1.30.3 h1:jUeBtG0Ih+ZIFH0F4UkmL9w3cSpaMv9tYYDbzILP8dY= github.com/aws/aws-sdk-go-v2 v1.30.3/go.mod h1:nIQjQVp5sfpQcTc9mPSr1B0PaWK5ByX9MOoDadSN4lc= github.com/aws/aws-sdk-go-v2/config v1.27.27 h1:HdqgGt1OAP0HkEDDShEl0oSYa9ZZBSOmKpdpsDMdO90= @@ -63,8 +61,6 @@ github.com/decred/dcrd/dcrec/secp256k1/v4 v4.2.0 h1:8UrgZ3GkP4i/CLijOJx79Yu+etly github.com/decred/dcrd/dcrec/secp256k1/v4 v4.2.0/go.mod h1:v57UDF4pDQJcEfFUCRop3lJL149eHGSe9Jvczhzjo/0= github.com/ecadlabs/goblst v1.0.0 h1:8/e3SQGwqbV0+ul+pg0aSNFfC3lgQcvEed3VdDBXSl8= github.com/ecadlabs/goblst v1.0.0/go.mod h1:s67gqaOol9o6fguh+evH75X5uQniOhv1HG/EU8xPLPY= -github.com/ecadlabs/gotez/v2 v2.0.5 h1:RmpCEKYlQD18TtL9vjSDRe3FYADhxlKh80DZQz8h31Q= -github.com/ecadlabs/gotez/v2 v2.0.5/go.mod h1:QypK0m1eDPmB9R7Uvgmsfm+JS7Z5Y6dIbIq1tMVYayU= github.com/ecadlabs/gotez/v2 v2.0.6 h1:P7eQ2G+SO1tTV4NHnkdNlrOHxKDo1iF9m34HTLfS3b8= github.com/ecadlabs/gotez/v2 v2.0.6/go.mod h1:QypK0m1eDPmB9R7Uvgmsfm+JS7Z5Y6dIbIq1tMVYayU= github.com/ecadlabs/pretty v0.0.0-20230412124801-f948fc689a04 h1:7WdblGykGxtGGtchW4kzTaJJO8Fm+JKhLzhttOOWr9k= @@ -171,10 +167,6 @@ github.com/hashicorp/vault/api/auth/approle v0.5.0 h1:a1TK6VGwYqSAfkmX4y4dJ4WBxM github.com/hashicorp/vault/api/auth/approle v0.5.0/go.mod h1:CHOQIA1AZACfjTzHggmyfiOZ+xCSKNRFqe48FTCzH0k= github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8= github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= -github.com/jmespath/go-jmespath v0.4.0 h1:BEgLn5cpjn8UN1mAw4NjwDrS35OdebyEtFe+9YPoQUg= -github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo= -github.com/jmespath/go-jmespath/internal/testify v1.5.1 h1:shLQSRRSCCPj3f2gpwzGwWFoC7ycTf1rcQZHOlsJ6N8= -github.com/jmespath/go-jmespath/internal/testify v1.5.1/go.mod h1:L3OGu8Wl2/fWfCI6z80xFu9LTZmf1ZRjMHUOPmWr69U= github.com/karalabe/hid v1.0.0 h1:+/CIMNXhSU/zIJgnIvBD2nKHxS/bnRHhhs9xBryLpPo= github.com/karalabe/hid v1.0.0/go.mod h1:Vr51f8rUOLYrfrWDFlV12GGQgM5AT8sVh+2fY4MPeu8= github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= @@ -250,8 +242,6 @@ golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPh golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.6.0/go.mod h1:OFC/31mSvZgRz0V1QTNCzfAI1aIRzbiufJtkMIlEp58= -golang.org/x/crypto v0.22.0 h1:g1v0xeRhjcugydODzvb3mEM9SQ0HGp9s/nh3COQ/C30= -golang.org/x/crypto v0.22.0/go.mod h1:vr6Su+7cTlO45qkww3VDJlzDn0ctJvRgYbC2NvXHt+M= golang.org/x/crypto v0.23.0 h1:dIJU/v2J8Mdglj/8rJ6UUOM3Zc9zLZxVZwwxMooUSAI= golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= @@ -298,15 +288,11 @@ golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.19.0 h1:q5f1RH2jigJ1MoAWp2KTp3gm5zAGFUTarQZ5U386+4o= -golang.org/x/sys v0.19.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.20.0 h1:Od9JTbYCk261bKm4M/mw7AklTlFYIa0bIp9BgSm1S8Y= golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= -golang.org/x/term v0.19.0 h1:+ThwsDv+tYfnJFhF4L8jITxu1tdTWRTZpdsWgEgjL6Q= -golang.org/x/term v0.19.0/go.mod h1:2CuTdWZ7KHSQwUzKva0cbMg6q2DMI3Mmxp+gKJbskEk= golang.org/x/term v0.20.0 h1:VnkxpohqXaOBYJtBmEppKUG6mXpi+4O6purfc2+sMhw= golang.org/x/term v0.20.0/go.mod h1:8UkIAJTvZgivsXaD6/pH6U9ecQzZ45awqEOzuCvwpFY= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= @@ -314,8 +300,6 @@ golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ= golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= -golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ= -golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= golang.org/x/text v0.15.0 h1:h1V/4gjBv8v9cjcR6+AR5+/cIYK5N/WAgiv4xlsEtAk= golang.org/x/text v0.15.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= golang.org/x/time v0.0.0-20200416051211-89c76fbcd5d1/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= @@ -368,9 +352,6 @@ google.golang.org/protobuf v1.31.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqw gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= -gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= -gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= From 1631d599ed1ae15da20cdfc5b1fa1e0dbe6c0661 Mon Sep 17 00:00:00 2001 From: Eugene Zagidullin Date: Wed, 7 Aug 2024 23:12:23 +0300 Subject: [PATCH 3/6] watermark moved to subpackage --- pkg/signatory/policy_hook_test.go | 5 +++-- pkg/signatory/signatory.go | 3 ++- pkg/signatory/signatory_test.go | 7 ++++--- pkg/signatory/{ => watermark}/watermark.go | 10 +++++----- pkg/signatory/{ => watermark}/watermark_file.go | 14 +++++++------- pkg/signatory/{ => watermark}/watermark_mem.go | 12 ++++++------ .../{ => watermark}/watermark_migration.go | 2 +- pkg/signatory/{ => watermark}/watermark_test.go | 4 ++-- 8 files changed, 30 insertions(+), 27 deletions(-) rename pkg/signatory/{ => watermark}/watermark.go (55%) rename pkg/signatory/{ => watermark}/watermark_file.go (92%) rename pkg/signatory/{ => watermark}/watermark_mem.go (71%) rename pkg/signatory/{ => watermark}/watermark_migration.go (99%) rename pkg/signatory/{ => watermark}/watermark_test.go (98%) diff --git a/pkg/signatory/policy_hook_test.go b/pkg/signatory/policy_hook_test.go index 41a91cf9..df7aacd8 100644 --- a/pkg/signatory/policy_hook_test.go +++ b/pkg/signatory/policy_hook_test.go @@ -17,6 +17,7 @@ import ( "github.com/ecadlabs/signatory/pkg/config" "github.com/ecadlabs/signatory/pkg/hashmap" "github.com/ecadlabs/signatory/pkg/signatory" + "github.com/ecadlabs/signatory/pkg/signatory/watermark" "github.com/ecadlabs/signatory/pkg/vault" "github.com/ecadlabs/signatory/pkg/vault/memory" "github.com/stretchr/testify/require" @@ -99,7 +100,7 @@ func testPolicyHookAuth(t *testing.T, status int) error { conf := signatory.Config{ Vaults: map[string]*config.VaultConfig{"mock": {Driver: "mock"}}, - Watermark: signatory.IgnoreWatermark{}, + Watermark: watermark.Ignore{}, VaultFactory: vault.FactoryFunc(func(ctx context.Context, name string, conf *yaml.Node) (vault.Vault, error) { return memory.New([]*memory.PrivateKey{ { @@ -138,7 +139,7 @@ func testPolicyHook(t *testing.T, status int) error { conf := signatory.Config{ Vaults: map[string]*config.VaultConfig{"mock": {Driver: "mock"}}, - Watermark: signatory.IgnoreWatermark{}, + Watermark: watermark.Ignore{}, VaultFactory: vault.FactoryFunc(func(ctx context.Context, name string, conf *yaml.Node) (vault.Vault, error) { return memory.New([]*memory.PrivateKey{ { diff --git a/pkg/signatory/signatory.go b/pkg/signatory/signatory.go index 2d8d1175..0fead5b8 100644 --- a/pkg/signatory/signatory.go +++ b/pkg/signatory/signatory.go @@ -25,6 +25,7 @@ import ( "github.com/ecadlabs/signatory/pkg/errors" "github.com/ecadlabs/signatory/pkg/hashmap" "github.com/ecadlabs/signatory/pkg/signatory/request" + "github.com/ecadlabs/signatory/pkg/signatory/watermark" "github.com/ecadlabs/signatory/pkg/vault" log "github.com/sirupsen/logrus" "gopkg.in/yaml.v3" @@ -544,7 +545,7 @@ type Config struct { Policy Policy Vaults map[string]*config.VaultConfig Interceptor SignInterceptor - Watermark Watermark + Watermark watermark.Watermark Logger log.FieldLogger VaultFactory vault.Factory PolicyHook *PolicyHook diff --git a/pkg/signatory/signatory_test.go b/pkg/signatory/signatory_test.go index 681bb467..f31938dc 100644 --- a/pkg/signatory/signatory_test.go +++ b/pkg/signatory/signatory_test.go @@ -12,6 +12,7 @@ import ( "github.com/ecadlabs/signatory/pkg/config" "github.com/ecadlabs/signatory/pkg/hashmap" "github.com/ecadlabs/signatory/pkg/signatory" + "github.com/ecadlabs/signatory/pkg/signatory/watermark" "github.com/ecadlabs/signatory/pkg/vault" "github.com/ecadlabs/signatory/pkg/vault/memory" "github.com/stretchr/testify/require" @@ -23,7 +24,7 @@ const privateKey = "edsk4FTF78Qf1m2rykGpHqostAiq5gYW4YZEoGUSWBTJr2njsDHSnd" func TestImport(t *testing.T) { conf := signatory.Config{ Vaults: map[string]*config.VaultConfig{"mock": {Driver: "mock"}}, - Watermark: signatory.IgnoreWatermark{}, + Watermark: watermark.Ignore{}, VaultFactory: vault.FactoryFunc(func(ctx context.Context, name string, conf *yaml.Node) (vault.Vault, error) { v, err := memory.New(nil, "Mock") if err != nil { @@ -310,7 +311,7 @@ func TestPolicy(t *testing.T) { t.Run(c.title, func(t *testing.T) { conf := signatory.Config{ Vaults: map[string]*config.VaultConfig{"mock": {Driver: "mock"}}, - Watermark: signatory.IgnoreWatermark{}, + Watermark: watermark.Ignore{}, VaultFactory: vault.FactoryFunc(func(ctx context.Context, name string, conf *yaml.Node) (vault.Vault, error) { return memory.NewUnparsed([]*memory.UnparsedKey{{Data: privateKey}}, "Mock"), nil }), @@ -400,7 +401,7 @@ func TestListPublicKeys(t *testing.T) { t.Run(c.title, func(t *testing.T) { conf := signatory.Config{ Vaults: map[string]*config.VaultConfig{"test": {Driver: "test"}}, - Watermark: signatory.IgnoreWatermark{}, + Watermark: watermark.Ignore{}, VaultFactory: vault.FactoryFunc(func(ctx context.Context, name string, conf *yaml.Node) (vault.Vault, error) { return NewTestVault(nil, c.lpk, nil, nil, "test"), nil }), diff --git a/pkg/signatory/watermark.go b/pkg/signatory/watermark/watermark.go similarity index 55% rename from pkg/signatory/watermark.go rename to pkg/signatory/watermark/watermark.go index 043ab247..ff202c96 100644 --- a/pkg/signatory/watermark.go +++ b/pkg/signatory/watermark/watermark.go @@ -1,4 +1,4 @@ -package signatory +package watermark import ( "github.com/ecadlabs/gotez/v2/crypt" @@ -10,12 +10,12 @@ type Watermark interface { IsSafeToSign(pkh crypt.PublicKeyHash, req protocol.SignRequest, digest *crypt.Digest) error } -// IgnoreWatermark watermark that do not validation and return true -type IgnoreWatermark struct{} +// Ignore watermark that do not validation and return true +type Ignore struct{} // IsSafeToSign always return true -func (w IgnoreWatermark) IsSafeToSign(crypt.PublicKeyHash, protocol.SignRequest, *crypt.Digest) error { +func (w Ignore) IsSafeToSign(crypt.PublicKeyHash, protocol.SignRequest, *crypt.Digest) error { return nil } -var _ Watermark = (*IgnoreWatermark)(nil) +var _ Watermark = (*Ignore)(nil) diff --git a/pkg/signatory/watermark_file.go b/pkg/signatory/watermark/watermark_file.go similarity index 92% rename from pkg/signatory/watermark_file.go rename to pkg/signatory/watermark/watermark_file.go index 0a8def77..b6ce7556 100644 --- a/pkg/signatory/watermark_file.go +++ b/pkg/signatory/watermark/watermark_file.go @@ -1,4 +1,4 @@ -package signatory +package watermark import ( "bufio" @@ -19,9 +19,9 @@ import ( log "github.com/sirupsen/logrus" ) -type FileWatermark struct { +type File struct { baseDir string - mem InMemoryWatermark + mem InMemory } // chain -> delegate(pkh) -> request type -> watermark @@ -69,8 +69,8 @@ func tryLoad(baseDir string) (map[tz.ChainID]delegateMap, error) { return out, nil } -func NewFileWatermark(baseDir string) (*FileWatermark, error) { - wm := FileWatermark{ +func NewFileWatermark(baseDir string) (*File, error) { + wm := File{ baseDir: baseDir, } var err error @@ -147,7 +147,7 @@ func writeWatermarkData(baseDir string, data delegateMap, chain *tz.ChainID) err return w.Flush() } -func (f *FileWatermark) IsSafeToSign(pkh crypt.PublicKeyHash, req protocol.SignRequest, digest *crypt.Digest) error { +func (f *File) IsSafeToSign(pkh crypt.PublicKeyHash, req protocol.SignRequest, digest *crypt.Digest) error { m, ok := req.(request.WithWatermark) if !ok { // watermark is not required @@ -163,4 +163,4 @@ func (f *FileWatermark) IsSafeToSign(pkh crypt.PublicKeyHash, req protocol.SignR return writeWatermarkData(f.baseDir, f.mem.chains[*chain], chain) } -var _ Watermark = (*FileWatermark)(nil) +var _ Watermark = (*File)(nil) diff --git a/pkg/signatory/watermark_mem.go b/pkg/signatory/watermark/watermark_mem.go similarity index 71% rename from pkg/signatory/watermark_mem.go rename to pkg/signatory/watermark/watermark_mem.go index 8fa59187..c8385288 100644 --- a/pkg/signatory/watermark_mem.go +++ b/pkg/signatory/watermark/watermark_mem.go @@ -1,4 +1,4 @@ -package signatory +package watermark import ( "sync" @@ -9,20 +9,20 @@ import ( "github.com/ecadlabs/signatory/pkg/signatory/request" ) -// InMemoryWatermark keep previous operation in memory -type InMemoryWatermark struct { +// InMemory keep previous operation in memory +type InMemory struct { chains map[tz.ChainID]delegateMap mtx sync.Mutex } // IsSafeToSign return true if this msgID is safe to sign -func (w *InMemoryWatermark) IsSafeToSign(pkh crypt.PublicKeyHash, req protocol.SignRequest, digest *crypt.Digest) error { +func (w *InMemory) IsSafeToSign(pkh crypt.PublicKeyHash, req protocol.SignRequest, digest *crypt.Digest) error { w.mtx.Lock() defer w.mtx.Unlock() return w.isSafeToSignUnlocked(pkh, req, digest) } -func (w *InMemoryWatermark) isSafeToSignUnlocked(pkh crypt.PublicKeyHash, req protocol.SignRequest, digest *crypt.Digest) error { +func (w *InMemory) isSafeToSignUnlocked(pkh crypt.PublicKeyHash, req protocol.SignRequest, digest *crypt.Digest) error { m, ok := req.(request.WithWatermark) if !ok { // watermark is not required @@ -55,4 +55,4 @@ func (w *InMemoryWatermark) isSafeToSignUnlocked(pkh crypt.PublicKeyHash, req pr return nil } -var _ Watermark = (*InMemoryWatermark)(nil) +var _ Watermark = (*InMemory)(nil) diff --git a/pkg/signatory/watermark_migration.go b/pkg/signatory/watermark/watermark_migration.go similarity index 99% rename from pkg/signatory/watermark_migration.go rename to pkg/signatory/watermark/watermark_migration.go index 7d7329f1..329914ab 100644 --- a/pkg/signatory/watermark_migration.go +++ b/pkg/signatory/watermark/watermark_migration.go @@ -1,4 +1,4 @@ -package signatory +package watermark import ( "encoding/json" diff --git a/pkg/signatory/watermark_test.go b/pkg/signatory/watermark/watermark_test.go similarity index 98% rename from pkg/signatory/watermark_test.go rename to pkg/signatory/watermark/watermark_test.go index e83a6475..111262de 100644 --- a/pkg/signatory/watermark_test.go +++ b/pkg/signatory/watermark/watermark_test.go @@ -1,6 +1,6 @@ //go:build !integration -package signatory +package watermark import ( "fmt" @@ -100,7 +100,7 @@ func TestWatermark(t *testing.T) { } t.Run("memory", func(t *testing.T) { - var wm InMemoryWatermark + var wm InMemory for i, c := range cases { t.Run(fmt.Sprintf("%d", i), func(t *testing.T) { err := wm.IsSafeToSign(c.pkh, c.req, &c.reqDigest) From af857a23797bdcb0a4f205db3d98527f53f429ed Mon Sep 17 00:00:00 2001 From: Eugene Zagidullin Date: Wed, 7 Aug 2024 23:13:51 +0300 Subject: [PATCH 4/6] oops --- cmd/approve-list-svc/server/server_test.go | 3 ++- cmd/commands/root.go | 3 ++- test/auth_test.go | 3 ++- 3 files changed, 6 insertions(+), 3 deletions(-) diff --git a/cmd/approve-list-svc/server/server_test.go b/cmd/approve-list-svc/server/server_test.go index 5c0b8726..46938b65 100644 --- a/cmd/approve-list-svc/server/server_test.go +++ b/cmd/approve-list-svc/server/server_test.go @@ -15,6 +15,7 @@ import ( "github.com/ecadlabs/signatory/pkg/config" "github.com/ecadlabs/signatory/pkg/hashmap" "github.com/ecadlabs/signatory/pkg/signatory" + "github.com/ecadlabs/signatory/pkg/signatory/watermark" "github.com/ecadlabs/signatory/pkg/vault" "github.com/ecadlabs/signatory/pkg/vault/memory" "github.com/stretchr/testify/require" @@ -57,7 +58,7 @@ func testServer(t *testing.T, addr []net.IP) error { conf := signatory.Config{ Vaults: map[string]*config.VaultConfig{"mock": {Driver: "mock"}}, - Watermark: signatory.IgnoreWatermark{}, + Watermark: watermark.Ignore{}, VaultFactory: vault.FactoryFunc(func(ctx context.Context, name string, conf *yaml.Node) (vault.Vault, error) { return memory.New([]*memory.PrivateKey{ { diff --git a/cmd/commands/root.go b/cmd/commands/root.go index fca72b00..4f3c4995 100644 --- a/cmd/commands/root.go +++ b/cmd/commands/root.go @@ -9,6 +9,7 @@ import ( "github.com/ecadlabs/signatory/pkg/config" "github.com/ecadlabs/signatory/pkg/metrics" "github.com/ecadlabs/signatory/pkg/signatory" + "github.com/ecadlabs/signatory/pkg/signatory/watermark" log "github.com/sirupsen/logrus" "github.com/spf13/cobra" ) @@ -78,7 +79,7 @@ func NewRootCommand(c *Context, name string) *cobra.Command { return err } - watermark, err := signatory.NewFileWatermark(baseDir) + watermark, err := watermark.NewFileWatermark(baseDir) if err != nil { return err } diff --git a/test/auth_test.go b/test/auth_test.go index 7295ee45..3a00d961 100644 --- a/test/auth_test.go +++ b/test/auth_test.go @@ -17,6 +17,7 @@ import ( "github.com/ecadlabs/signatory/pkg/hashmap" "github.com/ecadlabs/signatory/pkg/server" "github.com/ecadlabs/signatory/pkg/signatory" + "github.com/ecadlabs/signatory/pkg/signatory/watermark" "github.com/ecadlabs/signatory/pkg/vault" "github.com/ecadlabs/signatory/pkg/vault/memory" "github.com/stretchr/testify/require" @@ -73,7 +74,7 @@ func TestAuthenticatedRequest(t *testing.T) { conf := signatory.Config{ Vaults: map[string]*config.VaultConfig{"mock": {Driver: "mock"}}, - Watermark: signatory.IgnoreWatermark{}, + Watermark: watermark.Ignore{}, VaultFactory: vault.FactoryFunc(func(ctx context.Context, name string, conf *yaml.Node) (vault.Vault, error) { return memory.New([]*memory.PrivateKey{{PrivateKey: signPriv}}, "Mock") }), From 6914188094c3c70db387c2fe1f676984f8507759 Mon Sep 17 00:00:00 2001 From: Eugene Zagidullin Date: Wed, 14 Aug 2024 14:57:18 +0300 Subject: [PATCH 5/6] AWS watermark backend --- go.mod | 5 + go.sum | 12 ++ pkg/signatory/signatory.go | 2 +- pkg/signatory/watermark/aws.go | 190 ++++++++++++++++++ .../watermark/{watermark_file.go => file.go} | 3 +- .../watermark/{watermark_mem.go => mem.go} | 3 +- .../{watermark_migration.go => migration.go} | 0 pkg/signatory/watermark/watermark.go | 33 ++- pkg/signatory/watermark/watermark_test.go | 5 +- pkg/vault/aws/awskms.go | 15 +- 10 files changed, 256 insertions(+), 12 deletions(-) create mode 100644 pkg/signatory/watermark/aws.go rename pkg/signatory/watermark/{watermark_file.go => file.go} (96%) rename pkg/signatory/watermark/{watermark_mem.go => mem.go} (89%) rename pkg/signatory/watermark/{watermark_migration.go => migration.go} (100%) diff --git a/go.mod b/go.mod index 67bdb659..e64dcb10 100644 --- a/go.mod +++ b/go.mod @@ -36,11 +36,15 @@ require ( cloud.google.com/go/iam v1.1.5 // indirect github.com/aws/aws-sdk-go-v2 v1.30.3 // indirect github.com/aws/aws-sdk-go-v2/credentials v1.17.27 // indirect + github.com/aws/aws-sdk-go-v2/feature/dynamodb/attributevalue v1.14.10 // indirect github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.11 // indirect github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.15 // indirect github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.15 // indirect github.com/aws/aws-sdk-go-v2/internal/ini v1.8.0 // indirect + github.com/aws/aws-sdk-go-v2/service/dynamodb v1.34.4 // indirect + github.com/aws/aws-sdk-go-v2/service/dynamodbstreams v1.22.3 // indirect github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.11.3 // indirect + github.com/aws/aws-sdk-go-v2/service/internal/endpoint-discovery v1.9.16 // indirect github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.11.17 // indirect github.com/aws/aws-sdk-go-v2/service/sso v1.22.4 // indirect github.com/aws/aws-sdk-go-v2/service/ssooidc v1.26.4 // indirect @@ -61,6 +65,7 @@ require ( github.com/hashicorp/go-secure-stdlib/strutil v0.1.2 // indirect github.com/hashicorp/go-sockaddr v1.0.6 // indirect github.com/hashicorp/hcl v1.0.0 // indirect + github.com/jmespath/go-jmespath v0.4.0 // indirect github.com/kr/text v0.2.0 // indirect github.com/matttproud/golang_protobuf_extensions/v2 v2.0.0 // indirect github.com/mitchellh/go-homedir v1.1.0 // indirect diff --git a/go.sum b/go.sum index 28ad594d..b70bdf06 100644 --- a/go.sum +++ b/go.sum @@ -17,6 +17,8 @@ github.com/aws/aws-sdk-go-v2/config v1.27.27 h1:HdqgGt1OAP0HkEDDShEl0oSYa9ZZBSOm github.com/aws/aws-sdk-go-v2/config v1.27.27/go.mod h1:MVYamCg76dFNINkZFu4n4RjDixhVr51HLj4ErWzrVwg= github.com/aws/aws-sdk-go-v2/credentials v1.17.27 h1:2raNba6gr2IfA0eqqiP2XiQ0UVOpGPgDSi0I9iAP+UI= github.com/aws/aws-sdk-go-v2/credentials v1.17.27/go.mod h1:gniiwbGahQByxan6YjQUMcW4Aov6bLC3m+evgcoN4r4= +github.com/aws/aws-sdk-go-v2/feature/dynamodb/attributevalue v1.14.10 h1:orAIBscNu5aIjDOnKIrjO+IUFPMLKj3Lp0bPf4chiPc= +github.com/aws/aws-sdk-go-v2/feature/dynamodb/attributevalue v1.14.10/go.mod h1:GNjJ8daGhv10hmQYCnmkV8HuY6xXOXV4vzBssSjEIlU= github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.11 h1:KreluoV8FZDEtI6Co2xuNk/UqI9iwMrOx/87PBNIKqw= github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.11/go.mod h1:SeSUYBLsMYFoRvHE0Tjvn7kbxaUhl75CJi1sbfhMxkU= github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.15 h1:SoNJ4RlFEQEbtDcCEt+QG56MY4fm4W8rYirAmq+/DdU= @@ -25,8 +27,14 @@ github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.15 h1:C6WHdGnTDIYETAm5iE github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.15/go.mod h1:ZQLZqhcu+JhSrA9/NXRm8SkDvsycE+JkV3WGY41e+IM= github.com/aws/aws-sdk-go-v2/internal/ini v1.8.0 h1:hT8rVHwugYE2lEfdFE0QWVo81lF7jMrYJVDWI+f+VxU= github.com/aws/aws-sdk-go-v2/internal/ini v1.8.0/go.mod h1:8tu/lYfQfFe6IGnaOdrpVgEL2IrrDOf6/m9RQum4NkY= +github.com/aws/aws-sdk-go-v2/service/dynamodb v1.34.4 h1:utG3S4T+X7nONPIpRoi1tVcQdAdJxntiVS2yolPJyXc= +github.com/aws/aws-sdk-go-v2/service/dynamodb v1.34.4/go.mod h1:q9vzW3Xr1KEXa8n4waHiFt1PrppNDlMymlYP+xpsFbY= +github.com/aws/aws-sdk-go-v2/service/dynamodbstreams v1.22.3 h1:r27/FnxLPixKBRIlslsvhqscBuMK8uysCYG9Kfgm098= +github.com/aws/aws-sdk-go-v2/service/dynamodbstreams v1.22.3/go.mod h1:jqOFyN+QSWSoQC+ppyc4weiO8iNQXbzRbxDjQ1ayYd4= github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.11.3 h1:dT3MqvGhSoaIhRseqw2I0yH81l7wiR2vjs57O51EAm8= github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.11.3/go.mod h1:GlAeCkHwugxdHaueRr4nhPuY+WW+gR8UjlcqzPr1SPI= +github.com/aws/aws-sdk-go-v2/service/internal/endpoint-discovery v1.9.16 h1:lhAX5f7KpgwyieXjbDnRTjPEUI0l3emSRyxXj1PXP8w= +github.com/aws/aws-sdk-go-v2/service/internal/endpoint-discovery v1.9.16/go.mod h1:AblAlCwvi7Q/SFowvckgN+8M3uFPlopSYeLlbNDArhA= github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.11.17 h1:HGErhhrxZlQ044RiM+WdoZxp0p+EGM62y3L6pwA4olE= github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.11.17/go.mod h1:RkZEx4l0EHYDJpWppMJ3nD9wZJAa8/0lq9aVC+r2UII= github.com/aws/aws-sdk-go-v2/service/kms v1.35.3 h1:UPTdlTOwWUX49fVi7cymEN6hDqCwe3LNv1vi7TXUutk= @@ -167,6 +175,9 @@ github.com/hashicorp/vault/api/auth/approle v0.5.0 h1:a1TK6VGwYqSAfkmX4y4dJ4WBxM github.com/hashicorp/vault/api/auth/approle v0.5.0/go.mod h1:CHOQIA1AZACfjTzHggmyfiOZ+xCSKNRFqe48FTCzH0k= github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8= github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= +github.com/jmespath/go-jmespath v0.4.0 h1:BEgLn5cpjn8UN1mAw4NjwDrS35OdebyEtFe+9YPoQUg= +github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo= +github.com/jmespath/go-jmespath/internal/testify v1.5.1/go.mod h1:L3OGu8Wl2/fWfCI6z80xFu9LTZmf1ZRjMHUOPmWr69U= github.com/karalabe/hid v1.0.0 h1:+/CIMNXhSU/zIJgnIvBD2nKHxS/bnRHhhs9xBryLpPo= github.com/karalabe/hid v1.0.0/go.mod h1:Vr51f8rUOLYrfrWDFlV12GGQgM5AT8sVh+2fY4MPeu8= github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= @@ -352,6 +363,7 @@ google.golang.org/protobuf v1.31.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqw gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= +gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/pkg/signatory/signatory.go b/pkg/signatory/signatory.go index 0fead5b8..5925a3f2 100644 --- a/pkg/signatory/signatory.go +++ b/pkg/signatory/signatory.go @@ -394,7 +394,7 @@ func (s *Signatory) Sign(ctx context.Context, req *SignRequest) (crypt.Signature l.WithField(logRaw, hex.EncodeToString(req.Message)).Log(level, "About to sign raw bytes") digest := crypt.DigestFunc(req.Message) signFunc := func(ctx context.Context, message []byte, key vault.StoredKey) (crypt.Signature, error) { - if err = s.config.Watermark.IsSafeToSign(req.PublicKeyHash, msg, &digest); err != nil { + if err = s.config.Watermark.IsSafeToSign(ctx, req.PublicKeyHash, msg, &digest); err != nil { err = errors.Wrap(err, http.StatusConflict) l.Error(err) return nil, err diff --git a/pkg/signatory/watermark/aws.go b/pkg/signatory/watermark/aws.go new file mode 100644 index 00000000..6e73cab7 --- /dev/null +++ b/pkg/signatory/watermark/aws.go @@ -0,0 +1,190 @@ +package watermark + +import ( + "context" + "errors" + "fmt" + "strings" + "time" + + "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/feature/dynamodb/attributevalue" + "github.com/aws/aws-sdk-go-v2/service/dynamodb" + "github.com/aws/aws-sdk-go-v2/service/dynamodb/types" + "github.com/aws/smithy-go" + tz "github.com/ecadlabs/gotez/v2" + "github.com/ecadlabs/gotez/v2/crypt" + "github.com/ecadlabs/gotez/v2/protocol" + "github.com/ecadlabs/signatory/pkg/signatory/request" + awskms "github.com/ecadlabs/signatory/pkg/vault/aws" + log "github.com/sirupsen/logrus" +) + +const ( + readCapacityUnits = 5 + writeCapacityUnits = 5 + defaultTable = "watermark" +) + +type Config struct { + awskms.Config + Table string `yaml:"table"` +} + +func (c *Config) table() string { + if c.Table != "" { + return c.Table + } + return defaultTable +} + +type AWS struct { + cfg Config + client *dynamodb.Client +} + +func NewAWSWatermark(ctx context.Context, config *Config) (*AWS, error) { + cfg, err := awskms.NewConfig(ctx, &config.Config) + if err != nil { + return nil, err + } + + client := dynamodb.NewFromConfig(cfg) + a := AWS{ + client: client, + cfg: *config, + } + if err := a.maybeCreateTable(ctx); err != nil { + return nil, fmt.Errorf("(AWSWatermark) NewAWSWatermark: %w", err) + } + return &a, nil +} + +func (a *AWS) maybeCreateTable(ctx context.Context) error { + _, err := a.client.CreateTable(ctx, &dynamodb.CreateTableInput{ + AttributeDefinitions: []types.AttributeDefinition{ + { + AttributeName: aws.String("idx"), + AttributeType: types.ScalarAttributeTypeS, + }, + { + AttributeName: aws.String("request"), + AttributeType: types.ScalarAttributeTypeS, + }, + }, + KeySchema: []types.KeySchemaElement{ + { + AttributeName: aws.String("idx"), + KeyType: types.KeyTypeHash, + }, + { + AttributeName: aws.String("request"), + KeyType: types.KeyTypeRange, + }, + }, + ProvisionedThroughput: &types.ProvisionedThroughput{ + ReadCapacityUnits: aws.Int64(readCapacityUnits), + WriteCapacityUnits: aws.Int64(writeCapacityUnits), + }, + TableName: aws.String(a.cfg.table()), + }) + if err != nil { + var serr smithy.APIError + if errors.As(err, &serr) && serr.ErrorCode() == "ResourceInUseException" { + return nil + } + return err + } + log.WithField("table", a.cfg.table()).Info("table created") + waiter := dynamodb.NewTableExistsWaiter(a.client) + return waiter.Wait(context.TODO(), &dynamodb.DescribeTableInput{ + TableName: aws.String(a.cfg.table()), + }, time.Minute*5) // give excess time +} + +type watermark struct { + Idx string `dynamodbav:"idx"` + Request string `dynamodbav:"request"` + Level int32 `dynamodbav:"lvl"` + Round int32 `dynamodbav:"round"` + Digest *tz.BlockPayloadHash `dynamodbav:"digest"` +} + +func (w *watermark) key() map[string]types.AttributeValue { + return map[string]types.AttributeValue{ + "idx": &types.AttributeValueMemberS{Value: w.Idx}, + "request": &types.AttributeValueMemberS{Value: w.Request}, + } +} + +func (w *watermark) watermark() *request.Watermark { + return &request.Watermark{ + Level: w.Level, + Round: w.Round, + Hash: tz.Some(*w.Digest), + } +} + +func (a *AWS) IsSafeToSign(ctx context.Context, pkh crypt.PublicKeyHash, req protocol.SignRequest, digest *crypt.Digest) error { + m, ok := req.(request.WithWatermark) + if !ok { + // watermark is not required + return nil + } + wm := request.NewWatermark(m, digest) + prev := watermark{ + Idx: strings.Join([]string{m.GetChainID().String(), pkh.String()}, "/"), + Request: req.SignRequestKind(), + } + for { + response, err := a.client.GetItem(ctx, &dynamodb.GetItemInput{ + Key: prev.key(), + TableName: aws.String(a.cfg.table()), + }) + if err != nil { + return fmt.Errorf("(AWSWatermark) IsSafeToSign: %w", err) + } + + update := watermark{ + Idx: prev.Idx, + Request: prev.Request, + Level: wm.Level, + Round: wm.Round, + Digest: wm.Hash.UnwrapPtr(), + } + item, err := attributevalue.MarshalMap(&update) + if err != nil { + return fmt.Errorf("(AWSWatermark) IsSafeToSign: %w", err) + } + input := dynamodb.PutItemInput{ + TableName: aws.String(a.cfg.table()), + Item: item, + } + + if response.Item != nil { + if err := attributevalue.UnmarshalMap(response.Item, &prev); err != nil { + return fmt.Errorf("(AWSWatermark) IsSafeToSign: %w", err) + } + if !wm.Validate(prev.watermark()) { + return ErrWatermark + } + input.ConditionExpression = aws.String("lvl = :lvl AND round = :round AND digest = :digest") + input.ExpressionAttributeValues = map[string]types.AttributeValue{ + ":lvl": response.Item["lvl"], + ":round": response.Item["round"], + ":digest": response.Item["digest"], + } + } else { + input.ConditionExpression = aws.String("attribute_not_exists(idx)") + } + + _, err = a.client.PutItem((ctx), &input) + var serr smithy.APIError + if err == nil { + return nil + } else if !errors.As(err, &serr) || serr.ErrorCode() != "ConditionalCheckFailedException" { + return fmt.Errorf("(AWSWatermark) IsSafeToSign: %w", err) + } + // retry + } +} diff --git a/pkg/signatory/watermark/watermark_file.go b/pkg/signatory/watermark/file.go similarity index 96% rename from pkg/signatory/watermark/watermark_file.go rename to pkg/signatory/watermark/file.go index b6ce7556..e53716c0 100644 --- a/pkg/signatory/watermark/watermark_file.go +++ b/pkg/signatory/watermark/file.go @@ -2,6 +2,7 @@ package watermark import ( "bufio" + "context" "encoding/json" "errors" "fmt" @@ -147,7 +148,7 @@ func writeWatermarkData(baseDir string, data delegateMap, chain *tz.ChainID) err return w.Flush() } -func (f *File) IsSafeToSign(pkh crypt.PublicKeyHash, req protocol.SignRequest, digest *crypt.Digest) error { +func (f *File) IsSafeToSign(ctx context.Context, pkh crypt.PublicKeyHash, req protocol.SignRequest, digest *crypt.Digest) error { m, ok := req.(request.WithWatermark) if !ok { // watermark is not required diff --git a/pkg/signatory/watermark/watermark_mem.go b/pkg/signatory/watermark/mem.go similarity index 89% rename from pkg/signatory/watermark/watermark_mem.go rename to pkg/signatory/watermark/mem.go index c8385288..5da909c4 100644 --- a/pkg/signatory/watermark/watermark_mem.go +++ b/pkg/signatory/watermark/mem.go @@ -1,6 +1,7 @@ package watermark import ( + "context" "sync" tz "github.com/ecadlabs/gotez/v2" @@ -16,7 +17,7 @@ type InMemory struct { } // IsSafeToSign return true if this msgID is safe to sign -func (w *InMemory) IsSafeToSign(pkh crypt.PublicKeyHash, req protocol.SignRequest, digest *crypt.Digest) error { +func (w *InMemory) IsSafeToSign(ctx context.Context, pkh crypt.PublicKeyHash, req protocol.SignRequest, digest *crypt.Digest) error { w.mtx.Lock() defer w.mtx.Unlock() return w.isSafeToSignUnlocked(pkh, req, digest) diff --git a/pkg/signatory/watermark/watermark_migration.go b/pkg/signatory/watermark/migration.go similarity index 100% rename from pkg/signatory/watermark/watermark_migration.go rename to pkg/signatory/watermark/migration.go diff --git a/pkg/signatory/watermark/watermark.go b/pkg/signatory/watermark/watermark.go index ff202c96..2d3b4e14 100644 --- a/pkg/signatory/watermark/watermark.go +++ b/pkg/signatory/watermark/watermark.go @@ -1,21 +1,50 @@ package watermark import ( + "context" + "fmt" + "github.com/ecadlabs/gotez/v2/crypt" "github.com/ecadlabs/gotez/v2/protocol" + "gopkg.in/yaml.v3" ) // Watermark tests level against stored high watermark type Watermark interface { - IsSafeToSign(pkh crypt.PublicKeyHash, req protocol.SignRequest, digest *crypt.Digest) error + IsSafeToSign(ctx context.Context, pkh crypt.PublicKeyHash, req protocol.SignRequest, digest *crypt.Digest) error } // Ignore watermark that do not validation and return true type Ignore struct{} // IsSafeToSign always return true -func (w Ignore) IsSafeToSign(crypt.PublicKeyHash, protocol.SignRequest, *crypt.Digest) error { +func (w Ignore) IsSafeToSign(context.Context, crypt.PublicKeyHash, protocol.SignRequest, *crypt.Digest) error { return nil } var _ Watermark = (*Ignore)(nil) + +type Factory interface { + New(ctx context.Context, name string, conf *yaml.Node) (Watermark, error) +} + +type newWMBackendFunc func(ctx context.Context, conf *yaml.Node) (Watermark, error) + +type registry map[string]newWMBackendFunc + +func (r registry) New(ctx context.Context, name string, conf *yaml.Node) (Watermark, error) { + if newFunc, ok := r[name]; ok { + return newFunc(ctx, conf) + } + return nil, fmt.Errorf("unknown watermark backend: %s", name) +} + +var wmRegistry = make(registry) + +func RegisterWatermark(name string, newFunc newWMBackendFunc) { + wmRegistry[name] = newFunc +} + +func Registry() Factory { + return wmRegistry +} diff --git a/pkg/signatory/watermark/watermark_test.go b/pkg/signatory/watermark/watermark_test.go index 111262de..a989897d 100644 --- a/pkg/signatory/watermark/watermark_test.go +++ b/pkg/signatory/watermark/watermark_test.go @@ -3,6 +3,7 @@ package watermark import ( + "context" "fmt" "os" "testing" @@ -103,7 +104,7 @@ func TestWatermark(t *testing.T) { var wm InMemory for i, c := range cases { t.Run(fmt.Sprintf("%d", i), func(t *testing.T) { - err := wm.IsSafeToSign(c.pkh, c.req, &c.reqDigest) + err := wm.IsSafeToSign(context.Background(), c.pkh, c.req, &c.reqDigest) if c.expectErr { assert.Error(t, err) } else { @@ -120,7 +121,7 @@ func TestWatermark(t *testing.T) { require.NoError(t, err) for i, c := range cases { t.Run(fmt.Sprintf("%d", i), func(t *testing.T) { - err := wm.IsSafeToSign(c.pkh, c.req, &c.reqDigest) + err := wm.IsSafeToSign(context.Background(), c.pkh, c.req, &c.reqDigest) if c.expectErr { assert.Error(t, err) } else { diff --git a/pkg/vault/aws/awskms.go b/pkg/vault/aws/awskms.go index 1a8505c5..e5e099f4 100644 --- a/pkg/vault/aws/awskms.go +++ b/pkg/vault/aws/awskms.go @@ -6,6 +6,7 @@ import ( "fmt" "os" + "github.com/aws/aws-sdk-go-v2/aws" awsconfig "github.com/aws/aws-sdk-go-v2/config" "github.com/aws/aws-sdk-go-v2/service/kms" "github.com/aws/aws-sdk-go-v2/service/kms/types" @@ -20,7 +21,6 @@ import ( // Config contains AWS KMS backend configuration type Config struct { - UserName string `yaml:"user_name" validate:"required"` AccessKeyID string `yaml:"access_key_id"` AccessKey string `yaml:"secret_access_key"` Region string `yaml:"region" validate:"required"` @@ -155,15 +155,20 @@ func (v *Vault) SignMessage(ctx context.Context, message []byte, key vault.Store return sig, nil } -// New creates new AWS KMS backend -func New(ctx context.Context, config *Config) (*Vault, error) { +func NewConfig(ctx context.Context, config *Config) (aws.Config, error) { if config.AccessKeyID != "" { os.Setenv("AWS_ACCESS_KEY_ID", config.AccessKeyID) os.Setenv("AWS_SECRET_ACCESS_KEY", config.AccessKey) } - os.Setenv("AWS_REGION", config.Region) + if config.Region != "" { + os.Setenv("AWS_REGION", config.Region) + } + return awsconfig.LoadDefaultConfig(ctx) +} - cfg, err := awsconfig.LoadDefaultConfig(ctx) +// New creates new AWS KMS backend +func New(ctx context.Context, config *Config) (*Vault, error) { + cfg, err := NewConfig(ctx, config) if err != nil { return nil, err } From 2e42e61f71e8b00fee85fb888da5d80a1f54618e Mon Sep 17 00:00:00 2001 From: Eugene Zagidullin Date: Wed, 14 Aug 2024 15:42:14 +0300 Subject: [PATCH 6/6] configurable watermark backend --- cmd/commands/root.go | 10 +++++----- docs/aws_kms.md | 5 +---- docs/start.md | 21 +++++++++++++++++++-- go.mod | 6 +++--- go.sum | 3 +++ pkg/config/config.go | 10 ++++++++++ pkg/signatory/watermark/aws.go | 22 ++++++++++++++++++---- pkg/signatory/watermark/file.go | 9 ++++++++- pkg/signatory/watermark/mem.go | 8 +++++++- pkg/signatory/watermark/watermark.go | 11 +++++++---- pkg/vault/aws/awskms.go | 17 +++++------------ signatory.yaml | 5 ++++- 12 files changed, 90 insertions(+), 37 deletions(-) diff --git a/cmd/commands/root.go b/cmd/commands/root.go index 4f3c4995..f667c1f5 100644 --- a/cmd/commands/root.go +++ b/cmd/commands/root.go @@ -50,11 +50,11 @@ func NewRootCommand(c *Context, name string) *cobra.Command { } } - if baseDir == "" { - baseDir = conf.BaseDir + if baseDir != "" { + conf.BaseDir = baseDir } - baseDir = os.ExpandEnv(baseDir) - if err := os.MkdirAll(baseDir, 0770); err != nil { + conf.BaseDir = os.ExpandEnv(conf.BaseDir) + if err := os.MkdirAll(conf.BaseDir, 0770); err != nil { return err } @@ -79,7 +79,7 @@ func NewRootCommand(c *Context, name string) *cobra.Command { return err } - watermark, err := watermark.NewFileWatermark(baseDir) + watermark, err := watermark.Registry().New(cmd.Context(), conf.Watermark.Driver, &conf.Watermark.Config, conf) if err != nil { return err } diff --git a/docs/aws_kms.md b/docs/aws_kms.md index fdf934a8..ddb1dedb 100644 --- a/docs/aws_kms.md +++ b/docs/aws_kms.md @@ -19,7 +19,6 @@ vaults: aws: driver: awskms config: - user_name: access_key_id: secret_access_key: region: @@ -29,7 +28,6 @@ vaults: Name | Type | Required | Description -----|------|:--------:|------------ -user_name | string |✅| IAM user name access_key_id | string | OPTIONAL | IAM user detail secret_access_key | string | OPTIONAL | IAM user detail region | string | ✅ | Region where key is created @@ -54,7 +52,7 @@ To generate a new private key withing AWS, you must: ## Example Configuration for the AWS KMS vault in Signatory -This example shows a Signatory vault configuration for AWS KMS. Text in `{}` must be replaced, for example, `{AWS_User_Name}` should be replaced with your AWS username. +This example shows a Signatory vault configuration for AWS KMS. Text in `{}` must be replaced. ``` @@ -63,7 +61,6 @@ vaults: awskms: driver: awskms config: - user_name: {AWS_User_Name} access_key_id: {Access_Key_ID_In_AWS_User_Profile} secret_access_key: {Secret_access_Key_ID_In_AWS_User_Profile} region: {AWS_Region} diff --git a/docs/start.md b/docs/start.md index 4f55bc19..b4abf938 100644 --- a/docs/start.md +++ b/docs/start.md @@ -74,6 +74,10 @@ vaults: config: file: /etc/signatory/secret.json +watermark: + # Default + driver: file + # List enabled public keys hashes here tezos: # Default policy allows "block" and "endorsement" operations @@ -111,7 +115,7 @@ tezos: ] ``` -## Configuration Example - AWS KMS Vault +### Configuration Example - AWS KMS Vault This configuration example uses AWS KMS as ```yaml @@ -128,7 +132,6 @@ vaults: aws: driver: awskms config: - user_name: signatory_testnets # IAM User or Role access_key_id: # Optional secret_access_key: # Optional region: us-west-2 @@ -145,6 +148,20 @@ tezos: - transaction ``` +### Watermark backend + +Basic syntax: + +```yaml +# Optional +watermark: + driver: + # Optional + config: +``` + +Currently three backends are supported: `file` (a default one), `mem` (for testing purpose only) and `aws`. See [AWS KMS][aws] for configuration syntax. + ## Backends * [AWS KMS](aws_kms.md) * [Azure Key Vault](azure_kms.md) diff --git a/go.mod b/go.mod index e64dcb10..637db568 100644 --- a/go.mod +++ b/go.mod @@ -4,7 +4,10 @@ go 1.21 require ( cloud.google.com/go/kms v1.15.5 + github.com/aws/aws-sdk-go-v2 v1.30.3 github.com/aws/aws-sdk-go-v2/config v1.27.27 + github.com/aws/aws-sdk-go-v2/feature/dynamodb/attributevalue v1.14.10 + github.com/aws/aws-sdk-go-v2/service/dynamodb v1.34.4 github.com/aws/aws-sdk-go-v2/service/kms v1.35.3 github.com/aws/smithy-go v1.20.3 github.com/certusone/yubihsm-go v0.3.0 @@ -34,14 +37,11 @@ require ( cloud.google.com/go/compute v1.23.3 // indirect cloud.google.com/go/compute/metadata v0.2.3 // indirect cloud.google.com/go/iam v1.1.5 // indirect - github.com/aws/aws-sdk-go-v2 v1.30.3 // indirect github.com/aws/aws-sdk-go-v2/credentials v1.17.27 // indirect - github.com/aws/aws-sdk-go-v2/feature/dynamodb/attributevalue v1.14.10 // indirect github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.11 // indirect github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.15 // indirect github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.15 // indirect github.com/aws/aws-sdk-go-v2/internal/ini v1.8.0 // indirect - github.com/aws/aws-sdk-go-v2/service/dynamodb v1.34.4 // indirect github.com/aws/aws-sdk-go-v2/service/dynamodbstreams v1.22.3 // indirect github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.11.3 // indirect github.com/aws/aws-sdk-go-v2/service/internal/endpoint-discovery v1.9.16 // indirect diff --git a/go.sum b/go.sum index b70bdf06..23a76957 100644 --- a/go.sum +++ b/go.sum @@ -177,6 +177,7 @@ github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2 github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= github.com/jmespath/go-jmespath v0.4.0 h1:BEgLn5cpjn8UN1mAw4NjwDrS35OdebyEtFe+9YPoQUg= github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo= +github.com/jmespath/go-jmespath/internal/testify v1.5.1 h1:shLQSRRSCCPj3f2gpwzGwWFoC7ycTf1rcQZHOlsJ6N8= github.com/jmespath/go-jmespath/internal/testify v1.5.1/go.mod h1:L3OGu8Wl2/fWfCI6z80xFu9LTZmf1ZRjMHUOPmWr69U= github.com/karalabe/hid v1.0.0 h1:+/CIMNXhSU/zIJgnIvBD2nKHxS/bnRHhhs9xBryLpPo= github.com/karalabe/hid v1.0.0/go.mod h1:Vr51f8rUOLYrfrWDFlV12GGQgM5AT8sVh+2fY4MPeu8= @@ -364,6 +365,8 @@ gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8 gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= +gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/pkg/config/config.go b/pkg/config/config.go index 4ab1ed2b..a0d38006 100644 --- a/pkg/config/config.go +++ b/pkg/config/config.go @@ -51,6 +51,13 @@ type Config struct { Server ServerConfig `yaml:"server"` PolicyHook *PolicyHook `yaml:"policy_hook"` BaseDir string `yaml:"base_dir" validate:"required"` + Watermark *WatermarkConfig `yaml:"watermark"` +} + +// WatermarkConfig represents watermark backend configuration +type WatermarkConfig struct { + Driver string `yaml:"driver" validate:"required"` + Config yaml.Node `yaml:"config"` } var defaultConfig = Config{ @@ -59,6 +66,9 @@ var defaultConfig = Config{ UtilityAddress: ":9583", }, BaseDir: "/var/lib/signatory", + Watermark: &WatermarkConfig{ + Driver: "file", + }, } // Read read the config from a file diff --git a/pkg/signatory/watermark/aws.go b/pkg/signatory/watermark/aws.go index 6e73cab7..4cdd925f 100644 --- a/pkg/signatory/watermark/aws.go +++ b/pkg/signatory/watermark/aws.go @@ -15,9 +15,11 @@ import ( tz "github.com/ecadlabs/gotez/v2" "github.com/ecadlabs/gotez/v2/crypt" "github.com/ecadlabs/gotez/v2/protocol" + "github.com/ecadlabs/signatory/pkg/config" "github.com/ecadlabs/signatory/pkg/signatory/request" awskms "github.com/ecadlabs/signatory/pkg/vault/aws" log "github.com/sirupsen/logrus" + "gopkg.in/yaml.v3" ) const ( @@ -26,12 +28,12 @@ const ( defaultTable = "watermark" ) -type Config struct { +type AWSConfig struct { awskms.Config Table string `yaml:"table"` } -func (c *Config) table() string { +func (c *AWSConfig) table() string { if c.Table != "" { return c.Table } @@ -39,11 +41,11 @@ func (c *Config) table() string { } type AWS struct { - cfg Config + cfg AWSConfig client *dynamodb.Client } -func NewAWSWatermark(ctx context.Context, config *Config) (*AWS, error) { +func NewAWSWatermark(ctx context.Context, config *AWSConfig) (*AWS, error) { cfg, err := awskms.NewConfig(ctx, &config.Config) if err != nil { return nil, err @@ -188,3 +190,15 @@ func (a *AWS) IsSafeToSign(ctx context.Context, pkh crypt.PublicKeyHash, req pro // retry } } + +func init() { + RegisterWatermark("aws", func(ctx context.Context, node *yaml.Node, global *config.Config) (Watermark, error) { + var conf AWSConfig + if node != nil { + if err := node.Decode(&conf); err != nil { + return nil, err + } + } + return NewAWSWatermark(ctx, &conf) + }) +} diff --git a/pkg/signatory/watermark/file.go b/pkg/signatory/watermark/file.go index e53716c0..b3715ebf 100644 --- a/pkg/signatory/watermark/file.go +++ b/pkg/signatory/watermark/file.go @@ -15,9 +15,11 @@ import ( "github.com/ecadlabs/gotez/v2/b58" "github.com/ecadlabs/gotez/v2/crypt" "github.com/ecadlabs/gotez/v2/protocol" + "github.com/ecadlabs/signatory/pkg/config" "github.com/ecadlabs/signatory/pkg/hashmap" "github.com/ecadlabs/signatory/pkg/signatory/request" log "github.com/sirupsen/logrus" + "gopkg.in/yaml.v3" ) type File struct { @@ -71,6 +73,7 @@ func tryLoad(baseDir string) (map[tz.ChainID]delegateMap, error) { } func NewFileWatermark(baseDir string) (*File, error) { + wm := File{ baseDir: baseDir, } @@ -164,4 +167,8 @@ func (f *File) IsSafeToSign(ctx context.Context, pkh crypt.PublicKeyHash, req pr return writeWatermarkData(f.baseDir, f.mem.chains[*chain], chain) } -var _ Watermark = (*File)(nil) +func init() { + RegisterWatermark("file", func(ctx context.Context, node *yaml.Node, global *config.Config) (Watermark, error) { + return NewFileWatermark(global.BaseDir) + }) +} diff --git a/pkg/signatory/watermark/mem.go b/pkg/signatory/watermark/mem.go index 5da909c4..dfd08ae4 100644 --- a/pkg/signatory/watermark/mem.go +++ b/pkg/signatory/watermark/mem.go @@ -7,7 +7,9 @@ import ( tz "github.com/ecadlabs/gotez/v2" "github.com/ecadlabs/gotez/v2/crypt" "github.com/ecadlabs/gotez/v2/protocol" + "github.com/ecadlabs/signatory/pkg/config" "github.com/ecadlabs/signatory/pkg/signatory/request" + "gopkg.in/yaml.v3" ) // InMemory keep previous operation in memory @@ -56,4 +58,8 @@ func (w *InMemory) isSafeToSignUnlocked(pkh crypt.PublicKeyHash, req protocol.Si return nil } -var _ Watermark = (*InMemory)(nil) +func init() { + RegisterWatermark("mem", func(context.Context, *yaml.Node, *config.Config) (Watermark, error) { + return new(InMemory), nil + }) +} diff --git a/pkg/signatory/watermark/watermark.go b/pkg/signatory/watermark/watermark.go index 2d3b4e14..3055c065 100644 --- a/pkg/signatory/watermark/watermark.go +++ b/pkg/signatory/watermark/watermark.go @@ -6,6 +6,8 @@ import ( "github.com/ecadlabs/gotez/v2/crypt" "github.com/ecadlabs/gotez/v2/protocol" + "github.com/ecadlabs/signatory/pkg/config" + log "github.com/sirupsen/logrus" "gopkg.in/yaml.v3" ) @@ -25,16 +27,17 @@ func (w Ignore) IsSafeToSign(context.Context, crypt.PublicKeyHash, protocol.Sign var _ Watermark = (*Ignore)(nil) type Factory interface { - New(ctx context.Context, name string, conf *yaml.Node) (Watermark, error) + New(ctx context.Context, name string, conf *yaml.Node, global *config.Config) (Watermark, error) } -type newWMBackendFunc func(ctx context.Context, conf *yaml.Node) (Watermark, error) +type newWMBackendFunc func(ctx context.Context, conf *yaml.Node, global *config.Config) (Watermark, error) type registry map[string]newWMBackendFunc -func (r registry) New(ctx context.Context, name string, conf *yaml.Node) (Watermark, error) { +func (r registry) New(ctx context.Context, name string, conf *yaml.Node, global *config.Config) (Watermark, error) { if newFunc, ok := r[name]; ok { - return newFunc(ctx, conf) + log.WithField("backend", name).Info("Initializing watermark backend") + return newFunc(ctx, conf, global) } return nil, fmt.Errorf("unknown watermark backend: %s", name) } diff --git a/pkg/vault/aws/awskms.go b/pkg/vault/aws/awskms.go index e5e099f4..7df844bd 100644 --- a/pkg/vault/aws/awskms.go +++ b/pkg/vault/aws/awskms.go @@ -12,7 +12,6 @@ import ( "github.com/aws/aws-sdk-go-v2/service/kms/types" "github.com/aws/smithy-go" "github.com/ecadlabs/gotez/v2/crypt" - "github.com/ecadlabs/signatory/pkg/config" "github.com/ecadlabs/signatory/pkg/cryptoutils" "github.com/ecadlabs/signatory/pkg/vault" @@ -23,7 +22,7 @@ import ( type Config struct { AccessKeyID string `yaml:"access_key_id"` AccessKey string `yaml:"secret_access_key"` - Region string `yaml:"region" validate:"required"` + Region string `yaml:"region"` } type Vault struct { @@ -183,17 +182,11 @@ func New(ctx context.Context, config *Config) (*Vault, error) { func init() { vault.RegisterVault("awskms", func(ctx context.Context, node *yaml.Node) (vault.Vault, error) { var conf Config - if node == nil || node.Kind == 0 { - return nil, errors.New("(AWSKMS): config is missing") - } - if err := node.Decode(&conf); err != nil { - return nil, err - } - - if err := config.Validator().Struct(&conf); err != nil { - return nil, err + if node != nil { + if err := node.Decode(&conf); err != nil { + return nil, err + } } - return New(ctx, &conf) }) } diff --git a/signatory.yaml b/signatory.yaml index 4a9e1274..02ba5b4e 100644 --- a/signatory.yaml +++ b/signatory.yaml @@ -15,7 +15,6 @@ server: secret: secret2 jwt_exp: 30 - vaults: # Name is used to identify backend during import process kms: @@ -49,6 +48,10 @@ vaults: transitConfig: mountPoint: "transit/" +watermark: + # Default + driver: file + # List enabled public keys hashes here tezos: # This example does not specifiy a policy, and be default will allow signing of "block" and "endorsement" operations only.