From bb46df62c6ad8a6b4452f65cf9a101fc4eab69ea Mon Sep 17 00:00:00 2001 From: Alan Sebastian Date: Thu, 21 Jun 2018 12:36:42 -0700 Subject: [PATCH] Add support for SSM Parameter Store secrets --- README.md | 2 +- pkg/secret/ssm.go | 57 +++++++++++++++++++++++++++++++++++++++++++++++ watchers/s3/s3.go | 9 ++++++-- 3 files changed, 65 insertions(+), 3 deletions(-) create mode 100644 pkg/secret/ssm.go diff --git a/README.md b/README.md index 861d481..69fbe99 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # CPS - Centralized Property Service -CPS is a centralized dynamic property service. It serves up the precomputed properties for a service as well as dynamic consul properties in the form of `conqueso.service.ips=`. +CPS is a centralized dynamic property service. It serves up the precomputed properties for a service as well as dynamic consul properties in the form of `conqueso.service.ips=`.It also supports AWS SSM Parameter Store SecureStrings. ## configuration diff --git a/pkg/secret/ssm.go b/pkg/secret/ssm.go new file mode 100644 index 0000000..f59d2d2 --- /dev/null +++ b/pkg/secret/ssm.go @@ -0,0 +1,57 @@ +package secret + +import ( + "encoding/json" + "errors" + "os" + + "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go/aws/session" + "github.com/aws/aws-sdk-go/service/ssm" + + log "github.com/sirupsen/logrus" +) + +func init() { + log.SetFormatter(&log.JSONFormatter{}) + log.SetOutput(os.Stdout) +} + +func GetSSMSecret(k string, v []byte) (string, error) { + var j map[string]interface{} + err := json.Unmarshal(v, &j) + if err != nil { + log.Errorf("Failed to unmarshall SSM object: %v", err) + return "", err + } + + var region string + if _, ok := j["$ssm"]; ok { + data := j["$ssm"].(map[string]interface{}) + region = data["region"].(string) + } else { + return "", errors.New("Object is not an SSM stanza") + } + + sess := session.Must(session.NewSessionWithOptions(session.Options{ + Config: aws.Config{ + Region: aws.String(region), + }, + })) + + svc := ssm.New(sess) + + decrypt := true + params := &ssm.GetParameterInput{ + Name: &k, + WithDecryption: &decrypt, + } + + p, err := svc.GetParameter(params) + if err != nil { + log.Errorf("Error getting SSM parameter %v: %v", k, err) + return "", err + } + + return *p.Parameter.Value, nil +} diff --git a/watchers/s3/s3.go b/watchers/s3/s3.go index 46534e1..af24191 100644 --- a/watchers/s3/s3.go +++ b/watchers/s3/s3.go @@ -162,9 +162,14 @@ func parsePropertyFile(k string, b string, svc *s3.S3) { log.Debugf("Wrote %s/%s:(%s)=%s", path, string(key), dataTypeString, string(value)) properties[string(key)] = "" case "object": - // TODO: Decrypt secret here. log.Debugf("Wrote %s/%s:(%s)=%s", path, string(key), dataTypeString, string(value)) - secret.Decrypt(value) + s, err := secret.GetSSMSecret(string(key), value) + if err != nil { + log.Error(err) + return err + } else { + properties[string(key)] = s + } default: log.Errorf("Service: %v | Key: %v | Value %v | Type: %v | Unsupported! %v:%T", k, string(key), string(value), dataTypeString, dataTypeString, dataTypeString) }