mirror of https://github.com/hashicorp/packer
parent
e3635566eb
commit
55fa3e1b0b
@ -0,0 +1,97 @@
|
||||
// Package secretsmanager provide methods to get data from
|
||||
// AWS Secret Manager
|
||||
package secretsmanager
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
|
||||
"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/aws/aws-sdk-go/service/secretsmanager/secretsmanageriface"
|
||||
)
|
||||
|
||||
// SecretsManager returns a representation of the Secrets Manager API
|
||||
func (c *Client) SecretsManager() secretsmanageriface.SecretsManagerAPI {
|
||||
return c.api
|
||||
}
|
||||
|
||||
// New creates an AWS Session Manager Client
|
||||
func New(config *AWSConfig) *Client {
|
||||
c := &Client{
|
||||
config: config,
|
||||
}
|
||||
|
||||
s := c.newSession(config)
|
||||
c.api = secretsmanager.New(s)
|
||||
return c
|
||||
}
|
||||
|
||||
func (c *Client) newSession(config *AWSConfig) *session.Session {
|
||||
// Initialize config with error verbosity
|
||||
sess := aws.NewConfig().WithCredentialsChainVerboseErrors(true)
|
||||
|
||||
if config.Region != "" {
|
||||
sess = sess.WithRegion(config.Region)
|
||||
}
|
||||
|
||||
opts := session.Options{
|
||||
Config: *sess,
|
||||
}
|
||||
|
||||
return session.Must(session.NewSessionWithOptions(opts))
|
||||
}
|
||||
|
||||
// GetSecret return an AWS Secret Manager secret
|
||||
// in plain text from a given secret name
|
||||
func (c *Client) GetSecret(spec *SecretSpec) (string, error) {
|
||||
params := &secretsmanager.GetSecretValueInput{
|
||||
SecretId: aws.String(spec.Name),
|
||||
VersionStage: aws.String("AWSCURRENT"),
|
||||
}
|
||||
|
||||
resp, err := c.api.GetSecretValue(params)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
if resp.SecretString == nil {
|
||||
return "", errors.New("Secret is not string")
|
||||
}
|
||||
|
||||
secret := SecretString{
|
||||
Name: *resp.Name,
|
||||
SecretString: *resp.SecretString,
|
||||
}
|
||||
value, err := getSecretValue(&secret, spec)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
return value, nil
|
||||
}
|
||||
|
||||
func getSecretValue(s *SecretString, spec *SecretSpec) (string, error) {
|
||||
var secretValue map[string]string
|
||||
|
||||
blob := []byte(s.SecretString)
|
||||
|
||||
err := json.Unmarshal(blob, &secretValue)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
// If key is not set then return first value stored in secret
|
||||
if spec.Key == "" {
|
||||
for _, v := range secretValue {
|
||||
return v, nil
|
||||
}
|
||||
}
|
||||
|
||||
if v, ok := secretValue[spec.Key]; ok {
|
||||
return v, nil
|
||||
}
|
||||
|
||||
return "", errors.New("No secret found")
|
||||
}
|
||||
@ -0,0 +1,121 @@
|
||||
package secretsmanager
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/aws/aws-sdk-go/aws"
|
||||
"github.com/aws/aws-sdk-go/service/secretsmanager"
|
||||
"github.com/aws/aws-sdk-go/service/secretsmanager/secretsmanageriface"
|
||||
)
|
||||
|
||||
type mockedSecret struct {
|
||||
secretsmanageriface.SecretsManagerAPI
|
||||
Resp secretsmanager.GetSecretValueOutput
|
||||
}
|
||||
|
||||
// GetSecret return mocked secret value
|
||||
func (m mockedSecret) GetSecretValue(in *secretsmanager.GetSecretValueInput) (*secretsmanager.GetSecretValueOutput, error) {
|
||||
return &m.Resp, nil
|
||||
}
|
||||
|
||||
func TestGetSecret(t *testing.T) {
|
||||
testCases := []struct {
|
||||
arg *SecretSpec
|
||||
mock secretsmanager.GetSecretValueOutput
|
||||
want string
|
||||
ok bool
|
||||
}{
|
||||
{
|
||||
arg: &SecretSpec{Name: "test/secret"},
|
||||
mock: secretsmanager.GetSecretValueOutput{
|
||||
Name: aws.String("test/secret"),
|
||||
SecretString: aws.String(`{"key": "test"}`),
|
||||
},
|
||||
want: "test",
|
||||
ok: true,
|
||||
},
|
||||
{
|
||||
arg: &SecretSpec{
|
||||
Name: "test/secret",
|
||||
Key: "key",
|
||||
},
|
||||
mock: secretsmanager.GetSecretValueOutput{
|
||||
Name: aws.String("test/secret"),
|
||||
SecretString: aws.String(`{"key": "test"}`),
|
||||
},
|
||||
want: "test",
|
||||
ok: true,
|
||||
},
|
||||
{
|
||||
arg: &SecretSpec{
|
||||
Name: "test/secret",
|
||||
Key: "second_key",
|
||||
},
|
||||
mock: secretsmanager.GetSecretValueOutput{
|
||||
Name: aws.String("test/secret"),
|
||||
SecretString: aws.String(`{"first_key": "first_val", "second_key": "second_val"}`),
|
||||
},
|
||||
want: "second_val",
|
||||
ok: true,
|
||||
},
|
||||
{
|
||||
arg: &SecretSpec{
|
||||
Name: "test/secret",
|
||||
},
|
||||
mock: secretsmanager.GetSecretValueOutput{
|
||||
Name: aws.String("test/secret"),
|
||||
SecretString: aws.String(`{"first_key": "first_val", "second_key": "second_val"}`),
|
||||
},
|
||||
want: "first_val",
|
||||
ok: true,
|
||||
},
|
||||
{
|
||||
arg: &SecretSpec{
|
||||
Name: "test/secret",
|
||||
Key: "nonexistent",
|
||||
},
|
||||
mock: secretsmanager.GetSecretValueOutput{
|
||||
Name: aws.String("test/secret"),
|
||||
SecretString: aws.String(`{"key": "test"}`),
|
||||
},
|
||||
ok: false,
|
||||
},
|
||||
{
|
||||
arg: &SecretSpec{
|
||||
Name: "test/secret",
|
||||
Key: "nonexistent",
|
||||
},
|
||||
mock: secretsmanager.GetSecretValueOutput{
|
||||
Name: aws.String("test/secret"),
|
||||
SecretString: aws.String(`{"first_key": "first_val", "second_key": "second_val"}`),
|
||||
},
|
||||
ok: false,
|
||||
},
|
||||
{
|
||||
arg: &SecretSpec{
|
||||
Name: "test/secret",
|
||||
Key: "nonexistent",
|
||||
},
|
||||
mock: secretsmanager.GetSecretValueOutput{},
|
||||
ok: false,
|
||||
},
|
||||
}
|
||||
|
||||
for _, test := range testCases {
|
||||
c := &Client{
|
||||
api: mockedSecret{Resp: test.mock},
|
||||
}
|
||||
got, err := c.GetSecret(test.arg)
|
||||
if test.ok {
|
||||
if got != test.want {
|
||||
t.Fatalf("want %v, got %v, error %v, using arg %v", test.want, got, err, test.arg)
|
||||
}
|
||||
}
|
||||
if !test.ok {
|
||||
if err == nil {
|
||||
t.Fatalf("error expected but got %q, using arg %v", err, test.arg)
|
||||
}
|
||||
}
|
||||
t.Logf("arg (%v), want %v, got %v, err %v", test.arg, test.want, got, err)
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,36 @@
|
||||
package secretsmanager
|
||||
|
||||
import (
|
||||
"github.com/aws/aws-sdk-go/service/secretsmanager/secretsmanageriface"
|
||||
)
|
||||
|
||||
// AWSConfig store configuration used to initialize
|
||||
// secrets manager client.
|
||||
type AWSConfig struct {
|
||||
Region string
|
||||
}
|
||||
|
||||
// SecretSpec represent specs of secret to be searched
|
||||
// If Key field is not set then package will return first
|
||||
// secret key stored in secret name.
|
||||
//
|
||||
// maps to ClusterConfig
|
||||
type SecretSpec struct {
|
||||
Name string
|
||||
Key string
|
||||
}
|
||||
|
||||
// Client represents an AWS Secrets Manager client
|
||||
//
|
||||
// maps to ProviderServices
|
||||
type Client struct {
|
||||
config *AWSConfig
|
||||
api secretsmanageriface.SecretsManagerAPI
|
||||
}
|
||||
|
||||
// SecretString is a concret representation
|
||||
// of an AWS Secrets Manager Secret String
|
||||
type SecretString struct {
|
||||
Name string
|
||||
SecretString string
|
||||
}
|
||||
Loading…
Reference in new issue