rotate

package module
v2.0.3 Latest Latest
Warning

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

Go to latest
Published: May 10, 2021 License: Apache-2.0 Imports: 15 Imported by: 0

README

Password Rotation Lambda

password-rotation-lambda is an AWS Lambda function (in Go) that rotates database passwords using AWS Secrets Manager. Currently, it supports RDS for MySQL.

This package handles the four Secrets Manager rotation steps and database-specific password setting. Currently, it only supports RDS for MySQL. Your main.go imports this packages (which exports itself as rotate for short) and provides AWS sessions/clients and a SecretSetter to decode your secret string.

package main

import (
	"log"

	"github.com/aws/aws-lambda-go/lambda"
	"github.com/aws/aws-sdk-go/aws/session"
	"github.com/aws/aws-sdk-go/service/rds"
	"github.com/aws/aws-sdk-go/service/secretsmanager"

	"github.com/square/password-rotation-lambda"
	"github.com/square/password-rotation-lambda/db/mysql"
)

func main() {
	// Start AWS session using env vars automatically set by Lambda
	sess, err := session.NewSession()
	if err != nil {
		log.Fatalf("error making AWS session: %s", err)
	}

	// Make password setter for MySQL (RDS)
	ps := mysql.NewPasswordSetter(mysql.Config{
		RDSClient: rds.New(sess),                   // RDS API client
		DbClient:  mysql.NewRDSClient(true, false), // RDS MySQL cilent (true=TLS, false=dry run)
	})

	// Make Rotator which is the Lambda function/handler
	r := rotate.NewRotator(rotate.Config{
		SecretsManager: secretsmanager.New(sess),
		PasswordSetter: ps,
	})

	// Run Rotator in Lambda, waiting for events from Secrets Manager
	lambda.Start(r.Handler)
}

More docs and examples to come.

Documentation

Index

Constants

View Source
const (
	EVENT_BEGIN_ROTATION              = "begin-rotation"
	EVENT_BEGIN_PASSWORD_ROTATION     = "begin-password-rotation"
	EVENT_END_PASSWORD_ROTATION       = "end-password-rotation"
	EVENT_BEGIN_PASSWORD_VERIFICATION = "begin-password-verification"
	EVENT_END_PASSWORD_VERIFICATION   = "end-password-verification"
	EVENT_NEW_PASSWORD_IS_CURRENT     = "new-password-is-current"
	EVENT_END_ROTATION                = "end-rotation"
	EVENT_BEGIN_PASSWORD_ROLLBACK     = "begin-password-rollback"
	EVENT_ERROR                       = "error"
)
View Source
const (
	AWSCURRENT = "AWSCURRENT"
	AWSPENDING = "AWSPENDING"
)
View Source
const (
	DEFAULT_PASSWORD_LENGTH = 20 // password character length for RandomPassword
)

Variables

View Source
var (
	// Debug enables debug output to STDERR. It does not print secret values.
	// Debug lines start with "DEBUG". AWS Lambda usually logs all output to CloudWatch Logs.
	Debug = false

	// DebugSecret IS DANGEROUS: it prints secret values to STDERR when Debug is enabled.
	// If Debug is false (disabled), this value is ignored.
	//
	// Be very careful enabling this!
	DebugSecret = false
)
View Source
var (
	// ErrInvalidStep is returned if the "Step" value in the Secrets Manager event
	// is not one of "createSecret", "setSecret", "testSecret", or "finishSecret".
	ErrInvalidStep = errors.New("invalid Step value from event")
)

Functions

func InvokedBySecretsManager

func InvokedBySecretsManager(event map[string]string) bool

InvokedBySecretsManager returns true if the event is from Secrets Manager.

Types

type Config

type Config struct {
	// SecretsManager is an AWS Secrets Manager client. Create one by calling
	// secretsmanager.New() using package github.com/aws/aws-sdk-go/service/secretsmanager.
	// See https://pkg.go.dev/github.com/aws/aws-sdk-go@v1.30.4/service/secretsmanager?tab=doc#SecretsManager
	// for more details. The client implements this data type.
	SecretsManager secretsmanageriface.SecretsManagerAPI

	// SecretSetter manages the secret value and rotates the password. This is
	// the most important user-provided object. If none is provided, RandomPassword
	// is used. See SecretSetter for more details.
	SecretSetter SecretSetter

	// PasswordSetter sets the new, rotated password on databases. Implementations
	// are provided in the db/ directory.
	PasswordSetter db.PasswordSetter

	// SkipDatabase skips setting the the new, rotated password on databases if true
	// but does all the other work. If there is a database issue that blocks a
	// Secrets Manager rotation, this lets the Secrets Manager rotation complete.
	// Normally, this should be false; only set to true when knowingly fixing an issue
	// that requires it.
	SkipDatabase bool

	// EventReceiver receives events during the four-step password rotation process.
	// If none is provided, NullEventReceiver is used. See EventReceiver for more details.
	EventReceiver EventReceiver
}

Config represents the user-provided configuration for a Rotator.

type Event

