From d787f71a2fd9e143ab429c510fd5bf60a147a450 Mon Sep 17 00:00:00 2001 From: Bowen Xue <93296844+bxue-l2@users.noreply.github.com> Date: Fri, 22 Mar 2024 18:35:26 -0700 Subject: [PATCH] Fireblock with aws secret manager (#377) Co-authored-by: Bowen Xue --- common/aws/secretmanager/secretmanager.go | 37 ++++++++++++++++++++ common/fireblocks_config.go | 42 ++++++++++++++++------- disperser/cmd/batcher/config.go | 5 +-- disperser/cmd/batcher/main.go | 28 ++++++++++----- go.mod | 1 + go.sum | 5 +++ inabox/deploy/config.go | 1 + inabox/deploy/env_vars.go | 2 ++ 8 files changed, 96 insertions(+), 25 deletions(-) create mode 100644 common/aws/secretmanager/secretmanager.go diff --git a/common/aws/secretmanager/secretmanager.go b/common/aws/secretmanager/secretmanager.go new file mode 100644 index 0000000000..593abdadb2 --- /dev/null +++ b/common/aws/secretmanager/secretmanager.go @@ -0,0 +1,37 @@ +package secretmanager + +import ( + "context" + "log" + + "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/config" + "github.com/aws/aws-sdk-go-v2/service/secretsmanager" +) + +func ReadStringFromSecretManager(ctx context.Context, secretName, region string) (string, error) { + config, err := config.LoadDefaultConfig(ctx, config.WithRegion(region)) + if err != nil { + log.Fatal(err) + } + + // Create Secrets Manager client + svc := secretsmanager.NewFromConfig(config) + + input := &secretsmanager.GetSecretValueInput{ + SecretId: aws.String(secretName), + VersionStage: aws.String("AWSCURRENT"), // VersionStage defaults to AWSCURRENT if unspecified + } + + result, err := svc.GetSecretValue(ctx, input) + if err != nil { + // For a list of exceptions thrown, see + // https://docs.aws.amazon.com/secretsmanager/latest/apireference/API_GetSecretValue.html + return "", err + } + + // Decrypts secret using the associated KMS key. + var secretString string = *result.SecretString + + return secretString, nil +} diff --git a/common/fireblocks_config.go b/common/fireblocks_config.go index f3c7b0e7f5..9d013c74e4 100644 --- a/common/fireblocks_config.go +++ b/common/fireblocks_config.go @@ -5,34 +5,38 @@ import ( ) const ( - FireblocksAPIKeyFlagName = "fireblocks-api-key" - FireblocksAPISecretPathFlagName = "fireblocks-api-secret-path" + FireblocksAPIKeyNameFlagName = "fireblocks-api-key-name" + FireblocksAPISecretNameFlagName = "fireblocks-api-secret-name" FireblocksBaseURLFlagName = "fireblocks-api-url" FireblocksVaultAccountNameFlagName = "fireblocks-vault-account-name" FireblocksWalletAddressFlagName = "fireblocks-wallet-address" + FireblocksSecretManagerRegion = "fireblocks-secret-manager-region" + FireblocksDisable = "fireblocks-disable" ) type FireblocksConfig struct { - APIKey string - SecretKeyPath string + APIKeyName string + SecretKeyName string BaseURL string VaultAccountName string WalletAddress string + Region string + Disable bool } func FireblocksCLIFlags(envPrefix string, flagPrefix string) []cli.Flag { return []cli.Flag{ cli.StringFlag{ - Name: PrefixFlag(flagPrefix, FireblocksAPIKeyFlagName), - Usage: "Fireblocks API Key. To configure Fireblocks MPC wallet, this field is required. Otherwise, private key must be configured in eth client so that it can fall back to private key wallet.", + Name: PrefixFlag(flagPrefix, FireblocksAPIKeyNameFlagName), + Usage: "Fireblocks API Key Name. To configure Fireblocks MPC wallet, this field is required. Otherwise, private key must be configured in eth client so that it can fall back to private key wallet.", Required: false, - EnvVar: PrefixEnvVar(envPrefix, "FIREBLOCKS_API_KEY"), + EnvVar: PrefixEnvVar(envPrefix, "FIREBLOCKS_API_KEY_NAME"), }, cli.StringFlag{ - Name: PrefixFlag(flagPrefix, FireblocksAPISecretPathFlagName), - Usage: "Fireblocks API Secret Path. To configure Fireblocks MPC wallet, this field is required. Otherwise, private key must be configured in eth client so that it can fall back to private key wallet.", + Name: PrefixFlag(flagPrefix, FireblocksAPISecretNameFlagName), + Usage: "Fireblocks API Secret Name. To configure Fireblocks MPC wallet, this field is required. Otherwise, private key must be configured in eth client so that it can fall back to private key wallet.", Required: false, - EnvVar: PrefixEnvVar(envPrefix, "FIREBLOCKS_API_SECRET_PATH"), + EnvVar: PrefixEnvVar(envPrefix, "FIREBLOCKS_API_SECRET_NAME"), }, cli.StringFlag{ Name: PrefixFlag(flagPrefix, FireblocksBaseURLFlagName), @@ -52,15 +56,29 @@ func FireblocksCLIFlags(envPrefix string, flagPrefix string) []cli.Flag { Required: false, EnvVar: PrefixEnvVar(envPrefix, "FIREBLOCKS_WALLET_ADDRESS"), }, + cli.StringFlag{ + Name: PrefixFlag(flagPrefix, FireblocksSecretManagerRegion), + Usage: "Fireblocks AWS Secret Manager Region.", + Required: false, + EnvVar: PrefixEnvVar(envPrefix, "FIREBLOCKS_SECRET_MANAGER_REGION"), + }, + cli.BoolFlag{ + Name: PrefixFlag(flagPrefix, FireblocksDisable), + Usage: "Disable Fireblocks. By default, Disable is set to false.", + Required: false, + EnvVar: PrefixEnvVar(envPrefix, "FIREBLOCKS_DISABLE"), + }, } } func ReadFireblocksCLIConfig(ctx *cli.Context, flagPrefix string) FireblocksConfig { return FireblocksConfig{ - APIKey: ctx.GlobalString(PrefixFlag(flagPrefix, FireblocksAPIKeyFlagName)), - SecretKeyPath: ctx.GlobalString(PrefixFlag(flagPrefix, FireblocksAPISecretPathFlagName)), + APIKeyName: ctx.GlobalString(PrefixFlag(flagPrefix, FireblocksAPIKeyNameFlagName)), + SecretKeyName: ctx.GlobalString(PrefixFlag(flagPrefix, FireblocksAPISecretNameFlagName)), BaseURL: ctx.GlobalString(PrefixFlag(flagPrefix, FireblocksBaseURLFlagName)), VaultAccountName: ctx.GlobalString(PrefixFlag(flagPrefix, FireblocksVaultAccountNameFlagName)), WalletAddress: ctx.GlobalString(PrefixFlag(flagPrefix, FireblocksWalletAddressFlagName)), + Region: ctx.GlobalString(PrefixFlag(flagPrefix, FireblocksSecretManagerRegion)), + Disable: ctx.GlobalBool(PrefixFlag(flagPrefix, FireblocksDisable)), } } diff --git a/disperser/cmd/batcher/config.go b/disperser/cmd/batcher/config.go index ee3053558e..3b1028ffd0 100644 --- a/disperser/cmd/batcher/config.go +++ b/disperser/cmd/batcher/config.go @@ -39,10 +39,7 @@ func NewConfig(ctx *cli.Context) (Config, error) { } ethClientConfig := geth.ReadEthClientConfig(ctx) fireblocksConfig := common.ReadFireblocksCLIConfig(ctx, flags.FlagPrefix) - if len(fireblocksConfig.APIKey) > 0 && - len(fireblocksConfig.SecretKeyPath) > 0 && - len(fireblocksConfig.BaseURL) > 0 && - len(fireblocksConfig.VaultAccountName) > 0 { + if !fireblocksConfig.Disable { ethClientConfig = geth.ReadEthClientConfigRPCOnly(ctx) } config := Config{ diff --git a/disperser/cmd/batcher/main.go b/disperser/cmd/batcher/main.go index a9c18f7541..c18aca53f1 100644 --- a/disperser/cmd/batcher/main.go +++ b/disperser/cmd/batcher/main.go @@ -16,6 +16,7 @@ import ( "github.com/Layr-Labs/eigenda/common/aws/dynamodb" "github.com/Layr-Labs/eigenda/common/aws/s3" + "github.com/Layr-Labs/eigenda/common/aws/secretmanager" "github.com/Layr-Labs/eigenda/common/geth" "github.com/Layr-Labs/eigenda/core" coreeth "github.com/Layr-Labs/eigenda/core/eth" @@ -170,18 +171,27 @@ func RunBatcher(ctx *cli.Context) error { } finalizer := batcher.NewFinalizer(config.TimeoutConfig.ChainReadTimeout, config.BatcherConfig.FinalizerInterval, queue, client, rpcClient, config.BatcherConfig.MaxNumRetriesPerBlob, 1000, config.BatcherConfig.FinalizerPoolSize, logger, metrics.FinalizerMetrics) var wallet walletsdk.Wallet - if len(config.FireblocksConfig.APIKey) > 0 && - len(config.FireblocksConfig.SecretKeyPath) > 0 && - len(config.FireblocksConfig.BaseURL) > 0 && - len(config.FireblocksConfig.VaultAccountName) > 0 && - len(config.FireblocksConfig.WalletAddress) > 0 { - secretKey, err := os.ReadFile(config.FireblocksConfig.SecretKeyPath) + if !config.FireblocksConfig.Disable { + validConfigflag := len(config.FireblocksConfig.APIKeyName) > 0 && + len(config.FireblocksConfig.SecretKeyName) > 0 && + len(config.FireblocksConfig.BaseURL) > 0 && + len(config.FireblocksConfig.VaultAccountName) > 0 && + len(config.FireblocksConfig.WalletAddress) > 0 && + len(config.FireblocksConfig.Region) > 0 + if !validConfigflag { + return errors.New("fireblocks config is either invalid or incomplete") + } + apiKey, err := secretmanager.ReadStringFromSecretManager(context.Background(), config.FireblocksConfig.APIKeyName, config.FireblocksConfig.Region) + if err != nil { + return fmt.Errorf("cannot read fireblocks api key %s from secret manager: %w", config.FireblocksConfig.APIKeyName, err) + } + secretKey, err := secretmanager.ReadStringFromSecretManager(context.Background(), config.FireblocksConfig.SecretKeyName, config.FireblocksConfig.Region) if err != nil { - return fmt.Errorf("cannot read fireblocks secret from %s: %w", config.FireblocksConfig.SecretKeyPath, err) + return fmt.Errorf("cannot read fireblocks secret key %s from secret manager: %w", config.FireblocksConfig.SecretKeyName, err) } fireblocksClient, err := fireblocks.NewClient( - config.FireblocksConfig.APIKey, - secretKey, + apiKey, + []byte(secretKey), config.FireblocksConfig.BaseURL, config.TimeoutConfig.ChainReadTimeout, logger, diff --git a/go.mod b/go.mod index cb42732bd3..2372a69529 100644 --- a/go.mod +++ b/go.mod @@ -10,6 +10,7 @@ require ( github.com/aws/aws-sdk-go-v2 v1.21.2 github.com/aws/aws-sdk-go-v2/credentials v1.13.43 github.com/aws/aws-sdk-go-v2/feature/dynamodb/attributevalue v1.10.40 + github.com/aws/aws-sdk-go-v2/service/secretsmanager v1.21.2 github.com/consensys/gnark-crypto v0.12.1 github.com/ethereum/go-ethereum v1.13.14 github.com/fxamacker/cbor/v2 v2.5.0 diff --git a/go.sum b/go.sum index 09b620181e..d38494086a 100644 --- a/go.sum +++ b/go.sum @@ -38,6 +38,7 @@ github.com/allegro/bigcache v1.2.1-0.20190218064605-e24eb225f156 h1:eMwmnE/GDgah github.com/allegro/bigcache v1.2.1-0.20190218064605-e24eb225f156/go.mod h1:Cb/ax3seSYIx7SuZdm2G2xzfwmv3TPSk2ucNfQESPXM= github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8= github.com/aws/aws-sdk-go-v2 v1.18.1/go.mod h1:uzbQtefpm44goOPmdKyAlXSNcwlRgF3ePWVW6EtJvvw= +github.com/aws/aws-sdk-go-v2 v1.20.3/go.mod h1:/RfNgGmRxI+iFOB1OeJUyxiU+9s88k3pfHvDagGEp0M= github.com/aws/aws-sdk-go-v2 v1.21.0/go.mod h1:/RfNgGmRxI+iFOB1OeJUyxiU+9s88k3pfHvDagGEp0M= github.com/aws/aws-sdk-go-v2 v1.21.2 h1:+LXZ0sgo8quN9UOKXXzAWRT3FWd4NxeXWOZom9pE7GA= github.com/aws/aws-sdk-go-v2 v1.21.2/go.mod h1:ErQhvNuEMhJjweavOYhxVkn2RUx7kQXVATHrjKtxIpM= @@ -60,10 +61,12 @@ github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.13.13/go.mod h1:f/Ib/qYjhV2/qds github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.11.71 h1:SAB1UAVaf6nGCu3zyIrV+VWsendXrms1GqtW4zBotKA= github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.11.71/go.mod h1:ZNo5H4PR3/fwsXYqb+Ld5YAfvHcYCbltaTTtSay4l2o= github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.34/go.mod h1:wZpTEecJe0Btj3IYnDx/VlUzor9wm3fJHyvLpQF0VwY= +github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.40/go.mod h1:5kKmFhLeOVy6pwPDpDNA6/hK/d6URC98pqDDqHgdBx4= github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.41/go.mod h1:CrObHAuPneJBlfEJ5T3szXOUkLEThaGfvnhTf33buas= github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.43 h1:nFBQlGtkbPzp/NjZLuFxRqmT91rLJkgvsEQs68h962Y= github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.43/go.mod h1:auo+PiyLl0n1l8A0e8RIeR8tOzYPfZZH/JNlrJ8igTQ= github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.28/go.mod h1:7VRpKQQedkfIEXb4k52I7swUnZP0wohVajJMRn3vsUw= +github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.34/go.mod h1:RZP0scceAyhMIQ9JvFp7HvkpcgqjL4l/4C+7RAeGbuM= github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.35/go.mod h1:SJC1nEVVva1g3pHAIdCp7QsRIkMmLAgoDquQ9Rr8kYw= github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.37 h1:JRVhO25+r3ar2mKGP7E0LDl8K9/G36gjlqca5iQbaqc= github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.37/go.mod h1:Qe+2KtKml+FEsQF/DHmDV+xjtche/hwoF75EG4UlHW8= @@ -95,6 +98,8 @@ github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.15.6/go.mod h1:lnc2taB github.com/aws/aws-sdk-go-v2/service/s3 v1.36.0/go.mod h1:aVbf0sko/TsLWHx30c/uVu7c62+0EAJ3vbxaJga0xCw= github.com/aws/aws-sdk-go-v2/service/s3 v1.40.2 h1:Ll5/YVCOzRB+gxPqs2uD0R7/MyATC0w85626glSKmp4= github.com/aws/aws-sdk-go-v2/service/s3 v1.40.2/go.mod h1:Zjfqt7KhQK+PO1bbOsFNzKgaq7TcxzmEoDWN8lM0qzQ= +github.com/aws/aws-sdk-go-v2/service/secretsmanager v1.21.2 h1:6N4VK/eLcMYonOqGgihkYlgjE2URxEMqjjS/1zErTKA= +github.com/aws/aws-sdk-go-v2/service/secretsmanager v1.21.2/go.mod h1:aYWGu8cQcyRdfDi/V4agl6VDmDz2N42VhiHj0xMf77o= github.com/aws/aws-sdk-go-v2/service/sso v1.12.12/go.mod h1:HuCOxYsF21eKrerARYO6HapNeh9GBNq7fius2AcwodY= github.com/aws/aws-sdk-go-v2/service/sso v1.15.2 h1:JuPGc7IkOP4AaqcZSIcyqLpFSqBWK32rM9+a1g6u73k= github.com/aws/aws-sdk-go-v2/service/sso v1.15.2/go.mod h1:gsL4keucRCgW+xA85ALBpRFfdSLH4kHOVSnLMSuBECo= diff --git a/inabox/deploy/config.go b/inabox/deploy/config.go index c9201be618..380712e6ef 100644 --- a/inabox/deploy/config.go +++ b/inabox/deploy/config.go @@ -217,6 +217,7 @@ func (env *Config) generateBatcherVars(ind int, key, graphUrl, logPath string) B BATCHER_NUM_CONFIRMATIONS: "0", BATCHER_MAX_BLOBS_TO_FETCH_FROM_STORE: "100", BATCHER_FINALIZATION_BLOCK_DELAY: "5", + BATCHER_FIREBLOCKS_DISABLE: "true", } env.applyDefaults(&v, "BATCHER", "batcher", ind) diff --git a/inabox/deploy/env_vars.go b/inabox/deploy/env_vars.go index e93c055e8d..95f4f954f8 100644 --- a/inabox/deploy/env_vars.go +++ b/inabox/deploy/env_vars.go @@ -147,6 +147,8 @@ type BatcherVars struct { BATCHER_AWS_SECRET_ACCESS_KEY string BATCHER_AWS_ENDPOINT_URL string + + BATCHER_FIREBLOCKS_DISABLE string } func (vars BatcherVars) getEnvMap() map[string]string {