From 2e42e61f71e8b00fee85fb888da5d80a1f54618e Mon Sep 17 00:00:00 2001 From: Eugene Zagidullin Date: Wed, 14 Aug 2024 15:42:14 +0300 Subject: [PATCH] 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.