awssecretmanagerrotationlambda

package module
v0.0.0-...-3bdb644 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Oct 15, 2024 License: MIT Imports: 12 Imported by: 0

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:

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

Examples

Constants

This section is empty.

Variables

This section is empty.

Functions

func New

func New(opts ...Option) *impl

func WithAWSSecretsManager

func WithAWSSecretsManager(svc AWSSecretsManager) func(*impl)

func WithPrepareSecret

func WithPrepareSecret(prepareSecret func(ctx context.Context, secretARN string, secretOld string) (secretNew string, _ error)) func(*impl)

func WithSetSecret

func WithSetSecret(setSecret func(ctx context.Context, secretARN string, versionID string) error) func(*impl)

func WithTestSecret

func WithTestSecret(testSecret func(ctx context.Context, secretARN string, versionID string) error) func(*impl)

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

type Option

type Option func(*impl)

Directories

Path Synopsis
internal

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL