Skip to content

Commit

Permalink
Merge pull request #2 from markussiebert/feature/use-asset-hash-as-ve…
Browse files Browse the repository at this point in the history
…rsionId

feat(Provider): use asset hash as versionId
  • Loading branch information
markussiebert authored Apr 7, 2022
2 parents 46fd1e6 + 9b1d44c commit 5ddea99
Show file tree
Hide file tree
Showing 12 changed files with 240 additions and 386 deletions.
354 changes: 56 additions & 298 deletions API.md

Large diffs are not rendered by default.

5 changes: 4 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -43,4 +43,7 @@ Other than that, or perhaps more importantly, my goal was to learn new things:

# Other Tools like this

* [sops-secretsmanager-cdk](https://github.com/isotoma/sops-secretsmanager-cdk): Does nearly the same (really, found it after this was already done). Less options than this construct.
The problem this Construct addresses is so good, already two other implementations exist:

* [isotoma/sops-secretsmanager-cdk](https://github.com/isotoma/sops-secretsmanager-cdk): Does nearly the same. Uses CustomResource, wraps the sops cli, does not support flatten. Found it after I published my solution to npm :-/
* [taimos/secretsmanager-versioning](https://github.com/taimos/secretsmanager-versioning): Different approach on the same problem. This is a cli tool with very nice integration into cdk and also handles git versioning information.
9 changes: 0 additions & 9 deletions go.mod

This file was deleted.

4 changes: 4 additions & 0 deletions lambda/__snapshots__/handler_json_test.snap

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 6 additions & 0 deletions lambda/__snapshots__/handler_yaml_test.snap

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion lambda/__snapshots__/main_test.snap

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

50 changes: 30 additions & 20 deletions lambda/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import (
"log"
"regexp"
"strconv"
"strings"

runtime "github.com/aws/aws-lambda-go/lambda"
"github.com/aws/aws-sdk-go/aws"
Expand Down Expand Up @@ -66,23 +67,29 @@ func decryptSopsFileContent(content []byte, format string) (data []byte, err err
return resp, nil
}

func (a AWS) updateSecret(secretArn string, secretContent []byte) (data *secretsmanager.PutSecretValueOutput, err error) {
func (a AWS) updateSecret(sopsFileName string, secretArn string, secretContent []byte) (data *secretsmanager.PutSecretValueOutput, err error) {
secretContentString := string(secretContent)
clientRequestToken := strings.Split(sopsFileName, ".")[0]
input := &secretsmanager.PutSecretValueInput{
SecretId: &secretArn,
SecretString: &secretContentString,
SecretId: &secretArn,
SecretString: &secretContentString,
ClientRequestToken: &clientRequestToken,
}
secretResp, secretErr := a.secretsmanager.PutSecretValue(input)
if secretErr != nil {
return nil, errors.New(fmt.Sprintf("Failed to store secret value:\n%v\n", secretErr))
return nil, errors.New(fmt.Sprintf("Failed to store secret value:\nsecretArn: %s\nClientRequestToken: %s\n%v\n", secretArn, clientRequestToken, err))
}
re := regexp.MustCompile(`(^arn:.*:secretsmanager:)(.*)`)
arn := re.ReplaceAllString(*secretResp.ARN, `arn:custom:sopssync:$2`)
arn := generatePhysicalResourceId(*secretResp.ARN)
secretResp.ARN = &arn
log.Printf("Succesfully stored secret:\n%v\n", secretResp)
return secretResp, nil
}

func generatePhysicalResourceId(input string) string {
re := regexp.MustCompile(`(^arn:.*:secretsmanager:)(.*)`)
return re.ReplaceAllString(input, `arn:custom:sopssync:$2`)
}

func (a AWS) syncSopsToSecretsmanager(ctx context.Context, event cfn.Event) (physicalResourceID string, data map[string]interface{}, err error) {
// event
// eventJson, _ := json.MarshalIndent(event, "", " ")
Expand All @@ -94,24 +101,26 @@ func (a AWS) syncSopsToSecretsmanager(ctx context.Context, event cfn.Event) (phy

jsonResourceProps, err := json.Marshal(event.ResourceProperties)
if err != nil {
return "", nil, err
return "error", nil, err
}

resourceProperties := SopsSyncResourcePropertys{}
if err := json.Unmarshal(jsonResourceProps, &resourceProperties); err != nil {
return "", nil, err
}

tempArn := generatePhysicalResourceId(resourceProperties.SecretARN)

sopsFile := resourceProperties.SopsS3File

// This is where the magic happens
ecnryptedContent, err := a.getS3FileContent(sopsFile)
if err != nil {
return "", nil, err
return tempArn, nil, err
}
decryptedContent, err := decryptSopsFileContent(ecnryptedContent, resourceProperties.Format)
if err != nil {
return "", nil, err
return tempArn, nil, err
}
//log.Println(string(decryptedContent))
var decryptedInterface interface{}
Expand All @@ -120,14 +129,14 @@ func (a AWS) syncSopsToSecretsmanager(ctx context.Context, event cfn.Event) (phy
{
err := json.Unmarshal(decryptedContent, &decryptedInterface)
if err != nil {
return "", nil, err
return tempArn, nil, err
}
}
case "yaml":
{
err := yaml.Unmarshal(decryptedContent, &decryptedInterface)
if err != nil {
return "", nil, err
return tempArn, nil, err
}
}
default:
Expand All @@ -139,7 +148,7 @@ func (a AWS) syncSopsToSecretsmanager(ctx context.Context, event cfn.Event) (phy
}
resourcePropertiesFlatten, err := strconv.ParseBool(resourceProperties.Flatten)
if err != nil {
return "", nil, err
return tempArn, nil, err
}

var finalInterface interface{}
Expand All @@ -148,7 +157,7 @@ func (a AWS) syncSopsToSecretsmanager(ctx context.Context, event cfn.Event) (phy
flattenedInterface := make(map[string]interface{})
err := flatten("", decryptedInterface, flattenedInterface)
if err != nil {
return "", nil, err
return tempArn, nil, err
}
finalInterface = flattenedInterface
} else {
Expand All @@ -160,12 +169,12 @@ func (a AWS) syncSopsToSecretsmanager(ctx context.Context, event cfn.Event) (phy
}
resourcePropertiesStringifyValues, err := strconv.ParseBool(resourceProperties.StringifyValues)
if err != nil {
return "", nil, err
return tempArn, nil, err
}
if resourcePropertiesStringifyValues {
finalInterface, _, err = stringifyValues(finalInterface)
if err != nil {
return "", nil, err
return tempArn, nil, err
}
}

Expand All @@ -174,23 +183,23 @@ func (a AWS) syncSopsToSecretsmanager(ctx context.Context, event cfn.Event) (phy
}
resourcePropertieConvertToJSON, err := strconv.ParseBool(resourceProperties.ConvertToJSON)
if err != nil {
return "", nil, err
return tempArn, nil, err
}
if resourcePropertieConvertToJSON || resourceProperties.Format == "json" {
decryptedContent, err = toJSON(finalInterface)
if err != nil {
return "", nil, err
return tempArn, nil, err
}
} else if resourceProperties.Format == "yaml" {
decryptedContent, err = toYAML(finalInterface)
if err != nil {
return "", nil, err
return tempArn, nil, err
}
}
// Write the secret
updateSecretResp, err := a.updateSecret(resourceProperties.SecretARN, decryptedContent)
updateSecretResp, err := a.updateSecret(sopsFile.Key, resourceProperties.SecretARN, decryptedContent)
if err != nil {
return "", nil, err
return tempArn, nil, err
}

returnData := make(map[string]interface{})
Expand All @@ -204,6 +213,7 @@ func (a AWS) syncSopsToSecretsmanager(ctx context.Context, event cfn.Event) (phy
} else if event.RequestType == cfn.RequestDelete {
return "", nil, nil
} else {
// Should never happen ...
return "", nil, errors.New(fmt.Sprintf("RequestType '%s' not supported", event.RequestType))
}
}
Expand Down
3 changes: 2 additions & 1 deletion lambda/main_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -48,10 +48,11 @@ func Test_UpdateSecret(t *testing.T) {
t: t,
},
}
fileName := "4547532a137611d83958d17095c6c2d38ae0036a760c3b79c9dd5957d1c20cf2.yaml"
inputArn := "arn:${Partition}:secretsmanager:${Region}:${Account}:secret:${SecretId}"
secretValue := []byte("some-secret-data")

response, err := mocks.updateSecret(inputArn, secretValue)
response, err := mocks.updateSecret(fileName, inputArn, secretValue)
check(err)

snaps.MatchSnapshot(t, response)
Expand Down
Loading

0 comments on commit 5ddea99

Please sign in to comment.