Documentation ¶
Overview ¶
Package awssecretmanagerrotationlambda rotates a secret in https://aws.amazon.com/secrets-manager/
Following https://docs.aws.amazon.com/secretsmanager/latest/userguide/rotating-secrets.html and adding options to deal with JSON entries
And mostly based on:
- https://github.com/aws-samples/aws-secrets-manager-rotation-lambdas/blob/master/SecretsManagerRotationTemplate/lambda_function.py
- https://docs.aws.amazon.com/lambda/latest/dg/golang-handler.html
Steps to use:
- create secret manager entry with initial values
- deploy lambda https://docs.aws.amazon.com/lambda/latest/dg/golang-package.html
- => cd configo/awssecretmanager/awssecretmanagerrotationlambda/internal/cmd/lambda
- => GOOS=linux GOARCH=arm64 CGO_ENABLED=0 go build -tags lambda.norpc -o bootstrap main.go
- => zip SecretManagerRotater.zip bootstrap
- deploy lambda. Maybe with env var if you have a complex implementation.
- => upload .zip file
- => HandlerInfo is the name of the binary file to use. `bootstrap` in this case
- => runtime: "Custom runtime on Amazon Linux 2"
- => Architecture: arm64
- => use minimum perf lambda, Memory 128MB
- => set Permissions.Execution role
- => set Permissions.Resource-based policy statements
- configure secret manager entry to call lambda in "Rotation configuration"
- test by requesting a rotation: "Rotate secret immediately", validate the rotated value.
Permissions.Execution role: Policy SecretManagerRotateLambda. Example allowing access to all secrets.
{ "Version": "2012-10-17", "Statement": [ { "Sid": "VisualEditor0", "Effect": "Allow", "Action": "logs:CreateLogGroup", "Resource": "arn:aws:logs:us-east-1:_redacted_:*" }, { "Sid": "VisualEditor1", "Effect": "Allow", "Action": [ "logs:CreateLogStream", "logs:PutLogEvents" ], "Resource": "arn:aws:logs:us-east-1:_redacted_:log-group:/aws/lambda/SecretManagerRotate:*" }, { "Sid": "VisualEditor2", "Effect": "Allow", "Action": [ "secretsmanager:GetRandomPassword", "secretsmanager:GetSecretValue", "secretsmanager:DescribeSecret", "secretsmanager:PutSecretValue", "secretsmanager:UpdateSecretVersionStage" ], "Resource": "*" } ] }
Permissions.Resource-based policy statements ¶
- Statement ID:SecretManagerRotate
- Principal: secretsmanager.amazonaws.com
- PrincipalOrgID: -
- Conditions: None
- Action: lambda:InvokeFunction
Example (AllOptions) ¶
package main import ( "context" "github.com/aws/aws-lambda-go/lambda" "github.com/vincentkerdraon/configo/awssecretmanager/awssecretmanagerrotationlambda" ) func main() { //Do you own logic to change the secret old value into the new value //Useful if you are using a JSON document instead of only one value prepareSecretNew := func(ctx context.Context, secretARN, secretOld string) (secretNew string, _ error) { //(this is stupid simple logic for the example) return secretOld + "-", nil } //for example if you want the lambda to change the database secret (directly in the database service). setSecret := func(ctx context.Context, secretARN, versionID string) error { return nil } //if you used setSecret(), you want to test if it worked. testSecret := func(ctx context.Context, secretARN, versionID string) error { return nil } rotater := awssecretmanagerrotationlambda.New( awssecretmanagerrotationlambda.WithPrepareSecret(prepareSecretNew), awssecretmanagerrotationlambda.WithSetSecret(setSecret), awssecretmanagerrotationlambda.WithTestSecret(testSecret), // You could also inject AWSSecretsManagerService if needed // awssecretmanagerrotationlambda.WithAWSSecretsManager(svc), ) lambda.Start(rotater.HandleRequest) }
Output:
Example (Simple) ¶
package main import ( "github.com/aws/aws-lambda-go/lambda" "github.com/vincentkerdraon/configo/awssecretmanager/awssecretmanagerrotationlambda" ) func main() { //No argument in New(): using all the defaults rotater := awssecretmanagerrotationlambda.New() lambda.Start(rotater.HandleRequest) }
Output:
Example (WithComplexJSONValues) ¶
package main import ( "encoding/json" "os" "time" "github.com/aws/aws-lambda-go/lambda" "github.com/vincentkerdraon/configo/awssecretmanager/awssecretmanagerlib/lambdaconf" "github.com/vincentkerdraon/configo/awssecretmanager/awssecretmanagerrotationlambda" ) func main() { //let's say you have a secret manager entry: // - arn = SecretID1 // - content = {"key1":"val1","key2":"val2"} // we want the lambda to rotate "val1" but leave everything else untouched //ignore this. Assume configuration is set for the lambda err := os.Setenv("Conf", `{"Secrets":{"secretARN1":{"Keys":{"key1":{"Constraint":"AlphaNum","AlphaNumLength":16}}}}}`) if err != nil { panic(err) } //read lambda configuration lambdaConf := lambdaconf.LambdaConf{} lambdaConfJSON := os.Getenv("Conf") if err := json.Unmarshal([]byte(lambdaConfJSON), &lambdaConf); err != nil { panic(err) } if err := lambdaConf.Validate(); err != nil { panic(err) } //define the function to change the secret in a JSON document. prepareSecretNew := lambdaconf.PrepareNewSecretFormatted(time.Now(), lambdaConf) //Create and start the lambda listener rotater := awssecretmanagerrotationlambda.New(awssecretmanagerrotationlambda.WithPrepareSecret(prepareSecretNew)) lambda.Start(rotater.HandleRequest) // after running the lambda, the secret will change to something similar to: // - content = {"key1":"vqYXDhvE0oG0Smbj","key2":"val2"} }
Output:
Index ¶
- func New(opts ...Option) *impl
- func WithAWSSecretsManager(svc AWSSecretsManager) func(*impl)
- func WithPrepareSecret(...) func(*impl)
- func WithSetSecret(setSecret func(ctx context.Context, secretARN string, versionID string) error) func(*impl)
- func WithTestSecret(testSecret func(ctx context.Context, secretARN string, versionID string) error) func(*impl)
- type AWSSecretsManager
- type Option
Examples ¶
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func WithAWSSecretsManager ¶
func WithAWSSecretsManager(svc AWSSecretsManager) func(*impl)
func WithPrepareSecret ¶
func WithSetSecret ¶
Types ¶
type AWSSecretsManager ¶
type AWSSecretsManager interface { GetRandomPasswordWithContext(ctx context.Context, input *secretsmanager.GetRandomPasswordInput, opts ...request.Option) (*secretsmanager.GetRandomPasswordOutput, error) DescribeSecret(input *secretsmanager.DescribeSecretInput) (*secretsmanager.DescribeSecretOutput, error) GetSecretValueWithContext(ctx context.Context, input *secretsmanager.GetSecretValueInput, opts ...request.Option) (*secretsmanager.GetSecretValueOutput, error) PutSecretValueWithContext(ctx aws.Context, input *secretsmanager.PutSecretValueInput, opts ...request.Option) (*secretsmanager.PutSecretValueOutput, error) UpdateSecretVersionStageWithContext(ctx context.Context, input *secretsmanager.UpdateSecretVersionStageInput, opts ...request.Option) (*secretsmanager.UpdateSecretVersionStageOutput, error) }
func SvcSecretManagerDefault ¶
func SvcSecretManagerDefault() AWSSecretsManager
Click to show internal directories.
Click to hide internal directories.