diff --git a/Gopkg.lock b/Gopkg.lock index d71b23e..555f4b6 100644 --- a/Gopkg.lock +++ b/Gopkg.lock @@ -2,7 +2,7 @@ [[projects]] - digest = "1:3e74efd4e7284a53477ce4bd34eb7453fe6d8719050cc6e9f62aff5d50b7aee7" + digest = "1:be208c551e1739aa79df6f81cf3fd8855e4ab8ef8a8b98037005852b3d2d4543" name = "github.com/aws/aws-sdk-go-v2" packages = [ "aws", @@ -26,6 +26,7 @@ "private/protocol/rest", "private/protocol/xml/xmlutil", "service/kms", + "service/ssm", "service/sts", ] pruneopts = "UT" @@ -45,6 +46,7 @@ input-imports = [ "github.com/aws/aws-sdk-go-v2/aws/external", "github.com/aws/aws-sdk-go-v2/service/kms", + "github.com/aws/aws-sdk-go-v2/service/ssm", ] solver-name = "gps-cdcl" solver-version = 1 diff --git a/Makefile b/Makefile index b66d7e7..3c958d5 100644 --- a/Makefile +++ b/Makefile @@ -8,10 +8,10 @@ clean: rm ./secure-exec || true test: - go test -v -tags awskms ./... -coverprofile=coverage.txt -covermode=atomic + go test -v -tags "awskms awsssm" ./... -coverprofile=coverage.txt -covermode=atomic build: - GOOS=linux GOARCH=amd64 go build -i -tags awskms -o secure-exec + GOOS=linux GOARCH=amd64 go build -i -tags 'awskms awsssm' -o secure-exec docker: docker build -t secure-exec-example . diff --git a/main.go b/main.go index 5a3c43c..66ad69f 100644 --- a/main.go +++ b/main.go @@ -4,6 +4,7 @@ import ( "fmt" "github.com/s12v/secure-exec/provider" _ "github.com/s12v/secure-exec/provider/awskms" + _ "github.com/s12v/secure-exec/provider/awsssm" "os" "syscall" ) diff --git a/provider/awsssm/awsssm.go b/provider/awsssm/awsssm.go new file mode 100644 index 0000000..f15eb2d --- /dev/null +++ b/provider/awsssm/awsssm.go @@ -0,0 +1,57 @@ +// +build awsssm + +package awskms + +import ( + "errors" + "fmt" + "github.com/aws/aws-sdk-go-v2/aws/external" + "github.com/aws/aws-sdk-go-v2/service/ssm" + "github.com/s12v/secure-exec/provider" + "strings" +) + +type SsmProvider struct { + awsSSmClient *ssm.SSM +} + +const prefix = "{aws-ssm}" + +var fetch func (awsSsmClient *ssm.SSM, input *ssm.GetParameterInput) (*ssm.GetParameterOutput, error) + +func init() { + cfg, err := external.LoadDefaultAWSConfig() + if err != nil { + panic("unable to load AWS-SDK config, " + err.Error()) + } + + fetch = awsFetch + provider.Register(&SsmProvider{ssm.New(cfg)}) +} + +func awsFetch(awsSsmClient *ssm.SSM, input *ssm.GetParameterInput) (*ssm.GetParameterOutput, error) { + if resp, err := awsSsmClient.GetParameterRequest(input).Send(); err != nil { + return nil, errors.New(fmt.Sprintf("SSM error: %v", err)) + } else { + return resp, nil + } +} + +func (p *SsmProvider) Match(val string) bool { + return strings.HasPrefix(val, prefix) && len(val) > len(prefix) +} + +func (p *SsmProvider) Decode(val string) (string, error) { + name := val[len(prefix):] + var withEncryption = true + input := &ssm.GetParameterInput{Name: &name, WithDecryption: &withEncryption} + if err := input.Validate(); err != nil { + return "", err + } + + if output, err := fetch(p.awsSSmClient, input); err != nil { + return "", err + } else { + return *output.Parameter.Value, nil + } +} diff --git a/provider/awsssm/awsssm_test.go b/provider/awsssm/awsssm_test.go new file mode 100644 index 0000000..3f6e7b6 --- /dev/null +++ b/provider/awsssm/awsssm_test.go @@ -0,0 +1,48 @@ +// +build awsssm + +package awskms + +import ( + "github.com/aws/aws-sdk-go-v2/service/ssm" + "testing" +) + +func TestSsmProvider_Match(t *testing.T) { + kmsProvider := SsmProvider{} + + if kmsProvider.Match("{aws-ssm}something") != true { + t.Fatal("expected to match") + } + + if kmsProvider.Match("https://example.com") != false { + t.Fatal("not expected to match") + } +} + +func TestSsmProvider_Decode(t *testing.T) { + ssmProvider := SsmProvider{} + + value := "boom" + fetch = func(awsSsmClient *ssm.SSM, input *ssm.GetParameterInput) (*ssm.GetParameterOutput, error) { + if *input.Name != "/foo/bar" { + t.Fatalf("unexpected name %v", input.Name) + } + + return &ssm.GetParameterOutput{Parameter: &ssm.Parameter{Value: &value}}, nil + } + + if r, _ := ssmProvider.Decode("{aws-ssm}/foo/bar"); r != "boom" { + t.Fatalf("unexpected plaintext %v", r) + } +} + +func TestSsmProvider_DecodeInvalidInput(t *testing.T) { + ssmProvider := SsmProvider{} + r, err := ssmProvider.Decode("{aws-ssm}") + if err == nil { + t.Fatal("expected an error", r) + } + if r != "" { + t.Fatalf("unexpected result: '%v'", r) + } +} diff --git a/provider/awsssm/noop.go b/provider/awsssm/noop.go new file mode 100644 index 0000000..0629e46 --- /dev/null +++ b/provider/awsssm/noop.go @@ -0,0 +1,6 @@ +// +build !awsssm + +package awskms + +func init() { +}