Skip to content

Commit

Permalink
Changed façade API;
Browse files Browse the repository at this point in the history
Adjusted release notes.

Signed-off-by: Dmitry Kisler <admin@dkisler.com>
  • Loading branch information
kislerdm committed Jan 24, 2023
1 parent 88e5a04 commit af90a3d
Show file tree
Hide file tree
Showing 7 changed files with 278 additions and 29 deletions.
44 changes: 43 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,51 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [v0.1.1] - 2023-01-25

### Changed

- Changed the module's façade API:
- **now**: The main function `NewHandler(cfg Config)` is used to initialise the Lambda handler used as the input
to [`lambda.Start`](https://github.com/aws/aws-lambda-go/blob/0d45ea2853e8fa138a242336f40eadf5f66fe947/lambda/entry.go#L44)
function to initialize AWS Lambda
- **was**: The main function `Start(cfg Config)` wraps the
function [`lambda.Start`](https://github.com/aws/aws-lambda-go/blob/0d45ea2853e8fa138a242336f40eadf5f66fe947/lambda/entry.go#L44)
to initialize AWS Lambda

An example:

```go
package main

import (
"log"
"os"

"github.com/aws/aws-lambda-go/lambda"

secretRotation "github.com/kislerdm/aws-lambda-secret-rotation"
)

func main() {
/* ... */
handler, err := secretRotation.NewHandler(
secretRotation.Config{
/* ... */
Debug: secretRotation.StrToBool(os.Getenv("DEBUG")),
},
)
if err != nil {
log.Fatalf("unable to init lambda handler to rotate secret, %v", err)
}

lambda.Start(handler)
}
```

## [v0.1.0] - 2023-01-22

### Added
### Added

- Lambda handler
- Interfaces for clients to communicate with the AWS Secretsmanager and the service delegated secrets storage
1 change: 0 additions & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ module github.com/kislerdm/aws-lambda-secret-rotation
go 1.19

require (
github.com/aws/aws-lambda-go v1.37.0
github.com/aws/aws-sdk-go-v2 v1.17.3
github.com/aws/aws-sdk-go-v2/service/secretsmanager v1.18.1
github.com/aws/smithy-go v1.13.5
Expand Down
6 changes: 0 additions & 6 deletions go.sum
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
github.com/aws/aws-lambda-go v1.37.0 h1:WXkQ/xhIcXZZ2P5ZBEw+bbAKeCEcb5NtiYpSwVVzIXg=
github.com/aws/aws-lambda-go v1.37.0/go.mod h1:jwFe2KmMsHmffA1X2R09hH6lFzJQxzI8qK17ewzbQMM=
github.com/aws/aws-sdk-go-v2 v1.17.3 h1:shN7NlnVzvDUgPQ+1rLMSxY8OWRNDRYtiqe0p/PgrhY=
github.com/aws/aws-sdk-go-v2 v1.17.3/go.mod h1:uzbQtefpm44goOPmdKyAlXSNcwlRgF3ePWVW6EtJvvw=
github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.27 h1:I3cakv2Uy1vNmmhRQmFptYDxOvBnwCdNwyw63N0RaRU=
Expand All @@ -11,15 +9,11 @@ github.com/aws/aws-sdk-go-v2/service/secretsmanager v1.18.1/go.mod h1:jAeo/PdIJZ
github.com/aws/smithy-go v1.13.5 h1:hgz0X/DX0dGqTYpGALqXJoRKRj5oQ7150i5FdTePzO8=
github.com/aws/smithy-go v1.13.5/go.mod h1:Tg+OJXh4MB2R/uN61Ko2f6hTZwB/ZYGOtib8J3gBHzA=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/google/go-cmp v0.5.8 h1:e6P7q2lk1O+qJJb4BtCQXlK8vWEO8V1ZeuEdJNOqZyg=
github.com/google/go-cmp v0.5.8/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo=
github.com/jmespath/go-jmespath/internal/testify v1.5.1/go.mod h1:L3OGu8Wl2/fWfCI6z80xFu9LTZmf1ZRjMHUOPmWr69U=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.7.2 h1:4jaiDzPyXQvSd7D0EjG45355tLlV3VOECpq10pLC+8s=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
22 changes: 6 additions & 16 deletions lambda.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,13 +43,10 @@ type secretsmanagerTriggerPayload struct {
Step string `json:"Step"`
}

// Handler the type defining the lambda handler function.
type Handler func(ctx context.Context, event secretsmanagerTriggerPayload) error

// NewHandler initialises lambda handler.
func NewHandler(cfg Config) (Handler, error) {
if err := validateConfig(cfg); err != nil {
return nil, err
func NewHandler(cfg Config) (func(ctx context.Context, event secretsmanagerTriggerPayload) error, error) {
if cfg.SecretObj == nil {
return nil, errors.New("configuration for SecretObj type must be set")
}

return func(ctx context.Context, event secretsmanagerTriggerPayload) error {
Expand All @@ -58,7 +55,7 @@ func NewHandler(cfg Config) (Handler, error) {
"[DEBUG] arn: " + event.SecretARN + "; step: " + event.Step + "; token: " + event.Token + "\n",
)
}
if err := validateEvent(ctx, event, cfg.SecretsmanagerClient); err != nil {
if err := validateInput(ctx, event, cfg.SecretsmanagerClient); err != nil {
if cfg.Debug {
log.Println("[DEBUG] validation error:+" + err.Error() + "\n")
}
Expand All @@ -81,13 +78,6 @@ func NewHandler(cfg Config) (Handler, error) {
}, nil
}

func validateConfig(cfg Config) error {
if cfg.SecretObj == nil {
return errors.New("configuration for SecretObj type must be set")
}
return nil
}

// SecretsmanagerClient client to communicate with the secretsmanager.
type SecretsmanagerClient interface {
GetSecretValue(
Expand Down Expand Up @@ -122,8 +112,8 @@ type ServiceClient interface {
Test(ctx context.Context, secret any) error
}

// validateEvent checks if the secret version is staged correctly.
func validateEvent(ctx context.Context, event secretsmanagerTriggerPayload, client SecretsmanagerClient) error {
// validateInput checks if the secret version is staged correctly.
func validateInput(ctx context.Context, event secretsmanagerTriggerPayload, client SecretsmanagerClient) error {
v, err := client.DescribeSecret(
ctx, &secretsmanager.DescribeSecretInput{
SecretId: aws.String(event.SecretARN),
Expand Down
225 changes: 222 additions & 3 deletions lambda_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -846,13 +846,13 @@ func Test_validateEvent(t *testing.T) {
for _, tt := range tests {
t.Run(
tt.name, func(t *testing.T) {
err := validateEvent(tt.args.ctx, tt.args.event, tt.args.client)
err := validateInput(tt.args.ctx, tt.args.event, tt.args.client)
if (err != nil) != tt.wantErr {
t.Errorf("validateEvent() error = %v, wantErr %v", err, tt.wantErr)
t.Errorf("validateInput() error = %v, wantErr %v", err, tt.wantErr)

if tt.errType != nil {
if !errors.Is(err, tt.errType) {
t.Errorf("validateEvent() returned error type does not match expectation")
t.Errorf("validateInput() returned error type does not match expectation")
}
}
}
Expand Down Expand Up @@ -942,3 +942,222 @@ func TestStrToBool(t *testing.T) {
)
}
}

func TestNewHandler(t *testing.T) {
type args struct {
cfg Config
}
type argsHandler struct {
ctx context.Context
event secretsmanagerTriggerPayload
}
tests := []struct {
name string
args args
argsHandler argsHandler
wantErrInit bool
wantErr bool
}{
{
name: "unhappy path: SecretObj set to nil",
args: args{
cfg: Config{},
},
argsHandler: argsHandler{},
wantErrInit: true,
wantErr: false,
},
{
name: "unhappy path: unknown step",
args: args{
cfg: Config{
SecretsmanagerClient: &mockSecretsmanagerClient{
secretAWSCurrent: "arn:aws:secretsmanager:us-east-1:000000000000:secret:foo/bar-5BKPC8",
secretByID: map[string]map[string]string{
"foo": {
"AWSCURRENT": placeholderSecretUserStr,
},
},
rotationEnabled: aws.Bool(true),
},
SecretObj: &map[string]string{},
Debug: true,
},
},
argsHandler: argsHandler{
ctx: context.TODO(),
event: secretsmanagerTriggerPayload{
SecretARN: "arn:aws:secretsmanager:us-east-1:000000000000:secret:foo/bar-5BKPC8",
Token: "foo",
Step: "foobar",
},
},
wantErrInit: false,
wantErr: true,
},
{
name: "unhappy path: does not pass input validation",
args: args{
cfg: Config{
SecretsmanagerClient: &mockSecretsmanagerClient{
secretAWSCurrent: "arn:aws:secretsmanager:us-east-1:000000000000:secret:foo/bar-5BKPC8",
secretByID: map[string]map[string]string{
"foo": {
"AWSCURRENT": placeholderSecretUserStr,
},
},
},
SecretObj: &map[string]string{},
Debug: true,
},
},
argsHandler: argsHandler{
ctx: context.TODO(),
event: secretsmanagerTriggerPayload{
SecretARN: "arn:aws:secretsmanager:us-east-1:000000000000:secret:foo/bar-5BKPC8",
Token: "foo",
Step: "foobar",
},
},
wantErrInit: false,
wantErr: true,
},
{
name: "happy path: createSecret step",
args: args{
cfg: Config{
SecretsmanagerClient: &mockSecretsmanagerClient{
secretAWSCurrent: "arn:aws:secretsmanager:us-east-1:000000000000:secret:foo/bar-5BKPC8",
secretByID: map[string]map[string]string{
"foo": {
"AWSCURRENT": placeholderSecretUserStr,
"AWSPENDING": placeholderSecretUserNewStr,
},
},
rotationEnabled: aws.Bool(true),
},
ServiceClient: mockDBClient{},
SecretObj: &map[string]string{},
Debug: true,
},
},
argsHandler: argsHandler{
ctx: context.TODO(),
event: secretsmanagerTriggerPayload{
SecretARN: "arn:aws:secretsmanager:us-east-1:000000000000:secret:foo/bar-5BKPC8",
Token: "foo",
Step: "createSecret",
},
},
wantErrInit: false,
wantErr: false,
},
{
name: "happy path: setSecret step",
args: args{
cfg: Config{
SecretsmanagerClient: &mockSecretsmanagerClient{
secretAWSCurrent: "arn:aws:secretsmanager:us-east-1:000000000000:secret:foo/bar-5BKPC8",
secretByID: map[string]map[string]string{
"foo": {
"AWSCURRENT": placeholderSecretUserStr,
"AWSPENDING": placeholderSecretUserNewStr,
},
},
rotationEnabled: aws.Bool(true),
},
ServiceClient: mockDBClient{},
SecretObj: &map[string]string{},
Debug: true,
},
},
argsHandler: argsHandler{
ctx: context.TODO(),
event: secretsmanagerTriggerPayload{
SecretARN: "arn:aws:secretsmanager:us-east-1:000000000000:secret:foo/bar-5BKPC8",
Token: "foo",
Step: "setSecret",
},
},
wantErrInit: false,
wantErr: false,
},
{
name: "happy path: testSecret step",
args: args{
cfg: Config{
SecretsmanagerClient: &mockSecretsmanagerClient{
secretAWSCurrent: "arn:aws:secretsmanager:us-east-1:000000000000:secret:foo/bar-5BKPC8",
secretByID: map[string]map[string]string{
"foo": {
"AWSCURRENT": placeholderSecretUserStr,
"AWSPENDING": placeholderSecretUserNewStr,
},
},
rotationEnabled: aws.Bool(true),
},
ServiceClient: mockDBClient{},
SecretObj: &map[string]string{},
Debug: true,
},
},
argsHandler: argsHandler{
ctx: context.TODO(),
event: secretsmanagerTriggerPayload{
SecretARN: "arn:aws:secretsmanager:us-east-1:000000000000:secret:foo/bar-5BKPC8",
Token: "foo",
Step: "testSecret",
},
},
wantErrInit: false,
wantErr: false,
},
{
name: "happy path: finishSecret step",
args: args{
cfg: Config{
SecretsmanagerClient: &mockSecretsmanagerClient{
secretAWSCurrent: "arn:aws:secretsmanager:us-east-1:000000000000:secret:foo/bar-5BKPC8",
secretByID: map[string]map[string]string{
"foo": {
"AWSCURRENT": placeholderSecretUserStr,
"AWSPENDING": placeholderSecretUserNewStr,
},
},
rotationEnabled: aws.Bool(true),
},
ServiceClient: mockDBClient{},
SecretObj: &map[string]string{},
Debug: true,
},
},
argsHandler: argsHandler{
ctx: context.TODO(),
event: secretsmanagerTriggerPayload{
SecretARN: "arn:aws:secretsmanager:us-east-1:000000000000:secret:foo/bar-5BKPC8",
Token: "foo",
Step: "finishSecret",
},
},
wantErrInit: false,
wantErr: false,
},
}
for _, tt := range tests {
t.Run(
tt.name, func(t *testing.T) {
handler, err := NewHandler(tt.args.cfg)
if (err != nil) != tt.wantErrInit {
t.Errorf("NewHandler() error = %v, wantErrInit %v", err, tt.wantErrInit)
return
}
if !tt.wantErrInit {
if err := handler(tt.argsHandler.ctx, tt.argsHandler.event); (err != nil) != tt.wantErr {
t.Errorf("handler(ctx, event) error = %v, wantErr %v", err, tt.wantErr)
return
}
}
},
)
}
}
5 changes: 5 additions & 0 deletions plugin/neon/.release_notes/v0.1.2.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
## [v0.1.2] - 2023-01-25

### Changed

- Bumped `github.com/kislerdm/aws-lambda-secret-rotation` to v0.1.1
4 changes: 2 additions & 2 deletions plugin/neon/go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,15 @@ module github.com/kislerdm/aws-lambda-secret-rotation/plugin/neon
go 1.19

require (
github.com/aws/aws-lambda-go v1.37.0
github.com/aws/aws-sdk-go-v2/config v1.18.8
github.com/aws/aws-sdk-go-v2/service/secretsmanager v1.18.1
github.com/kislerdm/aws-lambda-secret-rotation v0.1.0
github.com/kislerdm/aws-lambda-secret-rotation v0.1.1
github.com/kislerdm/neon-sdk-go v0.1.4
github.com/lib/pq v1.10.7
)

require (
github.com/aws/aws-lambda-go v1.37.0 // indirect
github.com/aws/aws-sdk-go-v2 v1.17.3 // indirect
github.com/aws/aws-sdk-go-v2/credentials v1.13.8 // indirect
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.12.21 // indirect
Expand Down

0 comments on commit af90a3d

Please sign in to comment.