2020-05-15 07:50:33 -04:00
|
|
|
// Package secretsmanager provide methods to get data from
|
|
|
|
// AWS Secret Manager
|
|
|
|
package secretsmanager
|
|
|
|
|
|
|
|
import (
|
|
|
|
"encoding/json"
|
|
|
|
"errors"
|
2020-08-18 10:51:48 -04:00
|
|
|
"fmt"
|
2020-05-15 07:50:33 -04:00
|
|
|
|
|
|
|
"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"
|
|
|
|
)
|
|
|
|
|
2020-05-18 06:44:24 -04:00
|
|
|
// Client represents an AWS Secrets Manager client
|
|
|
|
type Client struct {
|
|
|
|
config *AWSConfig
|
|
|
|
api secretsmanageriface.SecretsManagerAPI
|
2020-05-15 07:50:33 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
// 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
|
2020-08-18 10:51:48 -04:00
|
|
|
sessConfig := aws.NewConfig().WithCredentialsChainVerboseErrors(true)
|
2020-05-15 07:50:33 -04:00
|
|
|
|
|
|
|
if config.Region != "" {
|
2020-08-18 10:51:48 -04:00
|
|
|
sessConfig = sessConfig.WithRegion(config.Region)
|
2020-05-15 07:50:33 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
opts := session.Options{
|
2020-08-18 10:51:48 -04:00
|
|
|
SharedConfigState: session.SharedConfigEnable,
|
|
|
|
Config: *sessConfig,
|
2020-05-15 07:50:33 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
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)
|
|
|
|
|
2020-08-17 07:41:21 -04:00
|
|
|
//For those plaintext secrets just return the value
|
|
|
|
if json.Valid(blob) != true {
|
|
|
|
return s.SecretString, nil
|
|
|
|
}
|
|
|
|
|
2020-05-15 07:50:33 -04:00
|
|
|
err := json.Unmarshal(blob, &secretValue)
|
|
|
|
if err != nil {
|
|
|
|
return "", err
|
|
|
|
}
|
|
|
|
|
2020-05-23 09:02:16 -04:00
|
|
|
// If key is not set and secret has multiple keys, return error
|
|
|
|
if spec.Key == "" && len(secretValue) > 1 {
|
|
|
|
return "", errors.New("Secret has multiple values and no key was set")
|
|
|
|
}
|
|
|
|
|
2020-05-15 07:50:33 -04:00
|
|
|
if spec.Key == "" {
|
|
|
|
for _, v := range secretValue {
|
|
|
|
return v, nil
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if v, ok := secretValue[spec.Key]; ok {
|
|
|
|
return v, nil
|
|
|
|
}
|
|
|
|
|
2020-08-18 10:51:48 -04:00
|
|
|
return "", fmt.Errorf("No secret found for key %q", spec.Key)
|
2020-05-15 07:50:33 -04:00
|
|
|
}
|