Skip to content

Commit

Permalink
feat: AWS support object mutation (#142)
Browse files Browse the repository at this point in the history
* feat: enable AWS object mutation

Signed-off-by: Bence Csati <[email protected]>

feat: enable AWS object mutation

Signed-off-by: Bence Csati <[email protected]>

* chore: code review

Signed-off-by: Bence Csati <[email protected]>

---------

Signed-off-by: Bence Csati <[email protected]>
  • Loading branch information
csatib02 authored Aug 14, 2024
1 parent 2f964fb commit d60c1b7
Show file tree
Hide file tree
Showing 5 changed files with 103 additions and 53 deletions.
94 changes: 49 additions & 45 deletions pkg/provider/aws/common.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,31 +39,31 @@ func getDataFromStore(ctx context.Context, storeClient client, storeType string,
func getDataFromSM(ctx context.Context, storeClient client, data map[string]string) (map[string]string, error) {
var secretsMap = make(map[string]string, len(data))
for key, value := range data {
if strings.Contains(value, "secretsmanager:") {
secret, err := storeClient.smClient.GetSecretValueWithContext(
ctx,
&secretsmanager.GetSecretValueInput{
SecretId: aws.String(value),
})
if err != nil {
return nil, fmt.Errorf("failed to get secret from AWS secrets manager: %w", err)
}

secretBytes, err := extractSecretValueFromSM(secret)
if err != nil {
return nil, fmt.Errorf("failed to extract secret value from AWS secrets manager: %w", err)
}

secretValue, err := parseSecretValueFromSM(secretBytes)
if err != nil {
return nil, fmt.Errorf("failed to parse secret value from AWS secrets manager: %w", err)
}

secretsMap[key] = string(secretValue)
if !strings.Contains(value, "secretsmanager:") {
secretsMap[key] = value
continue
}

secretsMap[key] = value
secret, err := storeClient.smClient.GetSecretValueWithContext(
ctx,
&secretsmanager.GetSecretValueInput{
SecretId: aws.String(value),
})
if err != nil {
return nil, fmt.Errorf("failed to get secret from AWS secrets manager: %w", err)
}

secretBytes, err := extractSecretValueFromSM(secret)
if err != nil {
return nil, fmt.Errorf("failed to extract secret value from AWS secrets manager: %w", err)
}

secretValue, err := parseSecretValueFromSM(secretBytes)
if err != nil {
return nil, fmt.Errorf("failed to parse secret value from AWS secrets manager: %w", err)
}

secretsMap[key] = string(secretValue)
}

return secretsMap, nil
Expand Down Expand Up @@ -126,39 +126,43 @@ func parseSecretValueFromSM(secretBytes []byte) ([]byte, error) {
func getDataFromSSM(ctx context.Context, storeClient client, data map[string]string) (map[string]string, error) {
var secretsMap = make(map[string]string, len(data))
for key, value := range data {
if strings.Contains(value, "ssm:") {
parameteredSecret, err := storeClient.ssmClient.GetParameterWithContext(
ctx,
&ssm.GetParameterInput{
Name: aws.String(value),
WithDecryption: aws.Bool(true),
})
if err != nil {
return nil, fmt.Errorf("failed to get secret from AWS SSM: %w", err)
}

secretsMap[key] = aws.StringValue(parameteredSecret.Parameter.Value)
if !strings.Contains(value, "ssm:") {
secretsMap[key] = value
continue
}

secretsMap[key] = value
parameteredSecret, err := storeClient.ssmClient.GetParameterWithContext(
ctx,
&ssm.GetParameterInput{
Name: aws.String(value),
WithDecryption: aws.Bool(true),
})
if err != nil {
return nil, fmt.Errorf("failed to get secret from AWS SSM: %w", err)
}

secretsMap[key] = aws.StringValue(parameteredSecret.Parameter.Value)
}

return secretsMap, nil
}
func checkOtherStoreForSecrets(ctx context.Context, storeClient client, data map[string]string) (map[string]string, error) {
// we might ARN's that are from the other store type
// we might have ARN's that are from the other store type
for k, v := range data {
if valid, storeType := isValidPrefixWithStoreType(v); valid {
secretFromOtherStore, err := getDataFromStore(ctx, storeClient, storeType, map[string]string{k: v})
if err != nil {
return nil, fmt.Errorf("getting data from store failed: %w", err)
}

for key, value := range secretFromOtherStore {
data[key] = value
}
valid, storeType := isValidPrefixWithStoreType(v)
if !valid {
continue
}

secretFromOtherStore, err := getDataFromStore(ctx, storeClient, storeType, map[string]string{k: v})
if err != nil {
return nil, fmt.Errorf("getting data from store failed: %w", err)
}

for key, value := range secretFromOtherStore {
data[key] = value
}

}

return data, nil
Expand Down
47 changes: 46 additions & 1 deletion pkg/provider/aws/object.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,55 @@ package aws

import (
"context"
"fmt"

"github.com/bank-vaults/secrets-webhook/pkg/provider"
"github.com/bank-vaults/secrets-webhook/pkg/provider/common"
)

func (m *mutator) MutateObject(_ context.Context, _ provider.ObjectMutateRequest) error {
func (m *mutator) MutateObject(ctx context.Context, mutateRequest provider.ObjectMutateRequest) error {
m.logger.Debug(fmt.Sprintf("mutating object: %s.%s", mutateRequest.Object.GetNamespace(), mutateRequest.Object.GetName()))

err := m.newClient(ctx, mutateRequest.K8sClient)
if err != nil {
return fmt.Errorf("creating AWS clients failed: %w", err)
}

return traverseObject(ctx, mutateRequest.Object.Object, *m.client)
}

func traverseObject(ctx context.Context, o interface{}, client client) error {
var iterator common.Iterator
switch value := o.(type) {
case map[string]interface{}:
iterator = common.MapIterator(value)

case []interface{}:
iterator = common.SliceIterator(value)

default:
return nil
}

for e := range iterator {
switch s := e.Get().(type) {
case string:
if valid, storeType := isValidPrefixWithStoreType(s); valid {
dataFromStore, err := getDataFromStore(ctx, client, storeType, map[string]string{"data": s})
if err != nil {
return fmt.Errorf("failed to get data from store: %w", err)
}

e.Set(dataFromStore["data"])
}

case map[string]interface{}, []interface{}:
err := traverseObject(ctx, e.Get(), client)
if err != nil {
return fmt.Errorf("failed to traverse object: %w", err)
}
}
}

return nil
}
2 changes: 1 addition & 1 deletion pkg/provider/aws/secret.go
Original file line number Diff line number Diff line change
Expand Up @@ -159,7 +159,7 @@ func secretNeedsMutation(secret *corev1.Secret) (bool, string, error) {
return false, "", fmt.Errorf("invalid auth type")
}

// check if any of the sub-keys have a vault prefix
// check if any of the sub-keys have a valid prefix
for _, v := range authMap {
if valid, storeType := isValidPrefixWithStoreType(v.(string)); valid {
return true, storeType, nil
Expand Down
2 changes: 1 addition & 1 deletion pkg/provider/bao/configmap.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ func (m *mutator) MutateConfigMap(ctx context.Context, mutateRequest provider.Co
TransitKeyID: m.config.TransitKeyID,
TransitPath: m.config.TransitPath,
TransitBatchSize: m.config.TransitBatchSize,
}, m.client, nil, m.logger)
}, m.client, nil /* baoinjector.SecretRenewer */, m.logger)

mutateRequest.ConfigMap.Data, err = injector.GetDataFromBao(mutateRequest.ConfigMap.Data)
if err != nil {
Expand Down
11 changes: 6 additions & 5 deletions pkg/provider/vault/configmap.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,11 +36,12 @@ func (m *mutator) MutateConfigMap(ctx context.Context, mutateRequest provider.Co
}
defer m.client.Close()

injector := vaultinjector.NewSecretInjector(vaultinjector.Config{
TransitKeyID: m.config.TransitKeyID,
TransitPath: m.config.TransitPath,
TransitBatchSize: m.config.TransitBatchSize,
}, m.client, nil, m.logger)
injector := vaultinjector.NewSecretInjector(
vaultinjector.Config{
TransitKeyID: m.config.TransitKeyID,
TransitPath: m.config.TransitPath,
TransitBatchSize: m.config.TransitBatchSize,
}, m.client, nil /* vaultinjector.SecretRenewer */, m.logger)

mutateRequest.ConfigMap.Data, err = injector.GetDataFromVault(mutateRequest.ConfigMap.Data)
if err != nil {
Expand Down

0 comments on commit d60c1b7

Please sign in to comment.