type Event struct {
	Name  string    // EVENT_ const
	Step  string    // "createSecret", "setSecret", "testSecret", or "finishSecret"
	Time  time.Time // when event occurred
	Error error     // non-nil if Step failed (Name will be EVENT_ERROR)
}

Event is an important event during the four-step Secrets Manager rotation process.

type EventReceiver

type EventReceiver interface {
	// Receive receives the Event sent by a Rotator during the four-step Secrets Manager
	// rotation process. If this function blocks, it blocks the rotation process.
	Receive(Event)
}

EventReceiver receives events from a Rotator during the four-step Secrets Manager rotation process.

type NullEventReceiver

type NullEventReceiver struct{}

NullEventReceiver is the default EventReceiver if none is provided in the Config. It ignores all events.

func (NullEventReceiver) Receive

func (r NullEventReceiver) Receive(Event)

type RandomPassword

type RandomPassword struct {

	// PasswordLength defines the length of the password generated by RandomPassword.
	// If not provided, DEFAULT_PASSWORD_LENGTH will be used
	PasswordLength int

	// ValidCharset defines the set of characters that random passwords generated
	// by RandomPassword may contain.
	// If not provided, the default charset
	//   ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789!@#$%^&*()-
	// will be used.
	ValidCharset []rune
}

RandomPassword is the default SecretSetter used by Rotator is none is specified in the Config. It requires the secret value to have two JSON fields: username and password. Other fields are ignored. It sets a random password DEFAULT_PASSWORD_LENGTH characters long using these characters:

ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789!@#$%^&*()-

RandomPassword does not support Handler (user-invoked password rotation), it only supports rotation by Secrets Manager. The password generated by RandomPassword may be configured by setting either `PasswordLength` or `ValidCharset` on initialization

func (RandomPassword) Credentials

func (s RandomPassword) Credentials(secret map[string]string) (username, password string)

func (RandomPassword) Handler

func (s RandomPassword) Handler(context.Context, map[string]string) (map[string]string, error)

func (RandomPassword) Init

func (RandomPassword) Rotate

func (s RandomPassword) Rotate(secret map[string]string) error

type Rotator

type Rotator struct {
	// contains filtered or unexported fields
}

Rotator is the AWS Lambda function and handler. Create a new Rotator by calling NewRotator, then use it in your main.go by calling lambda.Start(r.Handler) where "r" is the new Rotator. See the documentation and examples for more details.

Currently, only secret string, not secret binary, is used and it must be a JSON string with key-value pairs. See SecretSetter for details.

func NewRotator

func NewRotator(cfg Config) *Rotator

NewRotator creates a new Rotator.

func (*Rotator) CreateSecret

func (r *Rotator) CreateSecret(ctx context.Context, event map[string]string) error

CreateSecret is the first step in the Secrets Manager rotation process.

Do not call this function directly. It is exported only for testing.

func (*Rotator) FinishSecret

func (r *Rotator) FinishSecret(ctx context.Context, event map[string]string) error

FinishSecret is the fourth and final step in the Secrets Manager rotation process.

Do not call this function directly. It is exported only for testing.

func (*Rotator) Handler

func (r *Rotator) Handler(ctx context.Context, event map[string]string) (map[string]string, error)

Handler is the entry point for every invocation. This function is hooked into the Lambda framework by calling lambda.Start(r.Handler) where "r" is the Rotator returned by NewRotator.

Use only this function. The other Rotator functions are exported only for testing.

func (*Rotator) SetSecret

func (r *Rotator) SetSecret(ctx context.Context, event map[string]string) error

SetSecret is the second step in the Secrets Manager rotation process.

Do not call this function directly. It is exported only for testing.

func (*Rotator) TestSecret

func (r *Rotator) TestSecret(ctx context.Context, event map[string]string) error

TestSecret is the third step in the Secrets Manager rotation process.

Do not call this function directly. It is exported only for testing.

type SecretSetter

type SecretSetter interface {
	// Init is called before every Secrets Manager rotation step. Any user-specific
	// initialization should be done.
	Init(ctx context.Context, secret map[string]string) error

	// Handler is called if the event is not from Secrets Manager (user-invoked
	// password rotation). The event is user-defined data. After calling this method,
	// the Lambda function is done and no other methods are called.
	Handler(ctx context.Context, event map[string]string) (map[string]string, error)

	// Rotate changes the password in the secret. The method is expected to modify
	// the secret map. The caller (Rotator) passes the same map to Credentials to
	// return the username and password to set on the databases.
	Rotate(secret map[string]string) error

	// Credentials returns the username and password to set on the databases.
	Credentials(secret map[string]string) (username, password string)
}

SecretSetter manages the user-specific secret value. Rotator has only one requirement for the secret: it is a JSON string with key-value pairs. When Rotator gets the secret, it unmarshals the secret string as JSON into the map[string]string and passes it to the interface methods.

The secret value is user-defined. A suggested minimum value is:

{
  "username": "foo",
  "password": "bar"
}

Using that value as an exmaple, the Rotate method would change "password" to rotate the password, and the Credentials method would return "foo", "bar".

RandomPassword is used if no SecretSetter is specified in the Config passed to NewRotator.

Directories

Path Synopsis
db
examples
rds

Jump to

Keyboard shortcuts

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