/
aws_secret.go
108 lines (92 loc) · 3.74 KB
/
aws_secret.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
package golambda
import (
"encoding/json"
"errors"
"strings"
"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/aws/session"
"github.com/aws/aws-sdk-go/service/secretsmanager"
"github.com/m-mizutani/goerr"
)
// GetSecretValues bind secret data of AWS Secrets Manager to values. values should be set as pointer of struct with json meta tag.
//
// type mySecret struct {
// Token string `json:"token"`
// }
// var secret mySecret
// if err := golambda.GetSecretValues(secretARN, &secret); err != nil {
// log.Fatal("Failed: ", err)
// }
func GetSecretValues(secretArn string, values interface{}) error {
return GetSecretValuesWithFactory(secretArn, values, nil)
}
func newDefaultSecretsManager(region string) (SecretsManagerClient, error) {
ssn, err := session.NewSession(&aws.Config{
Region: aws.String(region),
})
if err != nil {
return nil, err
}
return secretsmanager.New(ssn), nil
}
// SecretsManagerClient is wrapper of secretsmanager.SecretsManager
type SecretsManagerClient interface {
GetSecretValue(*secretsmanager.GetSecretValueInput) (*secretsmanager.GetSecretValueOutput, error)
}
// SecretsManagerFactory is factory function type to replace SecretsManagerClient
type SecretsManagerFactory func(region string) (SecretsManagerClient, error)
// GetSecretValuesWithFactory can call SecretsManager.GetSecretValue with your SecretsManagerClient by factory. It uses newDefaultSecretsManager if factory is nil
func GetSecretValuesWithFactory(secretArn string, values interface{}, factory SecretsManagerFactory) error {
// sample: arn:aws:secretsmanager:ap-northeast-1:1234567890:secret:mytest
arn := strings.Split(secretArn, ":")
if len(arn) != 7 {
return goerr.New("Invalid SecretsManager ARN format").With("arn", secretArn)
}
region := arn[3]
if factory == nil {
factory = newDefaultSecretsManager
}
mgr, err := factory(region)
if err != nil {
return goerr.Wrap(err).With("region", region)
}
result, err := mgr.GetSecretValue(&secretsmanager.GetSecretValueInput{
SecretId: aws.String(secretArn),
})
if err != nil {
return goerr.Wrap(err, "Fail to retrieve secret values").With("arn", secretArn)
}
if err := json.Unmarshal([]byte(*result.SecretString), values); err != nil {
return goerr.Wrap(err, "Fail to parse secret values as JSON").
With("arn", secretArn).
With("GetSecretValue:result", result)
}
return nil
}
// SecretsManagerMock is mock of SecretsManagerClient for testing.
type SecretsManagerMock struct {
Secrets map[string]string
Region string
Input []*secretsmanager.GetSecretValueInput
}
// GetSecretValue is mock method for SecretsManagerMock. It checks if the secretId (ARN) exists in SecretsManagerMock.Secrets as key. It returns a string value if extsting or ResourceNotFoundException error if not existing.
func (x *SecretsManagerMock) GetSecretValue(input *secretsmanager.GetSecretValueInput) (*secretsmanager.GetSecretValueOutput, error) {
x.Input = append(x.Input, input)
value, ok := x.Secrets[*input.SecretId]
if !ok {
return nil, errors.New(secretsmanager.ErrCodeResourceNotFoundException)
}
return &secretsmanager.GetSecretValueOutput{
SecretString: aws.String(value),
}, nil
}
// NewSecretsManagerMock returns both of mock and factory method of the mock for testing. Developper can set secrets value as JSON to SecretsManagerMock.Secrets with key (secretes ARN). Also the mock stores Region that is extracted from secretArn and Input of secretsmanager.GetSecretValue when invoking GetSecretValuesWithFactory.
func NewSecretsManagerMock() (*SecretsManagerMock, SecretsManagerFactory) {
mock := &SecretsManagerMock{
Secrets: make(map[string]string),
}
return mock, func(region string) (SecretsManagerClient, error) {
mock.Region = region
return mock, nil
}
}