diff --git a/README.md b/README.md index 7e5fa8e..d308b9f 100644 --- a/README.md +++ b/README.md @@ -33,6 +33,7 @@ Summary: User can put AWS secret ARN as environment variable value. The `secrets-init` will resolve any environment value, using specified ARN, to referenced secret value. +If the secret is saved as a Key/Value pair, all the keys are applied to as environment variables and passed. The environment variable passed is ignored unless it is inside the key/value pair. ```sh # environment variable passed to `secrets-init` MY_DB_PASSWORD=arn:aws:secretsmanager:$AWS_REGION:$AWS_ACCOUNT_ID:secret:mydbpassword-cdma3 diff --git a/pkg/secrets/aws/secrets.go b/pkg/secrets/aws/secrets.go index 7a5959a..7ab246e 100644 --- a/pkg/secrets/aws/secrets.go +++ b/pkg/secrets/aws/secrets.go @@ -2,6 +2,7 @@ package aws import ( "context" + "encoding/json" "secrets-init/pkg/secrets" "strings" @@ -50,7 +51,20 @@ func (sp *SecretsProvider) ResolveSecrets(ctx context.Context, vars []string) ([ if err != nil { return vars, errors.Wrap(err, "failed to get secret from AWS Secrets Manager") } - env = key + "=" + *secret.SecretString + if IsJSON(secret.SecretString) { + var keyValueSecret map[string]string + err = json.Unmarshal([]byte(*secret.SecretString), &keyValueSecret) + if err != nil { + return vars, errors.Wrap(err, "failed to decode key/value secret") + } + for key, value := range keyValueSecret { + e := key + "=" + value + envs = append(envs, e) + } + continue // We continue to not add this ENV variable but only the environment variables that exists in the JSON + } else { + env = key + "=" + *secret.SecretString + } } else if strings.HasPrefix(value, "arn:aws:ssm") && strings.Contains(value, ":parameter/") { tokens := strings.Split(value, ":") // valid parameter ARN arn:aws:ssm:REGION:ACCOUNT:parameter/PATH @@ -80,3 +94,11 @@ func (sp *SecretsProvider) ResolveSecrets(ctx context.Context, vars []string) ([ return envs, nil } + +func IsJSON(str *string) bool { + if str == nil { + return false + } + var js json.RawMessage + return json.Unmarshal([]byte(*str), &js) == nil +} diff --git a/pkg/secrets/aws/secrets_test.go b/pkg/secrets/aws/secrets_test.go index f517a7a..ee4c799 100644 --- a/pkg/secrets/aws/secrets_test.go +++ b/pkg/secrets/aws/secrets_test.go @@ -67,6 +67,30 @@ func TestSecretsProvider_ResolveSecrets(t *testing.T) { return &sp }, }, + { + name: "get all secrets from from Secrets Manager json", + vars: []string{ + "test-secret-1=arn:aws:secretsmanager:12345678-json", + }, + want: []string{ + "TEST_1=test-secret-value-1", + "TEST_2=test-secret-value-2", + }, + mockServiceProvider: func(mockSM *mocks.SecretsManagerAPI, mockSSM *mocks.SSMAPI) secrets.Provider { + sp := SecretsProvider{sm: mockSM, ssm: mockSSM} + vars := map[string]string{ + "arn:aws:secretsmanager:12345678-json": "{\n \"TEST_1\": \"test-secret-value-1\",\n \"TEST_2\": \"test-secret-value-2\"\n}", + } + for n, v := range vars { + name := n + value := v + valueInput := secretsmanager.GetSecretValueInput{SecretId: &name} + valueOutput := secretsmanager.GetSecretValueOutput{SecretString: &value} + mockSM.On("GetSecretValue", &valueInput).Return(&valueOutput, nil) + } + return &sp + }, + }, { name: "no secrets", vars: []string{