From 106d9c0b5423748e7d8bedd9e8e1ba4e15423fc0 Mon Sep 17 00:00:00 2001 From: Graham Davison Date: Tue, 22 Aug 2023 14:40:33 -0700 Subject: [PATCH] Adds `endpoints.sts` and deprecates `sts_endpoint` --- internal/backend/remote-state/s3/backend.go | 43 ++++++++----------- .../remote-state/s3/backend_complete_test.go | 14 ++++-- .../docs/language/settings/backends/s3.mdx | 5 ++- 3 files changed, 34 insertions(+), 28 deletions(-) diff --git a/internal/backend/remote-state/s3/backend.go b/internal/backend/remote-state/s3/backend.go index 0e21a68f07..7dcc4b6bef 100644 --- a/internal/backend/remote-state/s3/backend.go +++ b/internal/backend/remote-state/s3/backend.go @@ -94,6 +94,11 @@ func (b *Backend) ConfigSchema() *configschema.Block { Optional: true, Description: "A custom endpoint for the S3 API", }, + "sts": { + Type: cty.String, + Optional: true, + Description: "A custom endpoint for the STS API", + }, }, }, }, @@ -107,6 +112,7 @@ func (b *Backend) ConfigSchema() *configschema.Block { Type: cty.String, Optional: true, Description: "A custom endpoint for the STS API", + Deprecated: true, }, "encrypt": { Type: cty.Bool, @@ -366,10 +372,11 @@ func (b *Backend) PrepareConfig(obj cty.Value) (cty.Value, tfdiags.Diagnostics) "dynamodb_endpoint": "dynamodb", "iam_endpoint": "iam", "endpoint": "s3", + "sts_endpoint": "sts", } endpoints := make(map[string]string) if val := obj.GetAttr("endpoints"); !val.IsNull() { - for _, k := range []string{"dynamodb", "iam", "s3"} { + for _, k := range []string{"dynamodb", "iam", "s3", "sts"} { if v := val.GetAttr(k); !v.IsNull() { endpoints[k] = v.AsString() } @@ -530,8 +537,8 @@ func (b *Backend) Configure(obj cty.Value) tfdiags.Diagnostics { SecretKey: stringAttr(obj, "secret_key"), SkipCredsValidation: boolAttr(obj, "skip_credentials_validation"), SkipMetadataApiCheck: boolAttr(obj, "skip_metadata_api_check"), - StsEndpoint: stringAttrDefaultEnvVar(obj, "sts_endpoint", "AWS_ENDPOINT_URL_STS", "AWS_STS_ENDPOINT"), - Token: stringAttr(obj, "token"), + // StsEndpoint: stringAttrDefaultEnvVar(obj, "sts_endpoint", "AWS_ENDPOINT_URL_STS", "AWS_STS_ENDPOINT"), + Token: stringAttr(obj, "token"), UserAgentProducts: []*awsbase.UserAgentProduct{ {Name: "APN", Version: "1.0"}, {Name: "HashiCorp", Version: "1.0"}, @@ -548,6 +555,15 @@ func (b *Backend) Configure(obj cty.Value) tfdiags.Diagnostics { cfg.IamEndpoint = v } + if v, ok := retrieveArgument(&diags, + newAttributeRetriever(obj, cty.GetAttrPath("endpoints").GetAttr("sts")), + newAttributeRetriever(obj, cty.GetAttrPath("sts_endpoint")), + newEnvvarRetriever("AWS_ENDPOINT_URL_STS"), + newEnvvarRetriever("AWS_STS_ENDPOINT"), + ); ok { + cfg.StsEndpoint = v + } + if assumeRole := obj.GetAttr("assume_role"); !assumeRole.IsNull() { if val, ok := stringAttrOk(assumeRole, "role_arn"); ok { cfg.AssumeRoleARN = val @@ -745,27 +761,6 @@ func stringAttrDefault(obj cty.Value, name, def string) string { } } -func stringAttrDefaultEnvVar(obj cty.Value, name string, envvars ...string) string { - if v, ok := stringAttrDefaultEnvVarOk(obj, name, envvars...); !ok { - return "" - } else { - return v - } -} - -func stringAttrDefaultEnvVarOk(obj cty.Value, name string, envvars ...string) (string, bool) { - if v, ok := stringAttrOk(obj, name); !ok { - for _, envvar := range envvars { - if v := os.Getenv(envvar); v != "" { - return v, true - } - } - return "", false - } else { - return v, true - } -} - func stringSetValueOk(val cty.Value) ([]string, bool) { var list []string typ := val.Type() diff --git a/internal/backend/remote-state/s3/backend_complete_test.go b/internal/backend/remote-state/s3/backend_complete_test.go index 2a004167b3..5905c0a2f3 100644 --- a/internal/backend/remote-state/s3/backend_complete_test.go +++ b/internal/backend/remote-state/s3/backend_complete_test.go @@ -26,6 +26,8 @@ func ExpectNoDiags(t *testing.T, diags tfdiags.Diagnostics) { } func expectDiagsCount(t *testing.T, diags tfdiags.Diagnostics, c int) { + t.Helper() + if l := len(diags); l != c { t.Fatalf("Diagnostics: expected %d element, got %d\n%s", c, l, diagnosticsString(diags)) } @@ -640,7 +642,9 @@ aws_secret_access_key = DefaultSharedCredentialsSecretKey ts := servicemocks.MockAwsApiServer("STS", tc.MockStsEndpoints) defer ts.Close() - tc.config["sts_endpoint"] = ts.URL + tc.config["endpoints"] = map[string]any{ + "sts": ts.URL, + } if tc.SharedConfigurationFile != "" { file, err := os.CreateTemp("", "aws-sdk-go-base-shared-configuration-file") @@ -1109,7 +1113,9 @@ aws_secret_access_key = DefaultSharedCredentialsSecretKey ts := servicemocks.MockAwsApiServer("STS", tc.MockStsEndpoints) defer ts.Close() - tc.config["sts_endpoint"] = ts.URL + tc.config["endpoints"] = map[string]any{ + "sts": ts.URL, + } if tc.SharedConfigurationFile != "" { file, err := os.CreateTemp("", "aws-sdk-go-base-shared-configuration-file") @@ -1544,7 +1550,9 @@ aws_secret_access_key = DefaultSharedCredentialsSecretKey ts := servicemocks.MockAwsApiServer("STS", tc.MockStsEndpoints) defer ts.Close() - tc.config["sts_endpoint"] = ts.URL + tc.config["endpoints"] = map[string]any{ + "sts": ts.URL, + } if tc.SharedConfigurationFile != "" { file, err := os.CreateTemp("", "aws-sdk-go-base-shared-configuration-file") diff --git a/website/docs/language/settings/backends/s3.mdx b/website/docs/language/settings/backends/s3.mdx index c142aea649..a1cd6b20df 100644 --- a/website/docs/language/settings/backends/s3.mdx +++ b/website/docs/language/settings/backends/s3.mdx @@ -162,7 +162,8 @@ The following configuration is optional: * `skip_credentials_validation` - (Optional) Skip credentials validation via the STS API. * `skip_region_validation` - (Optional) Skip validation of provided region name. * `skip_metadata_api_check` - (Optional) Skip usage of EC2 Metadata API. -* `sts_endpoint` - (Optional) Custom endpoint for the AWS Security Token Service (STS) API. This can also be sourced from the environment variable `AWS_ENDPOINT_URL_STS` or the deprecated environment variable `AWS_STS_ENDPOINT`. +* `sts_endpoint` - (Optional, **Deprecated**) Custom endpoint for the AWS Security Token Service (STS) API. + Use `endpoints.sts` instead. * `token` - (Optional) Multi-Factor Authentication (MFA) token. This can also be sourced from the `AWS_SESSION_TOKEN` environment variable. #### Overriding AWS API endpoints @@ -175,6 +176,8 @@ The optional argument `endpoints` contains the following arguments: This can also be sourced from the environment variable `AWS_ENDPOINT_URL_IAM` or the deprecated environment variable `AWS_IAM_ENDPOINT`. * `s3` - (Optional) Custom endpoint for the AWS S3 API. This can also be sourced from the environment variable `AWS_ENDPOINT_URL_S3` or the deprecated environment variable `AWS_S3_ENDPOINT`. +* `sts` - (Optional) Custom endpoint for the AWS STS API. + This can also be sourced from the environment variable `AWS_ENDPOINT_URL_STS` or the deprecated environment variable `AWS_STS_ENDPOINT`. #### Assume Role Configuration