From c701ad1e2adbbe7ea39344039a494f8d63dc8a52 Mon Sep 17 00:00:00 2001 From: Graham Davison Date: Fri, 8 Dec 2023 13:46:04 -0800 Subject: [PATCH] Adds tests for STS endpoint override --- .../remote-state/s3/backend_complete_test.go | 331 ++++++++++++++++++ 1 file changed, 331 insertions(+) diff --git a/internal/backend/remote-state/s3/backend_complete_test.go b/internal/backend/remote-state/s3/backend_complete_test.go index 9f32f8d51b..3ab712201e 100644 --- a/internal/backend/remote-state/s3/backend_complete_test.go +++ b/internal/backend/remote-state/s3/backend_complete_test.go @@ -2410,3 +2410,334 @@ func configureBackend(t *testing.T, config map[string]any) (*Backend, tfdiags.Di func sharedConfigCredentialsSource(filename string) string { return fmt.Sprintf(sharedConfigCredentialsProvider+": %s", filename) } + +func TestStsEndpoint(t *testing.T) { + type settype int + const ( + setNone settype = iota + setValid + setInvalid + ) + testcases := map[string]struct { + Config map[string]any + SetServiceEndpoint settype + SetEnv string + SetInvalidEnv string + // Use string at index 1 for valid endpoint url and index 2 for invalid endpoint url + ConfigFile string + ExpectedCredentials aws.Credentials + }{ + "service config": { + Config: map[string]any{ + "access_key": servicemocks.MockStaticAccessKey, + "secret_key": servicemocks.MockStaticSecretKey, + }, + SetServiceEndpoint: setValid, + ExpectedCredentials: mockdata.MockStaticCredentials, + }, + + "service config overrides service envvar": { + Config: map[string]any{ + "access_key": servicemocks.MockStaticAccessKey, + "secret_key": servicemocks.MockStaticSecretKey, + }, + SetServiceEndpoint: setValid, + SetInvalidEnv: "AWS_ENDPOINT_URL_STS", + ExpectedCredentials: mockdata.MockStaticCredentials, + }, + + "service config overrides base envvar": { + Config: map[string]any{ + "access_key": servicemocks.MockStaticAccessKey, + "secret_key": servicemocks.MockStaticSecretKey, + }, + SetServiceEndpoint: setValid, + SetInvalidEnv: "AWS_ENDPOINT_URL", + ExpectedCredentials: mockdata.MockStaticCredentials, + }, + + "service config overrides service config_file": { + Config: map[string]any{ + "profile": "default", + }, + ConfigFile: ` +[default] +aws_access_key_id = DefaultSharedCredentialsAccessKey +aws_secret_access_key = DefaultSharedCredentialsSecretKey +services = sts-test + +[services sts-test] +sts = + endpoint_url = %[2]s +`, + SetServiceEndpoint: setValid, + ExpectedCredentials: aws.Credentials{ + AccessKeyID: "DefaultSharedCredentialsAccessKey", + SecretAccessKey: "DefaultSharedCredentialsSecretKey", + Source: sharedConfigCredentialsProvider, + }, + }, + + "service config overrides base config_file": { + Config: map[string]any{ + "profile": "default", + }, + ConfigFile: ` +[default] +aws_access_key_id = DefaultSharedCredentialsAccessKey +aws_secret_access_key = DefaultSharedCredentialsSecretKey +endpoint_url = %[2]s +`, + SetServiceEndpoint: setValid, + ExpectedCredentials: aws.Credentials{ + AccessKeyID: "DefaultSharedCredentialsAccessKey", + SecretAccessKey: "DefaultSharedCredentialsSecretKey", + Source: sharedConfigCredentialsProvider, + }, + }, + + "service envvar": { + Config: map[string]any{ + "access_key": servicemocks.MockStaticAccessKey, + "secret_key": servicemocks.MockStaticSecretKey, + }, + SetEnv: "AWS_ENDPOINT_URL_STS", + ExpectedCredentials: mockdata.MockStaticCredentials, + }, + + "base envvar": { + Config: map[string]any{ + "access_key": servicemocks.MockStaticAccessKey, + "secret_key": servicemocks.MockStaticSecretKey, + }, + SetEnv: "AWS_ENDPOINT_URL", + ExpectedCredentials: mockdata.MockStaticCredentials, + }, + + "service envvar overrides base envvar": { + Config: map[string]any{ + "access_key": servicemocks.MockStaticAccessKey, + "secret_key": servicemocks.MockStaticSecretKey, + }, + SetEnv: "AWS_ENDPOINT_URL_STS", + SetInvalidEnv: "AWS_ENDPOINT_URL", + ExpectedCredentials: mockdata.MockStaticCredentials, + }, + + "service config_file": { + Config: map[string]any{ + "profile": "default", + }, + ConfigFile: ` +[default] +aws_access_key_id = DefaultSharedCredentialsAccessKey +aws_secret_access_key = DefaultSharedCredentialsSecretKey +services = sts-test + +[services sts-test] +sts = + endpoint_url = %[1]s +`, + ExpectedCredentials: aws.Credentials{ + AccessKeyID: "DefaultSharedCredentialsAccessKey", + SecretAccessKey: "DefaultSharedCredentialsSecretKey", + Source: sharedConfigCredentialsProvider, + }, + }, + + "service config_file overrides base config_file": { + Config: map[string]any{ + "profile": "default", + }, + ConfigFile: ` +[default] +aws_access_key_id = DefaultSharedCredentialsAccessKey +aws_secret_access_key = DefaultSharedCredentialsSecretKey +services = sts-test +endpoint_url = %[2]s + +[services sts-test] +sts = + endpoint_url = %[1]s +`, + ExpectedCredentials: aws.Credentials{ + AccessKeyID: "DefaultSharedCredentialsAccessKey", + SecretAccessKey: "DefaultSharedCredentialsSecretKey", + Source: sharedConfigCredentialsProvider, + }, + }, + + "service envvar overrides service config_file": { + Config: map[string]any{ + "profile": "default", + }, + SetEnv: "AWS_ENDPOINT_URL_STS", + ConfigFile: ` +[default] +aws_access_key_id = DefaultSharedCredentialsAccessKey +aws_secret_access_key = DefaultSharedCredentialsSecretKey +services = sts-test + +[services sts-test] +sts = + endpoint_url = %[2]s +`, + ExpectedCredentials: aws.Credentials{ + AccessKeyID: "DefaultSharedCredentialsAccessKey", + SecretAccessKey: "DefaultSharedCredentialsSecretKey", + Source: sharedConfigCredentialsProvider, + }, + }, + + "base envvar overrides service config_file": { + Config: map[string]any{ + "profile": "default", + }, + SetEnv: "AWS_ENDPOINT_URL", + ConfigFile: ` +[default] +aws_access_key_id = DefaultSharedCredentialsAccessKey +aws_secret_access_key = DefaultSharedCredentialsSecretKey +services = sts-test + +[services sts-test] +sts = + endpoint_url = %[2]s +`, + ExpectedCredentials: aws.Credentials{ + AccessKeyID: "DefaultSharedCredentialsAccessKey", + SecretAccessKey: "DefaultSharedCredentialsSecretKey", + Source: sharedConfigCredentialsProvider, + }, + }, + + "base config_file": { + Config: map[string]any{ + "profile": "default", + }, + ConfigFile: ` +[default] +aws_access_key_id = DefaultSharedCredentialsAccessKey +aws_secret_access_key = DefaultSharedCredentialsSecretKey +endpoint_url = %[1]s +`, + ExpectedCredentials: aws.Credentials{ + AccessKeyID: "DefaultSharedCredentialsAccessKey", + SecretAccessKey: "DefaultSharedCredentialsSecretKey", + Source: sharedConfigCredentialsProvider, + }, + }, + + "base envvar overrides base config_file": { + Config: map[string]any{ + "profile": "default", + }, + SetEnv: "AWS_ENDPOINT_URL", + ConfigFile: ` +[default] +aws_access_key_id = DefaultSharedCredentialsAccessKey +aws_secret_access_key = DefaultSharedCredentialsSecretKey +endpoint_url = %[2]s +`, + ExpectedCredentials: aws.Credentials{ + AccessKeyID: "DefaultSharedCredentialsAccessKey", + SecretAccessKey: "DefaultSharedCredentialsSecretKey", + Source: sharedConfigCredentialsProvider, + }, + }, + + "service envvar overrides base config_file": { + Config: map[string]any{ + "profile": "default", + }, + SetEnv: "AWS_ENDPOINT_URL_STS", + ConfigFile: ` +[default] +aws_access_key_id = DefaultSharedCredentialsAccessKey +aws_secret_access_key = DefaultSharedCredentialsSecretKey +endpoint_url = %[2]s +`, + ExpectedCredentials: aws.Credentials{ + AccessKeyID: "DefaultSharedCredentialsAccessKey", + SecretAccessKey: "DefaultSharedCredentialsSecretKey", + Source: sharedConfigCredentialsProvider, + }, + }, + } + + for name, testcase := range testcases { + testcase := testcase + + t.Run(name, func(t *testing.T) { + servicemocks.InitSessionTestEnv(t) + + // Populate required fields + testcase.Config["bucket"] = "bucket" + testcase.Config["key"] = "key" + testcase.Config["region"] = "us-west-2" + + ts := servicemocks.MockAwsApiServer("STS", []*servicemocks.MockEndpoint{ + servicemocks.MockStsGetCallerIdentityValidEndpoint, + }) + defer ts.Close() + stsEndpoint := ts.URL + + invalidTS := servicemocks.MockAwsApiServer("STS", []*servicemocks.MockEndpoint{ + servicemocks.MockStsGetCallerIdentityInvalidEndpointAccessDenied, + }) + defer invalidTS.Close() + stsInvalidEndpoint := invalidTS.URL + + if testcase.SetServiceEndpoint == setValid { + testcase.Config["endpoints"] = map[string]any{ + "sts": stsEndpoint, + } + } + if testcase.SetEnv != "" { + t.Setenv(testcase.SetEnv, stsEndpoint) + } + if testcase.SetInvalidEnv != "" { + t.Setenv(testcase.SetInvalidEnv, stsInvalidEndpoint) + } + if testcase.ConfigFile != "" { + tempDir := t.TempDir() + filename := writeSharedConfigFile(t, testcase.Config, tempDir, fmt.Sprintf(testcase.ConfigFile, stsEndpoint, stsInvalidEndpoint)) + testcase.ExpectedCredentials.Source = sharedConfigCredentialsSource(filename) + } + + b, diags := configureBackend(t, testcase.Config) + if diags.HasErrors() { + t.Fatalf("configuring backend: %s", diagnosticsString(diags)) + } + + ctx := context.TODO() + + credentialsValue, err := b.awsConfig.Credentials.Retrieve(ctx) + if err != nil { + t.Fatalf("unexpected credentials Retrieve() error: %s", err) + } + + if diff := cmp.Diff(credentialsValue, testcase.ExpectedCredentials, cmpopts.IgnoreFields(aws.Credentials{}, "Expires")); diff != "" { + t.Fatalf("unexpected credentials: (- got, + expected)\n%s", diff) + } + }) + } +} + +func writeSharedConfigFile(t *testing.T, config map[string]any, tempDir, content string) string { + t.Helper() + + file, err := os.Create(filepath.Join(tempDir, "aws-sdk-go-base-shared-configuration-file")) + if err != nil { + t.Fatalf("creating shared configuration file: %s", err) + } + + _, err = file.WriteString(content) + if err != nil { + t.Fatalf(" writing shared configuration file: %s", err) + } + + config["shared_config_files"] = []any{file.Name()} + + return file.Name() +}