// Copyright 2015-2019 Amazon.com, Inc. or its affiliates. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"). You may // not use this file except in compliance with the License. A copy of the // License is located at // // http://aws.amazon.com/apache2.0/ // // or in the "license" file accompanying this file. This file is distributed // on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either // express or implied. See the License for the specific language governing // permissions and limitations under the License. package clients import ( "testing" mock_ssmiface "github.com/aws/amazon-ecs-cli/ecs-cli/modules/clients/aws/amimetadata/mock/sdk" mock_secretsmanageriface "github.com/aws/amazon-ecs-cli/ecs-cli/modules/clients/aws/secretsmanager/mock/sdk" "github.com/aws/aws-sdk-go/aws" "github.com/aws/aws-sdk-go/service/secretsmanager" "github.com/aws/aws-sdk-go/service/secretsmanager/secretsmanageriface" "github.com/aws/aws-sdk-go/service/ssm" "github.com/aws/aws-sdk-go/service/ssm/ssmiface" "github.com/golang/mock/gomock" "github.com/stretchr/testify/require" ) func TestSSMDecrypter_DecryptSecret(t *testing.T) { testCases := map[string]struct { input string wantedSecret string setupDecrypter func(ctrl *gomock.Controller) *SSMDecrypter }{ "with ARN in default region": { input: "arn:aws:ssm:us-east-1:11111111111:parameter/TEST_DB_PASSWORD", wantedSecret: "1234", setupDecrypter: func(ctrl *gomock.Controller) *SSMDecrypter { defaultClient := mock_ssmiface.NewMockSSMAPI(ctrl) m := make(map[region]ssmiface.SSMAPI) m["default"] = defaultClient m["us-east-1"] = defaultClient gomock.InOrder( defaultClient.EXPECT().GetParameter(&ssm.GetParameterInput{ Name: aws.String("/TEST_DB_PASSWORD"), WithDecryption: aws.Bool(true), }).Return(&ssm.GetParameterOutput{ Parameter: &ssm.Parameter{ Value: aws.String("1234"), }, }, nil), ) return &SSMDecrypter{ SSMAPI: defaultClient, clients: m, } }, }, "with ARN in different region": { input: "arn:aws:ssm:us-west-2:11111111111:parameter/TEST_DB_PASSWORD", wantedSecret: "what??", setupDecrypter: func(ctrl *gomock.Controller) *SSMDecrypter { iadClient := mock_ssmiface.NewMockSSMAPI(ctrl) pdxClient := mock_ssmiface.NewMockSSMAPI(ctrl) m := make(map[region]ssmiface.SSMAPI) m["default"] = iadClient m["us-east-1"] = iadClient m["us-west-2"] = pdxClient gomock.InOrder( pdxClient.EXPECT().GetParameter(&ssm.GetParameterInput{ Name: aws.String("/TEST_DB_PASSWORD"), WithDecryption: aws.Bool(true), }).Return(&ssm.GetParameterOutput{ Parameter: &ssm.Parameter{ Value: aws.String("what??"), }, }, nil), iadClient.EXPECT().GetParameter(gomock.Any()).Times(0), // Should not have called IAD ) return &SSMDecrypter{ SSMAPI: iadClient, clients: m, } }, }, "with ARN and forward slashes": { input: "arn:aws:ssm:us-west-2:11111111111:parameter/TEST/DB/PASSWORD", wantedSecret: "ponies", setupDecrypter: func(ctrl *gomock.Controller) *SSMDecrypter { iadClient := mock_ssmiface.NewMockSSMAPI(ctrl) pdxClient := mock_ssmiface.NewMockSSMAPI(ctrl) m := make(map[region]ssmiface.SSMAPI) m["default"] = iadClient m["us-east-1"] = iadClient m["us-west-2"] = pdxClient gomock.InOrder( pdxClient.EXPECT().GetParameter(&ssm.GetParameterInput{ Name: aws.String("/TEST/DB/PASSWORD"), WithDecryption: aws.Bool(true), }).Return(&ssm.GetParameterOutput{ Parameter: &ssm.Parameter{ Value: aws.String("ponies"), }, }, nil), iadClient.EXPECT().GetParameter(gomock.Any()).Times(0), // Should not have called IAD ) return &SSMDecrypter{ SSMAPI: iadClient, clients: m, } }, }, "without ARN": { input: "TEST_DB_PASSWORD", wantedSecret: "hello", setupDecrypter: func(ctrl *gomock.Controller) *SSMDecrypter { iadClient := mock_ssmiface.NewMockSSMAPI(ctrl) pdxClient := mock_ssmiface.NewMockSSMAPI(ctrl) m := make(map[region]ssmiface.SSMAPI) m["default"] = iadClient m["us-east-1"] = iadClient m["us-west-2"] = pdxClient gomock.InOrder( iadClient.EXPECT().GetParameter(&ssm.GetParameterInput{ Name: aws.String("TEST_DB_PASSWORD"), WithDecryption: aws.Bool(true), }).Return(&ssm.GetParameterOutput{ Parameter: &ssm.Parameter{ Value: aws.String("hello"), }, }, nil), pdxClient.EXPECT().GetParameter(gomock.Any()).Times(0), // Should not have called PDX ) return &SSMDecrypter{ SSMAPI: iadClient, clients: m, } }, }, "with forward slash": { input: "/TEST/DB/PASSWORD", wantedSecret: "hello", setupDecrypter: func(ctrl *gomock.Controller) *SSMDecrypter { iadClient := mock_ssmiface.NewMockSSMAPI(ctrl) pdxClient := mock_ssmiface.NewMockSSMAPI(ctrl) m := make(map[region]ssmiface.SSMAPI) m["default"] = iadClient m["us-east-1"] = iadClient m["us-west-2"] = pdxClient gomock.InOrder( iadClient.EXPECT().GetParameter(&ssm.GetParameterInput{ Name: aws.String("/TEST/DB/PASSWORD"), WithDecryption: aws.Bool(true), }).Return(&ssm.GetParameterOutput{ Parameter: &ssm.Parameter{ Value: aws.String("hello"), }, }, nil), pdxClient.EXPECT().GetParameter(gomock.Any()).Times(0), // Should not have called PDX ) return &SSMDecrypter{ SSMAPI: iadClient, clients: m, } }, }, } for name, tc := range testCases { t.Run(name, func(t *testing.T) { // Given ctrl := gomock.NewController(t) defer ctrl.Finish() decrypter := tc.setupDecrypter(ctrl) // When got, err := decrypter.DecryptSecret(tc.input) // Then require.Equal(t, tc.wantedSecret, got) require.NoError(t, err) require.Equal(t, decrypter.clients["default"], decrypter.SSMAPI, "Expected DecryptSecret() to reset the client after each call") }) } } func TestSecretsManagerDecrypter_DecryptSecret(t *testing.T) { testCases := map[string]struct { input string wantedSecret string setupDecrypter func(ctrl *gomock.Controller) *SecretsManagerDecrypter }{ "with ARN in IAD": { input: "arn:aws:secretsmanager:us-east-1:11111111111:secret:alpha/efe/local-j0gCbT", wantedSecret: "verysafe", setupDecrypter: func(ctrl *gomock.Controller) *SecretsManagerDecrypter { iadClient := mock_secretsmanageriface.NewMockSecretsManagerAPI(ctrl) pdxClient := mock_secretsmanageriface.NewMockSecretsManagerAPI(ctrl) m := make(map[region]secretsmanageriface.SecretsManagerAPI) m["default"] = iadClient m["us-east-1"] = iadClient m["us-west-2"] = pdxClient gomock.InOrder( iadClient.EXPECT().GetSecretValue(&secretsmanager.GetSecretValueInput{ SecretId: aws.String("arn:aws:secretsmanager:us-east-1:11111111111:secret:alpha/efe/local-j0gCbT"), }).Return(&secretsmanager.GetSecretValueOutput{ SecretString: aws.String("verysafe"), }, nil), pdxClient.EXPECT().GetSecretValue(gomock.Any()).Times(0), ) return &SecretsManagerDecrypter{ SecretsManagerAPI: iadClient, clients: m, } }, }, "with ARN in PDX": { input: "arn:aws:secretsmanager:us-west-2:11111111111:secret:alpha/efe/local-j0gCbT", wantedSecret: "veryverysafe", setupDecrypter: func(ctrl *gomock.Controller) *SecretsManagerDecrypter { iadClient := mock_secretsmanageriface.NewMockSecretsManagerAPI(ctrl) pdxClient := mock_secretsmanageriface.NewMockSecretsManagerAPI(ctrl) m := make(map[region]secretsmanageriface.SecretsManagerAPI) m["default"] = iadClient m["us-east-1"] = iadClient m["us-west-2"] = pdxClient gomock.InOrder( pdxClient.EXPECT().GetSecretValue(&secretsmanager.GetSecretValueInput{ SecretId: aws.String("arn:aws:secretsmanager:us-west-2:11111111111:secret:alpha/efe/local-j0gCbT"), }).Return(&secretsmanager.GetSecretValueOutput{ SecretString: aws.String("veryverysafe"), }, nil), iadClient.EXPECT().GetSecretValue(gomock.Any()).Times(0), // Should not have called IAD ) return &SecretsManagerDecrypter{ SecretsManagerAPI: iadClient, clients: m, } }, }, } for name, tc := range testCases { t.Run(name, func(t *testing.T) { // Given ctrl := gomock.NewController(t) defer ctrl.Finish() decrypter := tc.setupDecrypter(ctrl) // When got, err := decrypter.DecryptSecret(tc.input) // Then require.Equal(t, tc.wantedSecret, got) require.NoError(t, err) }) } }