Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
c7f6258
Add support for multiple keys per secret
passuied Mar 19, 2025
b5e8867
Advertise feature if metadata property is set to tru
passuied Mar 19, 2025
aa86c43
Add BulkGetSecret tests
passuied Mar 19, 2025
852e675
Merge branch 'main' into feature/aws-secret-supports-multiple-keys
passuied Mar 21, 2025
fac1772
format
passuied Mar 24, 2025
04d68d8
Rename metadata to match feature name
passuied Apr 1, 2025
0110e96
Merge branch 'main' into feature/aws-secret-supports-multiple-keys
cicoyle Apr 1, 2025
adcb27f
fixed missed ref in rename
passuied Apr 2, 2025
c1dfc8d
Merge branch 'main' into feature/aws-secret-supports-multiple-keys
cicoyle Apr 14, 2025
a0d9c2f
fixed cases where the stored values are nested json.
passuied Apr 22, 2025
07a0095
linting error
passuied Apr 22, 2025
c694d58
Add'l test case per PR feedback
passuied Apr 23, 2025
e0d864c
Merge branch 'main' into feature/aws-secret-supports-multiple-keys
cicoyle Jun 24, 2025
3eb02fb
addressing linting errors
passuied Jun 24, 2025
40e099f
PR feedback
passuied Jun 24, 2025
b5f26b1
PR feedback #2
passuied Jun 24, 2025
3b600b7
Merge branch 'main' into feature/aws-secret-supports-multiple-keys
passuied Jun 25, 2025
410a23a
Merge branch 'main' into feature/aws-secret-supports-multiple-keys
cicoyle Jun 26, 2025
c14b496
Merge branch 'main' into feature/aws-secret-supports-multiple-keys
cicoyle Jun 27, 2025
31dcb78
Merge branch 'main' into feature/aws-secret-supports-multiple-keys
passuied Jul 10, 2025
d203976
Merge branch 'main' into feature/aws-secret-supports-multiple-keys
passuied Jul 16, 2025
0cecf35
Merge branch 'main' into feature/aws-secret-supports-multiple-keys
passuied Jul 25, 2025
ccb79d9
Merge branch 'main' into feature/aws-secret-supports-multiple-keys
yaron2 Aug 21, 2025
93775dd
Merge branch 'main' into feature/aws-secret-supports-multiple-keys
passuied Aug 28, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions common/authentication/aws/client_fake.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,12 +43,18 @@ func (m *MockParameterStore) DescribeParametersWithContext(ctx context.Context,
type MockSecretManager struct {
GetSecretValueFn func(context.Context, *secretsmanager.GetSecretValueInput, ...request.Option) (*secretsmanager.GetSecretValueOutput, error)
secretsmanageriface.SecretsManagerAPI

ListSecretsFn func(context.Context, *secretsmanager.ListSecretsInput, ...request.Option) (*secretsmanager.ListSecretsOutput, error)
}

func (m *MockSecretManager) GetSecretValueWithContext(ctx context.Context, input *secretsmanager.GetSecretValueInput, option ...request.Option) (*secretsmanager.GetSecretValueOutput, error) {
return m.GetSecretValueFn(ctx, input, option...)
}

func (m *MockSecretManager) ListSecretsWithContext(ctx context.Context, input *secretsmanager.ListSecretsInput, option ...request.Option) (*secretsmanager.ListSecretsOutput, error) {
return m.ListSecretsFn(ctx, input, option...)
}

type MockDynamoDB struct {
GetItemWithContextFn func(ctx context.Context, input *dynamodb.GetItemInput, op ...request.Option) (*dynamodb.GetItemOutput, error)
PutItemWithContextFn func(ctx context.Context, input *dynamodb.PutItemInput, op ...request.Option) (*dynamodb.PutItemOutput, error)
Expand Down
8 changes: 7 additions & 1 deletion secretstores/aws/secretmanager/metadata.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -16,4 +16,10 @@ metadata:
description: |
The Secrets manager endpoint. The AWS SDK will generate a default endpoint if not specified. Useful for local testing with AWS LocalStack
example: '"http://localhost:4566"'
type: string
type: string
- name: multipleKeyValuesPerSecret
required: false
description: |
A boolean value to indicate if the secrets with multiple key/values should break keys out.
example: "true"
type: bool
65 changes: 51 additions & 14 deletions secretstores/aws/secretmanager/secretmanager.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,16 +40,18 @@ func NewSecretManager(logger logger.Logger) secretstores.SecretStore {
}

type SecretManagerMetaData struct {
Region string `json:"region" mapstructure:"region" mdignore:"true"`
AccessKey string `json:"accessKey" mapstructure:"accessKey" mdignore:"true"`
SecretKey string `json:"secretKey" mapstructure:"secretKey" mdignore:"true"`
SessionToken string `json:"sessionToken" mapstructure:"sessionToken" mdignore:"true"`
Endpoint string `json:"endpoint" mapstructure:"endpoint"`
Region string `json:"region" mapstructure:"region" mdignore:"true"`
AccessKey string `json:"accessKey" mapstructure:"accessKey" mdignore:"true"`
SecretKey string `json:"secretKey" mapstructure:"secretKey" mdignore:"true"`
SessionToken string `json:"sessionToken" mapstructure:"sessionToken" mdignore:"true"`
Endpoint string `json:"endpoint" mapstructure:"endpoint"`
MultipleKeyValuesPerSecret bool `json:"multipleKeyValuesPerSecret" mapstructure:"multipleKeyValuesPerSecret"`
}

type smSecretStore struct {
authProvider awsAuth.Provider
logger logger.Logger
authProvider awsAuth.Provider
logger logger.Logger
multipleKeyValuesPerSecret bool
}

// Init creates an AWS secret manager client.
Expand All @@ -67,6 +69,7 @@ func (s *smSecretStore) Init(ctx context.Context, metadata secretstores.Metadata
SessionToken: meta.SessionToken,
Endpoint: meta.Endpoint,
}
s.multipleKeyValuesPerSecret = meta.MultipleKeyValuesPerSecret

provider, err := awsAuth.NewProvider(ctx, opts, awsAuth.GetConfig(opts))
if err != nil {
Expand All @@ -76,6 +79,40 @@ func (s *smSecretStore) Init(ctx context.Context, metadata secretstores.Metadata
return nil
}

func convertMapAnyToString(m map[string]any) map[string]string {
result := make(map[string]string, len(m))
for k, v := range m {
switch v := v.(type) {
case string:
result[k] = v
default:
jVal, _ := json.Marshal(v)
result[k] = string(jVal)
}
}
return result
}

func (s *smSecretStore) formatSecret(output *secretsmanager.GetSecretValueOutput) map[string]string {
result := map[string]string{}

if output.Name != nil && output.SecretString != nil {
if s.multipleKeyValuesPerSecret {
data := map[string]any{}
if err := json.Unmarshal([]byte(*output.SecretString), &data); err != nil {
result[*output.Name] = *output.SecretString
} else {
// In case of a nested JSON value, we need to stringify it
result = convertMapAnyToString(data)
}
} else {
result[*output.Name] = *output.SecretString
}
}

return result
}

// GetSecret retrieves a secret using a key and returns a map of decrypted string/string values.
func (s *smSecretStore) GetSecret(ctx context.Context, req secretstores.GetSecretRequest) (secretstores.GetSecretResponse, error) {
var versionID *string
Expand All @@ -98,9 +135,7 @@ func (s *smSecretStore) GetSecret(ctx context.Context, req secretstores.GetSecre
resp := secretstores.GetSecretResponse{
Data: map[string]string{},
}
if output.Name != nil && output.SecretString != nil {
resp.Data[*output.Name] = *output.SecretString
}
resp.Data = s.formatSecret(output)

return resp, nil
}
Expand Down Expand Up @@ -131,9 +166,7 @@ func (s *smSecretStore) BulkGetSecret(ctx context.Context, req secretstores.Bulk
return secretstores.BulkGetSecretResponse{Data: nil}, fmt.Errorf("couldn't get secret: %s", *entry.Name)
}

if entry.Name != nil && secrets.SecretString != nil {
resp.Data[*entry.Name] = map[string]string{*entry.Name: *secrets.SecretString}
}
resp.Data[*entry.Name] = s.formatSecret(secrets)
}

nextToken = output.NextToken
Expand All @@ -160,7 +193,11 @@ func (s *smSecretStore) getSecretManagerMetadata(spec secretstores.Metadata) (*S

// Features returns the features available in this secret store.
func (s *smSecretStore) Features() []secretstores.Feature {
return []secretstores.Feature{} // No Feature supported.
if s.multipleKeyValuesPerSecret {
return []secretstores.Feature{secretstores.FeatureMultipleKeyValuesPerSecret}
}

return []secretstores.Feature{}
}

func (s *smSecretStore) GetComponentMetadata() (metadataInfo metadata.MetadataMap) {
Expand Down
Loading
Loading