github.com/opentofu/opentofu@v1.7.1/internal/backend/remote-state/s3/backend_complete_test.go (about)

     1  // Copyright (c) The OpenTofu Authors
     2  // SPDX-License-Identifier: MPL-2.0
     3  // Copyright (c) 2023 HashiCorp, Inc.
     4  // SPDX-License-Identifier: MPL-2.0
     5  
     6  package s3
     7  
     8  import (
     9  	"context"
    10  	"fmt"
    11  	"os"
    12  	"path/filepath"
    13  	"regexp"
    14  	"testing"
    15  
    16  	"github.com/aws/aws-sdk-go-v2/aws"
    17  	"github.com/google/go-cmp/cmp"
    18  	"github.com/google/go-cmp/cmp/cmpopts"
    19  	"github.com/hashicorp/aws-sdk-go-base/v2/mockdata"
    20  	"github.com/hashicorp/aws-sdk-go-base/v2/servicemocks"
    21  	"github.com/opentofu/opentofu/internal/configs/hcl2shim"
    22  	"github.com/opentofu/opentofu/internal/encryption"
    23  	"github.com/opentofu/opentofu/internal/tfdiags"
    24  )
    25  
    26  const mockStsAssumeRolePolicy = `{
    27  	"Version": "2012-10-17",
    28  	"Statement": {
    29  	  "Effect": "Allow",
    30  	  "Action": "*",
    31  	  "Resource": "*"
    32  	}
    33    }`
    34  
    35  func ExpectNoDiags(t *testing.T, diags tfdiags.Diagnostics) {
    36  	expectDiagsCount(t, diags, 0)
    37  }
    38  
    39  func expectDiagsCount(t *testing.T, diags tfdiags.Diagnostics, c int) {
    40  	if l := len(diags); l != c {
    41  		t.Fatalf("Diagnostics: expected %d element, got %d\n%#v", c, l, diags)
    42  	}
    43  }
    44  
    45  func ExpectDiagsEqual(expected tfdiags.Diagnostics) diagsValidator {
    46  	return func(t *testing.T, diags tfdiags.Diagnostics) {
    47  		if diff := cmp.Diff(diags, expected, cmp.Comparer(diagnosticComparer)); diff != "" {
    48  			t.Fatalf("unexpected diagnostics difference: %s", diff)
    49  		}
    50  	}
    51  }
    52  
    53  type diagsValidator func(*testing.T, tfdiags.Diagnostics)
    54  
    55  // ExpectDiagsMatching returns a validator expeceting a single Diagnostic with fields matching the expectation
    56  func ExpectDiagsMatching(severity tfdiags.Severity, summary matcher, detail matcher) diagsValidator {
    57  	return func(t *testing.T, diags tfdiags.Diagnostics) {
    58  		for _, d := range diags {
    59  			if !summary.Match(d.Description().Summary) || !detail.Match(d.Description().Detail) {
    60  				t.Fatalf("expected Diagnostic matching %#v, got %#v",
    61  					tfdiags.Sourceless(
    62  						severity,
    63  						summary.String(),
    64  						detail.String(),
    65  					),
    66  					d,
    67  				)
    68  			}
    69  		}
    70  
    71  		expectDiagsCount(t, diags, 1)
    72  	}
    73  }
    74  
    75  type diagValidator func(*testing.T, tfdiags.Diagnostic)
    76  
    77  func ExpectDiagMatching(severity tfdiags.Severity, summary matcher, detail matcher) diagValidator {
    78  	return func(t *testing.T, d tfdiags.Diagnostic) {
    79  		if !summary.Match(d.Description().Summary) || !detail.Match(d.Description().Detail) {
    80  			t.Fatalf("expected Diagnostic matching %#v, got %#v",
    81  				tfdiags.Sourceless(
    82  					severity,
    83  					summary.String(),
    84  					detail.String(),
    85  				),
    86  				d,
    87  			)
    88  		}
    89  	}
    90  }
    91  
    92  func ExpectMultipleDiags(validators ...diagValidator) diagsValidator {
    93  	return func(t *testing.T, diags tfdiags.Diagnostics) {
    94  		count := len(validators)
    95  		if diagCount := len(diags); diagCount < count {
    96  			count = diagCount
    97  		}
    98  
    99  		for i := 0; i < count; i++ {
   100  			validators[i](t, diags[i])
   101  		}
   102  
   103  		expectDiagsCount(t, diags, len(validators))
   104  	}
   105  }
   106  
   107  type matcher interface {
   108  	fmt.Stringer
   109  	Match(string) bool
   110  }
   111  
   112  type equalsMatcher string
   113  
   114  func (m equalsMatcher) Match(s string) bool {
   115  	return string(m) == s
   116  }
   117  
   118  func (m equalsMatcher) String() string {
   119  	return string(m)
   120  }
   121  
   122  type regexpMatcher struct {
   123  	re *regexp.Regexp
   124  }
   125  
   126  func newRegexpMatcher(re string) regexpMatcher {
   127  	return regexpMatcher{
   128  		re: regexp.MustCompile(re),
   129  	}
   130  }
   131  
   132  func (m regexpMatcher) Match(s string) bool {
   133  	return m.re.MatchString(s)
   134  }
   135  
   136  func (m regexpMatcher) String() string {
   137  	return m.re.String()
   138  }
   139  
   140  type noopMatcher struct{}
   141  
   142  func (m noopMatcher) Match(s string) bool {
   143  	return true
   144  }
   145  
   146  func (m noopMatcher) String() string {
   147  	return ""
   148  }
   149  
   150  func TestBackendConfig_Authentication(t *testing.T) {
   151  	testCases := map[string]struct {
   152  		config                     map[string]any
   153  		EnableEc2MetadataServer    bool
   154  		EnableEcsCredentialsServer bool
   155  		EnableWebIdentityEnvVars   bool
   156  		// EnableWebIdentityConfig    bool // Not supported
   157  		EnvironmentVariables     map[string]string
   158  		ExpectedCredentialsValue aws.Credentials
   159  		MockStsEndpoints         []*servicemocks.MockEndpoint
   160  		SharedConfigurationFile  string
   161  		SharedCredentialsFile    string
   162  		ValidateDiags            diagsValidator
   163  	}{
   164  		"empty config": {
   165  			config: map[string]any{},
   166  			MockStsEndpoints: []*servicemocks.MockEndpoint{
   167  				servicemocks.MockStsGetCallerIdentityValidEndpoint,
   168  			},
   169  			ValidateDiags: ExpectDiagsMatching(
   170  				tfdiags.Error,
   171  				equalsMatcher("No valid credential sources found"),
   172  				newRegexpMatcher("^Please see.+"),
   173  			),
   174  		},
   175  
   176  		"config AccessKey": {
   177  			config: map[string]any{
   178  				"access_key": servicemocks.MockStaticAccessKey,
   179  				"secret_key": servicemocks.MockStaticSecretKey,
   180  			},
   181  			MockStsEndpoints: []*servicemocks.MockEndpoint{
   182  				servicemocks.MockStsGetCallerIdentityValidEndpoint,
   183  			},
   184  			ExpectedCredentialsValue: mockdata.MockStaticCredentials,
   185  			ValidateDiags:            ExpectNoDiags,
   186  		},
   187  
   188  		"config AccessKey forbidden account": {
   189  			config: map[string]any{
   190  				"access_key":            servicemocks.MockStaticAccessKey,
   191  				"secret_key":            servicemocks.MockStaticSecretKey,
   192  				"forbidden_account_ids": []any{"222222222222"},
   193  			},
   194  			MockStsEndpoints: []*servicemocks.MockEndpoint{
   195  				servicemocks.MockStsGetCallerIdentityValidEndpoint,
   196  			},
   197  			ExpectedCredentialsValue: mockdata.MockStaticCredentials,
   198  			ValidateDiags: ExpectDiagsMatching(
   199  				tfdiags.Error,
   200  				equalsMatcher("Invalid account ID"),
   201  				equalsMatcher("AWS account ID not allowed: 222222222222"),
   202  			),
   203  		},
   204  
   205  		"config Profile shared credentials profile aws_access_key_id": {
   206  			config: map[string]any{
   207  				"profile": "SharedCredentialsProfile",
   208  			},
   209  			ExpectedCredentialsValue: aws.Credentials{
   210  				AccessKeyID:     "ProfileSharedCredentialsAccessKey",
   211  				SecretAccessKey: "ProfileSharedCredentialsSecretKey",
   212  				Source:          "SharedConfigCredentials",
   213  			},
   214  			MockStsEndpoints: []*servicemocks.MockEndpoint{
   215  				servicemocks.MockStsGetCallerIdentityValidEndpoint,
   216  			},
   217  			SharedCredentialsFile: `
   218  [default]
   219  aws_access_key_id = DefaultSharedCredentialsAccessKey
   220  aws_secret_access_key = DefaultSharedCredentialsSecretKey
   221  
   222  [SharedCredentialsProfile]
   223  aws_access_key_id = ProfileSharedCredentialsAccessKey
   224  aws_secret_access_key = ProfileSharedCredentialsSecretKey
   225  `,
   226  			ValidateDiags: ExpectNoDiags,
   227  		},
   228  
   229  		"environment AWS_ACCESS_KEY_ID overrides config Profile": { // Legacy behavior
   230  			config: map[string]any{
   231  				"profile":             "SharedCredentialsProfile",
   232  				"use_legacy_workflow": true,
   233  			},
   234  			EnvironmentVariables: map[string]string{
   235  				"AWS_ACCESS_KEY_ID":     servicemocks.MockEnvAccessKey,
   236  				"AWS_SECRET_ACCESS_KEY": servicemocks.MockEnvSecretKey,
   237  			},
   238  			ExpectedCredentialsValue: mockdata.MockEnvCredentials,
   239  			MockStsEndpoints: []*servicemocks.MockEndpoint{
   240  				servicemocks.MockStsGetCallerIdentityValidEndpoint,
   241  			},
   242  			SharedCredentialsFile: `
   243  [default]
   244  aws_access_key_id = DefaultSharedCredentialsAccessKey
   245  aws_secret_access_key = DefaultSharedCredentialsSecretKey
   246  [SharedCredentialsProfile]
   247  aws_access_key_id = ProfileSharedCredentialsAccessKey
   248  aws_secret_access_key = ProfileSharedCredentialsSecretKey
   249  `,
   250  			ValidateDiags: ExpectDiagsMatching(
   251  				tfdiags.Warning,
   252  				equalsMatcher("Deprecated Parameter"),
   253  				noopMatcher{},
   254  			),
   255  		},
   256  
   257  		"environment AWS_ACCESS_KEY_ID does not override config Profile": {
   258  			config: map[string]any{
   259  				"profile": "SharedCredentialsProfile",
   260  			},
   261  			EnvironmentVariables: map[string]string{
   262  				"AWS_ACCESS_KEY_ID":     servicemocks.MockEnvAccessKey,
   263  				"AWS_SECRET_ACCESS_KEY": servicemocks.MockEnvSecretKey,
   264  			},
   265  			ExpectedCredentialsValue: aws.Credentials{
   266  				AccessKeyID:     "ProfileSharedCredentialsAccessKey",
   267  				SecretAccessKey: "ProfileSharedCredentialsSecretKey",
   268  				Source:          "SharedConfigCredentials",
   269  			},
   270  			MockStsEndpoints: []*servicemocks.MockEndpoint{
   271  				servicemocks.MockStsGetCallerIdentityValidEndpoint,
   272  			},
   273  			SharedCredentialsFile: `
   274  [default]
   275  aws_access_key_id = DefaultSharedCredentialsAccessKey
   276  aws_secret_access_key = DefaultSharedCredentialsSecretKey
   277  [SharedCredentialsProfile]
   278  aws_access_key_id = ProfileSharedCredentialsAccessKey
   279  aws_secret_access_key = ProfileSharedCredentialsSecretKey
   280  `,
   281  			ValidateDiags: ExpectNoDiags,
   282  		},
   283  
   284  		"environment AWS_ACCESS_KEY_ID": {
   285  			config: map[string]any{},
   286  			EnvironmentVariables: map[string]string{
   287  				"AWS_ACCESS_KEY_ID":     servicemocks.MockEnvAccessKey,
   288  				"AWS_SECRET_ACCESS_KEY": servicemocks.MockEnvSecretKey,
   289  			},
   290  			ExpectedCredentialsValue: mockdata.MockEnvCredentials,
   291  			MockStsEndpoints: []*servicemocks.MockEndpoint{
   292  				servicemocks.MockStsGetCallerIdentityValidEndpoint,
   293  			},
   294  			ValidateDiags: ExpectNoDiags,
   295  		},
   296  
   297  		"environment AWS_PROFILE shared credentials profile aws_access_key_id": {
   298  			config: map[string]any{},
   299  			EnvironmentVariables: map[string]string{
   300  				"AWS_PROFILE": "SharedCredentialsProfile",
   301  			},
   302  			ExpectedCredentialsValue: aws.Credentials{
   303  				AccessKeyID:     "ProfileSharedCredentialsAccessKey",
   304  				SecretAccessKey: "ProfileSharedCredentialsSecretKey",
   305  				Source:          "SharedConfigCredentials",
   306  			},
   307  			MockStsEndpoints: []*servicemocks.MockEndpoint{
   308  				servicemocks.MockStsGetCallerIdentityValidEndpoint,
   309  			},
   310  			SharedCredentialsFile: `
   311  [default]
   312  aws_access_key_id = DefaultSharedCredentialsAccessKey
   313  aws_secret_access_key = DefaultSharedCredentialsSecretKey
   314  
   315  [SharedCredentialsProfile]
   316  aws_access_key_id = ProfileSharedCredentialsAccessKey
   317  aws_secret_access_key = ProfileSharedCredentialsSecretKey
   318  `,
   319  			ValidateDiags: ExpectNoDiags,
   320  		},
   321  
   322  		"environment AWS_SESSION_TOKEN": {
   323  			config: map[string]any{},
   324  			EnvironmentVariables: map[string]string{
   325  				"AWS_ACCESS_KEY_ID":     servicemocks.MockEnvAccessKey,
   326  				"AWS_SECRET_ACCESS_KEY": servicemocks.MockEnvSecretKey,
   327  				"AWS_SESSION_TOKEN":     servicemocks.MockEnvSessionToken,
   328  			},
   329  			ExpectedCredentialsValue: mockdata.MockEnvCredentialsWithSessionToken,
   330  			MockStsEndpoints: []*servicemocks.MockEndpoint{
   331  				servicemocks.MockStsGetCallerIdentityValidEndpoint,
   332  			},
   333  		},
   334  
   335  		"shared credentials default aws_access_key_id": {
   336  			config: map[string]any{},
   337  			ExpectedCredentialsValue: aws.Credentials{
   338  				AccessKeyID:     "DefaultSharedCredentialsAccessKey",
   339  				SecretAccessKey: "DefaultSharedCredentialsSecretKey",
   340  				Source:          "SharedConfigCredentials",
   341  			},
   342  			MockStsEndpoints: []*servicemocks.MockEndpoint{
   343  				servicemocks.MockStsGetCallerIdentityValidEndpoint,
   344  			},
   345  			SharedCredentialsFile: `
   346  [default]
   347  aws_access_key_id = DefaultSharedCredentialsAccessKey
   348  aws_secret_access_key = DefaultSharedCredentialsSecretKey
   349  `,
   350  		},
   351  
   352  		"web identity token access key": {
   353  			config:                   map[string]any{},
   354  			EnableWebIdentityEnvVars: true,
   355  			ExpectedCredentialsValue: mockdata.MockStsAssumeRoleWithWebIdentityCredentials,
   356  			MockStsEndpoints: []*servicemocks.MockEndpoint{
   357  				servicemocks.MockStsAssumeRoleWithWebIdentityValidEndpoint,
   358  				servicemocks.MockStsGetCallerIdentityValidEndpoint,
   359  			},
   360  		},
   361  
   362  		"EC2 metadata access key": {
   363  			config:                   map[string]any{},
   364  			EnableEc2MetadataServer:  true,
   365  			ExpectedCredentialsValue: mockdata.MockEc2MetadataCredentials,
   366  			MockStsEndpoints: []*servicemocks.MockEndpoint{
   367  				servicemocks.MockStsGetCallerIdentityValidEndpoint,
   368  			},
   369  			ValidateDiags: ExpectNoDiags,
   370  		},
   371  
   372  		"ECS credentials access key": {
   373  			config:                     map[string]any{},
   374  			EnableEcsCredentialsServer: true,
   375  			ExpectedCredentialsValue:   mockdata.MockEcsCredentialsCredentials,
   376  			MockStsEndpoints: []*servicemocks.MockEndpoint{
   377  				servicemocks.MockStsGetCallerIdentityValidEndpoint,
   378  			},
   379  		},
   380  
   381  		"AssumeWebIdentity envvar AssumeRoleARN access key": {
   382  			config: map[string]any{
   383  				"role_arn":     servicemocks.MockStsAssumeRoleArn,
   384  				"session_name": servicemocks.MockStsAssumeRoleSessionName,
   385  			},
   386  			EnableWebIdentityEnvVars: true,
   387  			ExpectedCredentialsValue: mockdata.MockStsAssumeRoleCredentials,
   388  			MockStsEndpoints: []*servicemocks.MockEndpoint{
   389  				servicemocks.MockStsAssumeRoleWithWebIdentityValidEndpoint,
   390  				servicemocks.MockStsAssumeRoleValidEndpoint,
   391  				servicemocks.MockStsGetCallerIdentityValidEndpoint,
   392  			},
   393  			ValidateDiags: ExpectDiagsMatching(
   394  				tfdiags.Warning,
   395  				equalsMatcher("Deprecated Parameters"),
   396  				noopMatcher{},
   397  			),
   398  		},
   399  
   400  		"config AccessKey over environment AWS_ACCESS_KEY_ID": {
   401  			config: map[string]any{
   402  				"access_key": servicemocks.MockStaticAccessKey,
   403  				"secret_key": servicemocks.MockStaticSecretKey,
   404  			},
   405  			EnvironmentVariables: map[string]string{
   406  				"AWS_ACCESS_KEY_ID":     servicemocks.MockEnvAccessKey,
   407  				"AWS_SECRET_ACCESS_KEY": servicemocks.MockEnvSecretKey,
   408  			},
   409  			ExpectedCredentialsValue: mockdata.MockStaticCredentials,
   410  			MockStsEndpoints: []*servicemocks.MockEndpoint{
   411  				servicemocks.MockStsGetCallerIdentityValidEndpoint,
   412  			},
   413  			ValidateDiags: ExpectNoDiags,
   414  		},
   415  
   416  		"config AccessKey over shared credentials default aws_access_key_id": {
   417  			config: map[string]any{
   418  				"access_key": servicemocks.MockStaticAccessKey,
   419  				"secret_key": servicemocks.MockStaticSecretKey,
   420  			},
   421  			ExpectedCredentialsValue: mockdata.MockStaticCredentials,
   422  			MockStsEndpoints: []*servicemocks.MockEndpoint{
   423  				servicemocks.MockStsGetCallerIdentityValidEndpoint,
   424  			},
   425  			SharedCredentialsFile: `
   426  [default]
   427  aws_access_key_id = DefaultSharedCredentialsAccessKey
   428  aws_secret_access_key = DefaultSharedCredentialsSecretKey
   429  `,
   430  			ValidateDiags: ExpectNoDiags,
   431  		},
   432  
   433  		"config AccessKey over EC2 metadata access key": {
   434  			config: map[string]any{
   435  				"access_key": servicemocks.MockStaticAccessKey,
   436  				"secret_key": servicemocks.MockStaticSecretKey,
   437  			},
   438  			ExpectedCredentialsValue: mockdata.MockStaticCredentials,
   439  			MockStsEndpoints: []*servicemocks.MockEndpoint{
   440  				servicemocks.MockStsGetCallerIdentityValidEndpoint,
   441  			},
   442  		},
   443  
   444  		"config AccessKey over ECS credentials access key": {
   445  			config: map[string]any{
   446  				"access_key": servicemocks.MockStaticAccessKey,
   447  				"secret_key": servicemocks.MockStaticSecretKey,
   448  			},
   449  			EnableEcsCredentialsServer: true,
   450  			ExpectedCredentialsValue:   mockdata.MockStaticCredentials,
   451  			MockStsEndpoints: []*servicemocks.MockEndpoint{
   452  				servicemocks.MockStsGetCallerIdentityValidEndpoint,
   453  			},
   454  		},
   455  
   456  		"environment AWS_ACCESS_KEY_ID over shared credentials default aws_access_key_id": {
   457  			config: map[string]any{},
   458  			EnvironmentVariables: map[string]string{
   459  				"AWS_ACCESS_KEY_ID":     servicemocks.MockEnvAccessKey,
   460  				"AWS_SECRET_ACCESS_KEY": servicemocks.MockEnvSecretKey,
   461  			},
   462  			ExpectedCredentialsValue: mockdata.MockEnvCredentials,
   463  			MockStsEndpoints: []*servicemocks.MockEndpoint{
   464  				servicemocks.MockStsGetCallerIdentityValidEndpoint,
   465  			},
   466  			SharedCredentialsFile: `
   467  [default]
   468  aws_access_key_id = DefaultSharedCredentialsAccessKey
   469  aws_secret_access_key = DefaultSharedCredentialsSecretKey
   470  `,
   471  			ValidateDiags: ExpectNoDiags,
   472  		},
   473  
   474  		"environment AWS_ACCESS_KEY_ID over EC2 metadata access key": {
   475  			config: map[string]any{},
   476  			EnvironmentVariables: map[string]string{
   477  				"AWS_ACCESS_KEY_ID":     servicemocks.MockEnvAccessKey,
   478  				"AWS_SECRET_ACCESS_KEY": servicemocks.MockEnvSecretKey,
   479  			},
   480  			ExpectedCredentialsValue: mockdata.MockEnvCredentials,
   481  			MockStsEndpoints: []*servicemocks.MockEndpoint{
   482  				servicemocks.MockStsGetCallerIdentityValidEndpoint,
   483  			},
   484  		},
   485  
   486  		"environment AWS_ACCESS_KEY_ID over ECS credentials access key": {
   487  			config: map[string]any{},
   488  			EnvironmentVariables: map[string]string{
   489  				"AWS_ACCESS_KEY_ID":     servicemocks.MockEnvAccessKey,
   490  				"AWS_SECRET_ACCESS_KEY": servicemocks.MockEnvSecretKey,
   491  			},
   492  			EnableEcsCredentialsServer: true,
   493  			ExpectedCredentialsValue:   mockdata.MockEnvCredentials,
   494  			MockStsEndpoints: []*servicemocks.MockEndpoint{
   495  				servicemocks.MockStsGetCallerIdentityValidEndpoint,
   496  			},
   497  		},
   498  
   499  		"shared credentials default aws_access_key_id over EC2 metadata access key": {
   500  			config: map[string]any{},
   501  			ExpectedCredentialsValue: aws.Credentials{
   502  				AccessKeyID:     "DefaultSharedCredentialsAccessKey",
   503  				SecretAccessKey: "DefaultSharedCredentialsSecretKey",
   504  				Source:          "SharedConfigCredentials",
   505  			},
   506  			MockStsEndpoints: []*servicemocks.MockEndpoint{
   507  				servicemocks.MockStsGetCallerIdentityValidEndpoint,
   508  			},
   509  			SharedCredentialsFile: `
   510  [default]
   511  aws_access_key_id = DefaultSharedCredentialsAccessKey
   512  aws_secret_access_key = DefaultSharedCredentialsSecretKey
   513  `,
   514  		},
   515  
   516  		"shared credentials default aws_access_key_id over ECS credentials access key": {
   517  			config:                     map[string]any{},
   518  			EnableEcsCredentialsServer: true,
   519  			ExpectedCredentialsValue: aws.Credentials{
   520  				AccessKeyID:     "DefaultSharedCredentialsAccessKey",
   521  				SecretAccessKey: "DefaultSharedCredentialsSecretKey",
   522  				Source:          "SharedConfigCredentials",
   523  			},
   524  			MockStsEndpoints: []*servicemocks.MockEndpoint{
   525  				servicemocks.MockStsGetCallerIdentityValidEndpoint,
   526  			},
   527  			SharedCredentialsFile: `
   528  [default]
   529  aws_access_key_id = DefaultSharedCredentialsAccessKey
   530  aws_secret_access_key = DefaultSharedCredentialsSecretKey
   531  `,
   532  		},
   533  
   534  		"ECS credentials access key over EC2 metadata access key": {
   535  			config:                     map[string]any{},
   536  			EnableEcsCredentialsServer: true,
   537  			ExpectedCredentialsValue:   mockdata.MockEcsCredentialsCredentials,
   538  			MockStsEndpoints: []*servicemocks.MockEndpoint{
   539  				servicemocks.MockStsGetCallerIdentityValidEndpoint,
   540  			},
   541  		},
   542  
   543  		"retrieve region from shared configuration file": {
   544  			config: map[string]any{
   545  				"access_key": servicemocks.MockStaticAccessKey,
   546  				"secret_key": servicemocks.MockStaticSecretKey,
   547  			},
   548  			ExpectedCredentialsValue: mockdata.MockStaticCredentials,
   549  			MockStsEndpoints: []*servicemocks.MockEndpoint{
   550  				servicemocks.MockStsGetCallerIdentityValidEndpoint,
   551  			},
   552  			SharedConfigurationFile: `
   553  [default]
   554  region = us-east-1
   555  `,
   556  		},
   557  
   558  		"skip EC2 Metadata API check": {
   559  			config: map[string]any{
   560  				"skip_metadata_api_check": true,
   561  			},
   562  			// The IMDS server must be enabled so that auth will succeed if the IMDS is called
   563  			EnableEc2MetadataServer: true,
   564  			MockStsEndpoints: []*servicemocks.MockEndpoint{
   565  				servicemocks.MockStsGetCallerIdentityValidEndpoint,
   566  			},
   567  			ValidateDiags: ExpectDiagsMatching(
   568  				tfdiags.Error,
   569  				equalsMatcher("No valid credential sources found"),
   570  				newRegexpMatcher("^Please see.+"),
   571  			),
   572  		},
   573  
   574  		"invalid profile name from envvar": {
   575  			config: map[string]any{},
   576  			EnvironmentVariables: map[string]string{
   577  				"AWS_PROFILE": "no-such-profile",
   578  			},
   579  			MockStsEndpoints: []*servicemocks.MockEndpoint{
   580  				servicemocks.MockStsGetCallerIdentityValidEndpoint,
   581  			},
   582  			SharedCredentialsFile: `
   583  [some-profile]
   584  aws_access_key_id = DefaultSharedCredentialsAccessKey
   585  aws_secret_access_key = DefaultSharedCredentialsSecretKey
   586  `,
   587  			ValidateDiags: ExpectDiagsMatching(
   588  				tfdiags.Error,
   589  				equalsMatcher("failed to get shared config profile, no-such-profile"),
   590  				equalsMatcher(""),
   591  			),
   592  		},
   593  
   594  		"invalid profile name from config": {
   595  			config: map[string]any{
   596  				"profile": "no-such-profile",
   597  			},
   598  			SharedCredentialsFile: `
   599  [some-profile]
   600  aws_access_key_id = DefaultSharedCredentialsAccessKey
   601  aws_secret_access_key = DefaultSharedCredentialsSecretKey
   602  `,
   603  			MockStsEndpoints: []*servicemocks.MockEndpoint{
   604  				servicemocks.MockStsGetCallerIdentityValidEndpoint,
   605  			},
   606  			ValidateDiags: ExpectDiagsMatching(
   607  				tfdiags.Error,
   608  				equalsMatcher("failed to get shared config profile, no-such-profile"),
   609  				equalsMatcher(""),
   610  			),
   611  		},
   612  
   613  		"AWS_ACCESS_KEY_ID overrides AWS_PROFILE": {
   614  			config: map[string]any{},
   615  			EnvironmentVariables: map[string]string{
   616  				"AWS_ACCESS_KEY_ID":     servicemocks.MockEnvAccessKey,
   617  				"AWS_SECRET_ACCESS_KEY": servicemocks.MockEnvSecretKey,
   618  				"AWS_PROFILE":           "SharedCredentialsProfile",
   619  			},
   620  			SharedCredentialsFile: `
   621  [default]
   622  aws_access_key_id = DefaultSharedCredentialsAccessKey
   623  aws_secret_access_key = DefaultSharedCredentialsSecretKey
   624  
   625  [SharedCredentialsProfile]
   626  aws_access_key_id = ProfileSharedCredentialsAccessKey
   627  aws_secret_access_key = ProfileSharedCredentialsSecretKey
   628  `,
   629  			MockStsEndpoints: []*servicemocks.MockEndpoint{
   630  				servicemocks.MockStsGetCallerIdentityValidEndpoint,
   631  			},
   632  			ExpectedCredentialsValue: mockdata.MockEnvCredentials,
   633  			ValidateDiags:            ExpectNoDiags,
   634  		},
   635  
   636  		"AWS_ACCESS_KEY_ID does not override invalid profile name from envvar": {
   637  			config: map[string]any{},
   638  			EnvironmentVariables: map[string]string{
   639  				"AWS_ACCESS_KEY_ID":     servicemocks.MockEnvAccessKey,
   640  				"AWS_SECRET_ACCESS_KEY": servicemocks.MockEnvSecretKey,
   641  				"AWS_PROFILE":           "no-such-profile",
   642  			},
   643  			MockStsEndpoints: []*servicemocks.MockEndpoint{
   644  				servicemocks.MockStsGetCallerIdentityValidEndpoint,
   645  			},
   646  			SharedCredentialsFile: `
   647  [some-profile]
   648  aws_access_key_id = DefaultSharedCredentialsAccessKey
   649  aws_secret_access_key = DefaultSharedCredentialsSecretKey
   650  `,
   651  			ValidateDiags: ExpectDiagsMatching(
   652  				tfdiags.Error,
   653  				equalsMatcher("failed to get shared config profile, no-such-profile"),
   654  				equalsMatcher(""),
   655  			),
   656  		},
   657  	}
   658  
   659  	for name, tc := range testCases {
   660  		tc := tc
   661  
   662  		t.Run(name, func(t *testing.T) {
   663  			servicemocks.InitSessionTestEnv(t)
   664  
   665  			// Populate required fields
   666  			tc.config["region"] = "us-east-1"
   667  			tc.config["bucket"] = "bucket"
   668  			tc.config["key"] = "key"
   669  
   670  			if tc.ValidateDiags == nil {
   671  				tc.ValidateDiags = ExpectNoDiags
   672  			}
   673  
   674  			if tc.EnableEc2MetadataServer {
   675  				closeEc2Metadata := servicemocks.AwsMetadataApiMock(append(
   676  					servicemocks.Ec2metadata_securityCredentialsEndpoints,
   677  					servicemocks.Ec2metadata_instanceIdEndpoint,
   678  					servicemocks.Ec2metadata_iamInfoEndpoint,
   679  				))
   680  				defer closeEc2Metadata()
   681  			}
   682  
   683  			if tc.EnableEcsCredentialsServer {
   684  				closeEcsCredentials := servicemocks.EcsCredentialsApiMock()
   685  				defer closeEcsCredentials()
   686  			}
   687  
   688  			if tc.EnableWebIdentityEnvVars /*|| tc.EnableWebIdentityConfig*/ {
   689  				file, err := os.CreateTemp("", "aws-sdk-go-base-web-identity-token-file")
   690  				if err != nil {
   691  					t.Fatalf("unexpected error creating temporary web identity token file: %s", err)
   692  				}
   693  
   694  				defer os.Remove(file.Name())
   695  
   696  				err = os.WriteFile(file.Name(), []byte(servicemocks.MockWebIdentityToken), 0600)
   697  
   698  				if err != nil {
   699  					t.Fatalf("unexpected error writing web identity token file: %s", err)
   700  				}
   701  
   702  				if tc.EnableWebIdentityEnvVars {
   703  					t.Setenv("AWS_ROLE_ARN", servicemocks.MockStsAssumeRoleWithWebIdentityArn)
   704  					t.Setenv("AWS_ROLE_SESSION_NAME", servicemocks.MockStsAssumeRoleWithWebIdentitySessionName)
   705  					t.Setenv("AWS_WEB_IDENTITY_TOKEN_FILE", file.Name())
   706  				} /*else if tc.EnableWebIdentityConfig {
   707  					tc.Config.AssumeRoleWithWebIdentity = &AssumeRoleWithWebIdentity{
   708  						RoleARN:              servicemocks.MockStsAssumeRoleWithWebIdentityArn,
   709  						SessionName:          servicemocks.MockStsAssumeRoleWithWebIdentitySessionName,
   710  						WebIdentityTokenFile: file.Name(),
   711  					}
   712  				}*/
   713  			}
   714  
   715  			ts := servicemocks.MockAwsApiServer("STS", tc.MockStsEndpoints)
   716  			defer ts.Close()
   717  
   718  			tc.config["sts_endpoint"] = ts.URL
   719  
   720  			if tc.SharedConfigurationFile != "" {
   721  				file, err := os.CreateTemp("", "aws-sdk-go-base-shared-configuration-file")
   722  
   723  				if err != nil {
   724  					t.Fatalf("unexpected error creating temporary shared configuration file: %s", err)
   725  				}
   726  
   727  				defer os.Remove(file.Name())
   728  
   729  				err = os.WriteFile(file.Name(), []byte(tc.SharedConfigurationFile), 0600)
   730  
   731  				if err != nil {
   732  					t.Fatalf("unexpected error writing shared configuration file: %s", err)
   733  				}
   734  
   735  				setSharedConfigFile(t, file.Name())
   736  			}
   737  
   738  			if tc.SharedCredentialsFile != "" {
   739  				file, err := os.CreateTemp("", "aws-sdk-go-base-shared-credentials-file")
   740  
   741  				if err != nil {
   742  					t.Fatalf("unexpected error creating temporary shared credentials file: %s", err)
   743  				}
   744  
   745  				defer os.Remove(file.Name())
   746  
   747  				err = os.WriteFile(file.Name(), []byte(tc.SharedCredentialsFile), 0600)
   748  
   749  				if err != nil {
   750  					t.Fatalf("unexpected error writing shared credentials file: %s", err)
   751  				}
   752  
   753  				tc.config["shared_credentials_files"] = []any{file.Name()}
   754  				if tc.ExpectedCredentialsValue.Source == "SharedConfigCredentials" {
   755  					tc.ExpectedCredentialsValue.Source = fmt.Sprintf("SharedConfigCredentials: %s", file.Name())
   756  				}
   757  
   758  				tc.config["shared_config_files"] = []any{file.Name()}
   759  			}
   760  
   761  			for k, v := range tc.EnvironmentVariables {
   762  				t.Setenv(k, v)
   763  			}
   764  
   765  			b, diags := configureBackend(t, tc.config)
   766  
   767  			tc.ValidateDiags(t, diags)
   768  
   769  			if diags.HasErrors() {
   770  				return
   771  			}
   772  
   773  			credentials, err := b.awsConfig.Credentials.Retrieve(context.TODO())
   774  			if err != nil {
   775  				t.Fatalf("Error when requesting credentials: %s", err)
   776  			}
   777  
   778  			if diff := cmp.Diff(credentials, tc.ExpectedCredentialsValue, cmpopts.IgnoreFields(aws.Credentials{}, "Expires")); diff != "" {
   779  				t.Fatalf("unexpected credentials: (- got, + expected)\n%s", diff)
   780  			}
   781  		})
   782  	}
   783  }
   784  func TestBackendConfig_Authentication_AssumeRoleInline(t *testing.T) {
   785  	testCases := map[string]struct {
   786  		config                     map[string]any
   787  		EnableEc2MetadataServer    bool
   788  		EnableEcsCredentialsServer bool
   789  		EnvironmentVariables       map[string]string
   790  		ExpectedCredentialsValue   aws.Credentials
   791  		MockStsEndpoints           []*servicemocks.MockEndpoint
   792  		SharedConfigurationFile    string
   793  		SharedCredentialsFile      string
   794  		ValidateDiags              diagsValidator
   795  	}{
   796  		"from config access_key": {
   797  			config: map[string]any{
   798  				"access_key":   servicemocks.MockStaticAccessKey,
   799  				"secret_key":   servicemocks.MockStaticSecretKey,
   800  				"role_arn":     servicemocks.MockStsAssumeRoleArn,
   801  				"session_name": servicemocks.MockStsAssumeRoleSessionName,
   802  			},
   803  			ExpectedCredentialsValue: mockdata.MockStsAssumeRoleCredentials,
   804  			MockStsEndpoints: []*servicemocks.MockEndpoint{
   805  				servicemocks.MockStsAssumeRoleValidEndpoint,
   806  				servicemocks.MockStsGetCallerIdentityValidEndpoint,
   807  			},
   808  			ValidateDiags: ExpectDiagsMatching(
   809  				tfdiags.Warning,
   810  				equalsMatcher("Deprecated Parameters"),
   811  				noopMatcher{},
   812  			),
   813  		},
   814  
   815  		"from environment AWS_ACCESS_KEY_ID": {
   816  			config: map[string]any{
   817  				"role_arn":     servicemocks.MockStsAssumeRoleArn,
   818  				"session_name": servicemocks.MockStsAssumeRoleSessionName,
   819  			},
   820  			EnvironmentVariables: map[string]string{
   821  				"AWS_ACCESS_KEY_ID":     servicemocks.MockEnvAccessKey,
   822  				"AWS_SECRET_ACCESS_KEY": servicemocks.MockEnvSecretKey,
   823  			},
   824  			ExpectedCredentialsValue: mockdata.MockStsAssumeRoleCredentials,
   825  			MockStsEndpoints: []*servicemocks.MockEndpoint{
   826  				servicemocks.MockStsAssumeRoleValidEndpoint,
   827  				servicemocks.MockStsGetCallerIdentityValidEndpoint,
   828  			},
   829  			ValidateDiags: ExpectDiagsMatching(
   830  				tfdiags.Warning,
   831  				equalsMatcher("Deprecated Parameters"),
   832  				noopMatcher{},
   833  			),
   834  		},
   835  
   836  		"from config Profile with Ec2InstanceMetadata source": {
   837  			config: map[string]any{
   838  				"profile": "SharedConfigurationProfile",
   839  			},
   840  			EnableEc2MetadataServer:  true,
   841  			ExpectedCredentialsValue: mockdata.MockStsAssumeRoleCredentials,
   842  			MockStsEndpoints: []*servicemocks.MockEndpoint{
   843  				servicemocks.MockStsAssumeRoleValidEndpoint,
   844  				servicemocks.MockStsGetCallerIdentityValidEndpoint,
   845  			},
   846  			SharedConfigurationFile: fmt.Sprintf(`
   847  [profile SharedConfigurationProfile]
   848  credential_source = Ec2InstanceMetadata
   849  role_arn = %[1]s
   850  role_session_name = %[2]s
   851  `, servicemocks.MockStsAssumeRoleArn, servicemocks.MockStsAssumeRoleSessionName),
   852  		},
   853  
   854  		"from environment AWS_PROFILE with Ec2InstanceMetadata source": {
   855  			config:                  map[string]any{},
   856  			EnableEc2MetadataServer: true,
   857  			EnvironmentVariables: map[string]string{
   858  				"AWS_PROFILE": "SharedConfigurationProfile",
   859  			},
   860  			ExpectedCredentialsValue: mockdata.MockStsAssumeRoleCredentials,
   861  			MockStsEndpoints: []*servicemocks.MockEndpoint{
   862  				servicemocks.MockStsAssumeRoleValidEndpoint,
   863  				servicemocks.MockStsGetCallerIdentityValidEndpoint,
   864  			},
   865  			SharedConfigurationFile: fmt.Sprintf(`
   866  [profile SharedConfigurationProfile]
   867  credential_source = Ec2InstanceMetadata
   868  role_arn = %[1]s
   869  role_session_name = %[2]s
   870  `, servicemocks.MockStsAssumeRoleArn, servicemocks.MockStsAssumeRoleSessionName),
   871  		},
   872  
   873  		"from config Profile with source profile": {
   874  			config: map[string]any{
   875  				"profile": "SharedConfigurationProfile",
   876  			},
   877  			ExpectedCredentialsValue: mockdata.MockStsAssumeRoleCredentials,
   878  			MockStsEndpoints: []*servicemocks.MockEndpoint{
   879  				servicemocks.MockStsAssumeRoleValidEndpoint,
   880  				servicemocks.MockStsGetCallerIdentityValidEndpoint,
   881  			},
   882  			SharedConfigurationFile: fmt.Sprintf(`
   883  [profile SharedConfigurationProfile]
   884  role_arn = %[1]s
   885  role_session_name = %[2]s
   886  source_profile = SharedConfigurationSourceProfile
   887  
   888  [profile SharedConfigurationSourceProfile]
   889  aws_access_key_id = SharedConfigurationSourceAccessKey
   890  aws_secret_access_key = SharedConfigurationSourceSecretKey
   891  `, servicemocks.MockStsAssumeRoleArn, servicemocks.MockStsAssumeRoleSessionName),
   892  		},
   893  
   894  		"from environment AWS_PROFILE with source profile": {
   895  			config: map[string]any{},
   896  			EnvironmentVariables: map[string]string{
   897  				"AWS_PROFILE": "SharedConfigurationProfile",
   898  			},
   899  			ExpectedCredentialsValue: mockdata.MockStsAssumeRoleCredentials,
   900  			MockStsEndpoints: []*servicemocks.MockEndpoint{
   901  				servicemocks.MockStsAssumeRoleValidEndpoint,
   902  				servicemocks.MockStsGetCallerIdentityValidEndpoint,
   903  			},
   904  			SharedConfigurationFile: fmt.Sprintf(`
   905  [profile SharedConfigurationProfile]
   906  role_arn = %[1]s
   907  role_session_name = %[2]s
   908  source_profile = SharedConfigurationSourceProfile
   909  
   910  [profile SharedConfigurationSourceProfile]
   911  aws_access_key_id = SharedConfigurationSourceAccessKey
   912  aws_secret_access_key = SharedConfigurationSourceSecretKey
   913  `, servicemocks.MockStsAssumeRoleArn, servicemocks.MockStsAssumeRoleSessionName),
   914  		},
   915  
   916  		"from default profile": {
   917  			config: map[string]any{
   918  				"role_arn":     servicemocks.MockStsAssumeRoleArn,
   919  				"session_name": servicemocks.MockStsAssumeRoleSessionName,
   920  			},
   921  			ExpectedCredentialsValue: mockdata.MockStsAssumeRoleCredentials,
   922  			MockStsEndpoints: []*servicemocks.MockEndpoint{
   923  				servicemocks.MockStsAssumeRoleValidEndpoint,
   924  				servicemocks.MockStsGetCallerIdentityValidEndpoint,
   925  			},
   926  			SharedCredentialsFile: `
   927  [default]
   928  aws_access_key_id = DefaultSharedCredentialsAccessKey
   929  aws_secret_access_key = DefaultSharedCredentialsSecretKey
   930  `,
   931  			ValidateDiags: ExpectDiagsMatching(
   932  				tfdiags.Warning,
   933  				equalsMatcher("Deprecated Parameters"),
   934  				noopMatcher{},
   935  			),
   936  		},
   937  
   938  		"from EC2 metadata": {
   939  			config: map[string]any{
   940  				"role_arn":     servicemocks.MockStsAssumeRoleArn,
   941  				"session_name": servicemocks.MockStsAssumeRoleSessionName,
   942  			},
   943  			EnableEc2MetadataServer:  true,
   944  			ExpectedCredentialsValue: mockdata.MockStsAssumeRoleCredentials,
   945  			MockStsEndpoints: []*servicemocks.MockEndpoint{
   946  				servicemocks.MockStsAssumeRoleValidEndpoint,
   947  				servicemocks.MockStsGetCallerIdentityValidEndpoint,
   948  			},
   949  			ValidateDiags: ExpectDiagsMatching(
   950  				tfdiags.Warning,
   951  				equalsMatcher("Deprecated Parameters"),
   952  				noopMatcher{},
   953  			),
   954  		},
   955  
   956  		"from ECS credentials": {
   957  			config: map[string]any{
   958  				"role_arn":     servicemocks.MockStsAssumeRoleArn,
   959  				"session_name": servicemocks.MockStsAssumeRoleSessionName,
   960  			},
   961  			EnableEcsCredentialsServer: true,
   962  			ExpectedCredentialsValue:   mockdata.MockStsAssumeRoleCredentials,
   963  			MockStsEndpoints: []*servicemocks.MockEndpoint{
   964  				servicemocks.MockStsAssumeRoleValidEndpoint,
   965  				servicemocks.MockStsGetCallerIdentityValidEndpoint,
   966  			},
   967  			ValidateDiags: ExpectDiagsMatching(
   968  				tfdiags.Warning,
   969  				equalsMatcher("Deprecated Parameters"),
   970  				noopMatcher{},
   971  			),
   972  		},
   973  
   974  		"with duration": {
   975  			config: map[string]any{
   976  				"access_key":                   servicemocks.MockStaticAccessKey,
   977  				"secret_key":                   servicemocks.MockStaticSecretKey,
   978  				"role_arn":                     servicemocks.MockStsAssumeRoleArn,
   979  				"session_name":                 servicemocks.MockStsAssumeRoleSessionName,
   980  				"assume_role_duration_seconds": 3600,
   981  			},
   982  			ExpectedCredentialsValue: mockdata.MockStsAssumeRoleCredentials,
   983  			MockStsEndpoints: []*servicemocks.MockEndpoint{
   984  				servicemocks.MockStsAssumeRoleValidEndpointWithOptions(map[string]string{"DurationSeconds": "3600"}),
   985  				servicemocks.MockStsGetCallerIdentityValidEndpoint,
   986  			},
   987  			ValidateDiags: ExpectDiagsMatching(
   988  				tfdiags.Warning,
   989  				equalsMatcher("Deprecated Parameters"),
   990  				noopMatcher{},
   991  			),
   992  		},
   993  
   994  		"with external ID": {
   995  			config: map[string]any{
   996  				"access_key":   servicemocks.MockStaticAccessKey,
   997  				"secret_key":   servicemocks.MockStaticSecretKey,
   998  				"role_arn":     servicemocks.MockStsAssumeRoleArn,
   999  				"session_name": servicemocks.MockStsAssumeRoleSessionName,
  1000  				"external_id":  servicemocks.MockStsAssumeRoleExternalId,
  1001  			},
  1002  			ExpectedCredentialsValue: mockdata.MockStsAssumeRoleCredentials,
  1003  			MockStsEndpoints: []*servicemocks.MockEndpoint{
  1004  				servicemocks.MockStsAssumeRoleValidEndpointWithOptions(map[string]string{"ExternalId": servicemocks.MockStsAssumeRoleExternalId}),
  1005  				servicemocks.MockStsGetCallerIdentityValidEndpoint,
  1006  			},
  1007  			ValidateDiags: ExpectDiagsMatching(
  1008  				tfdiags.Warning,
  1009  				equalsMatcher("Deprecated Parameters"),
  1010  				noopMatcher{},
  1011  			),
  1012  		},
  1013  
  1014  		"with policy": {
  1015  			config: map[string]any{
  1016  				"access_key":         servicemocks.MockStaticAccessKey,
  1017  				"secret_key":         servicemocks.MockStaticSecretKey,
  1018  				"role_arn":           servicemocks.MockStsAssumeRoleArn,
  1019  				"session_name":       servicemocks.MockStsAssumeRoleSessionName,
  1020  				"assume_role_policy": mockStsAssumeRolePolicy,
  1021  			},
  1022  			ExpectedCredentialsValue: mockdata.MockStsAssumeRoleCredentials,
  1023  			MockStsEndpoints: []*servicemocks.MockEndpoint{
  1024  				servicemocks.MockStsAssumeRoleValidEndpointWithOptions(map[string]string{"Policy": mockStsAssumeRolePolicy}),
  1025  				servicemocks.MockStsGetCallerIdentityValidEndpoint,
  1026  			},
  1027  			ValidateDiags: ExpectDiagsMatching(
  1028  				tfdiags.Warning,
  1029  				equalsMatcher("Deprecated Parameters"),
  1030  				noopMatcher{},
  1031  			),
  1032  		},
  1033  
  1034  		"with policy ARNs": {
  1035  			config: map[string]any{
  1036  				"access_key":              servicemocks.MockStaticAccessKey,
  1037  				"secret_key":              servicemocks.MockStaticSecretKey,
  1038  				"role_arn":                servicemocks.MockStsAssumeRoleArn,
  1039  				"session_name":            servicemocks.MockStsAssumeRoleSessionName,
  1040  				"assume_role_policy_arns": []any{servicemocks.MockStsAssumeRolePolicyArn},
  1041  			},
  1042  			ExpectedCredentialsValue: mockdata.MockStsAssumeRoleCredentials,
  1043  			MockStsEndpoints: []*servicemocks.MockEndpoint{
  1044  				servicemocks.MockStsAssumeRoleValidEndpointWithOptions(map[string]string{"PolicyArns.member.1.arn": servicemocks.MockStsAssumeRolePolicyArn}),
  1045  				servicemocks.MockStsGetCallerIdentityValidEndpoint,
  1046  			},
  1047  			ValidateDiags: ExpectDiagsMatching(
  1048  				tfdiags.Warning,
  1049  				equalsMatcher("Deprecated Parameters"),
  1050  				noopMatcher{},
  1051  			),
  1052  		},
  1053  
  1054  		"with tags": {
  1055  			config: map[string]any{
  1056  				"access_key":   servicemocks.MockStaticAccessKey,
  1057  				"secret_key":   servicemocks.MockStaticSecretKey,
  1058  				"role_arn":     servicemocks.MockStsAssumeRoleArn,
  1059  				"session_name": servicemocks.MockStsAssumeRoleSessionName,
  1060  				"assume_role_tags": map[string]any{
  1061  					servicemocks.MockStsAssumeRoleTagKey: servicemocks.MockStsAssumeRoleTagValue,
  1062  				},
  1063  			},
  1064  			ExpectedCredentialsValue: mockdata.MockStsAssumeRoleCredentials,
  1065  			MockStsEndpoints: []*servicemocks.MockEndpoint{
  1066  				servicemocks.MockStsAssumeRoleValidEndpointWithOptions(map[string]string{"Tags.member.1.Key": servicemocks.MockStsAssumeRoleTagKey, "Tags.member.1.Value": servicemocks.MockStsAssumeRoleTagValue}),
  1067  				servicemocks.MockStsGetCallerIdentityValidEndpoint,
  1068  			},
  1069  			ValidateDiags: ExpectDiagsMatching(
  1070  				tfdiags.Warning,
  1071  				equalsMatcher("Deprecated Parameters"),
  1072  				noopMatcher{},
  1073  			),
  1074  		},
  1075  
  1076  		"with transitive tags": {
  1077  			config: map[string]any{
  1078  				"access_key":   servicemocks.MockStaticAccessKey,
  1079  				"secret_key":   servicemocks.MockStaticSecretKey,
  1080  				"role_arn":     servicemocks.MockStsAssumeRoleArn,
  1081  				"session_name": servicemocks.MockStsAssumeRoleSessionName,
  1082  				"assume_role_tags": map[string]any{
  1083  					servicemocks.MockStsAssumeRoleTagKey: servicemocks.MockStsAssumeRoleTagValue,
  1084  				},
  1085  				"assume_role_transitive_tag_keys": []any{servicemocks.MockStsAssumeRoleTagKey},
  1086  			},
  1087  			ExpectedCredentialsValue: mockdata.MockStsAssumeRoleCredentials,
  1088  			MockStsEndpoints: []*servicemocks.MockEndpoint{
  1089  				servicemocks.MockStsAssumeRoleValidEndpointWithOptions(map[string]string{"Tags.member.1.Key": servicemocks.MockStsAssumeRoleTagKey, "Tags.member.1.Value": servicemocks.MockStsAssumeRoleTagValue, "TransitiveTagKeys.member.1": servicemocks.MockStsAssumeRoleTagKey}),
  1090  				servicemocks.MockStsGetCallerIdentityValidEndpoint,
  1091  			},
  1092  			ValidateDiags: ExpectDiagsMatching(
  1093  				tfdiags.Warning,
  1094  				equalsMatcher("Deprecated Parameters"),
  1095  				noopMatcher{},
  1096  			),
  1097  		},
  1098  
  1099  		"error": {
  1100  			config: map[string]any{
  1101  				"access_key":   servicemocks.MockStaticAccessKey,
  1102  				"secret_key":   servicemocks.MockStaticSecretKey,
  1103  				"role_arn":     servicemocks.MockStsAssumeRoleArn,
  1104  				"session_name": servicemocks.MockStsAssumeRoleSessionName,
  1105  			},
  1106  			MockStsEndpoints: []*servicemocks.MockEndpoint{
  1107  				servicemocks.MockStsAssumeRoleInvalidEndpointInvalidClientTokenId,
  1108  				servicemocks.MockStsGetCallerIdentityValidEndpoint,
  1109  			},
  1110  			ValidateDiags: ExpectMultipleDiags(
  1111  				ExpectDiagMatching(
  1112  					tfdiags.Warning,
  1113  					equalsMatcher("Deprecated Parameters"),
  1114  					noopMatcher{},
  1115  				),
  1116  				ExpectDiagMatching(
  1117  					tfdiags.Error,
  1118  					equalsMatcher("Cannot assume IAM Role"),
  1119  					noopMatcher{},
  1120  				),
  1121  			),
  1122  		},
  1123  	}
  1124  
  1125  	for name, tc := range testCases {
  1126  		tc := tc
  1127  
  1128  		t.Run(name, func(t *testing.T) {
  1129  			servicemocks.InitSessionTestEnv(t)
  1130  
  1131  			ctx := context.TODO()
  1132  
  1133  			// Populate required fields
  1134  			tc.config["region"] = "us-east-1"
  1135  			tc.config["bucket"] = "bucket"
  1136  			tc.config["key"] = "key"
  1137  
  1138  			if tc.ValidateDiags == nil {
  1139  				tc.ValidateDiags = ExpectNoDiags
  1140  			}
  1141  
  1142  			if tc.EnableEc2MetadataServer {
  1143  				closeEc2Metadata := servicemocks.AwsMetadataApiMock(append(
  1144  					servicemocks.Ec2metadata_securityCredentialsEndpoints,
  1145  					servicemocks.Ec2metadata_instanceIdEndpoint,
  1146  					servicemocks.Ec2metadata_iamInfoEndpoint,
  1147  				))
  1148  				defer closeEc2Metadata()
  1149  			}
  1150  
  1151  			if tc.EnableEcsCredentialsServer {
  1152  				closeEcsCredentials := servicemocks.EcsCredentialsApiMock()
  1153  				defer closeEcsCredentials()
  1154  			}
  1155  
  1156  			ts := servicemocks.MockAwsApiServer("STS", tc.MockStsEndpoints)
  1157  			defer ts.Close()
  1158  
  1159  			tc.config["sts_endpoint"] = ts.URL
  1160  
  1161  			if tc.SharedConfigurationFile != "" {
  1162  				file, err := os.CreateTemp("", "aws-sdk-go-base-shared-configuration-file")
  1163  
  1164  				if err != nil {
  1165  					t.Fatalf("unexpected error creating temporary shared configuration file: %s", err)
  1166  				}
  1167  
  1168  				defer os.Remove(file.Name())
  1169  
  1170  				err = os.WriteFile(file.Name(), []byte(tc.SharedConfigurationFile), 0600)
  1171  
  1172  				if err != nil {
  1173  					t.Fatalf("unexpected error writing shared configuration file: %s", err)
  1174  				}
  1175  
  1176  				setSharedConfigFile(t, file.Name())
  1177  			}
  1178  
  1179  			if tc.SharedCredentialsFile != "" {
  1180  				file, err := os.CreateTemp("", "aws-sdk-go-base-shared-credentials-file")
  1181  
  1182  				if err != nil {
  1183  					t.Fatalf("unexpected error creating temporary shared credentials file: %s", err)
  1184  				}
  1185  
  1186  				defer os.Remove(file.Name())
  1187  
  1188  				err = os.WriteFile(file.Name(), []byte(tc.SharedCredentialsFile), 0600)
  1189  
  1190  				if err != nil {
  1191  					t.Fatalf("unexpected error writing shared credentials file: %s", err)
  1192  				}
  1193  
  1194  				tc.config["shared_credentials_files"] = []any{file.Name()}
  1195  				if tc.ExpectedCredentialsValue.Source == "SharedConfigCredentials" {
  1196  					tc.ExpectedCredentialsValue.Source = fmt.Sprintf("SharedConfigCredentials: %s", file.Name())
  1197  				}
  1198  			}
  1199  
  1200  			for k, v := range tc.EnvironmentVariables {
  1201  				t.Setenv(k, v)
  1202  			}
  1203  
  1204  			b, diags := configureBackend(t, tc.config)
  1205  
  1206  			tc.ValidateDiags(t, diags)
  1207  
  1208  			if diags.HasErrors() {
  1209  				return
  1210  			}
  1211  
  1212  			credentials, err := b.awsConfig.Credentials.Retrieve(ctx)
  1213  			if err != nil {
  1214  				t.Fatalf("Error when requesting credentials: %s", err)
  1215  			}
  1216  
  1217  			if diff := cmp.Diff(credentials, tc.ExpectedCredentialsValue, cmpopts.IgnoreFields(aws.Credentials{}, "Expires")); diff != "" {
  1218  				t.Fatalf("unexpected credentials: (- got, + expected)\n%s", diff)
  1219  			}
  1220  		})
  1221  	}
  1222  }
  1223  
  1224  func TestBackendConfig_Authentication_AssumeRoleNested(t *testing.T) {
  1225  	testCases := map[string]struct {
  1226  		config                     map[string]any
  1227  		EnableEc2MetadataServer    bool
  1228  		EnableEcsCredentialsServer bool
  1229  		EnvironmentVariables       map[string]string
  1230  		ExpectedCredentialsValue   aws.Credentials
  1231  		MockStsEndpoints           []*servicemocks.MockEndpoint
  1232  		SharedConfigurationFile    string
  1233  		SharedCredentialsFile      string
  1234  		ValidateDiags              diagsValidator
  1235  	}{
  1236  		"from config access_key": {
  1237  			config: map[string]any{
  1238  				"access_key": servicemocks.MockStaticAccessKey,
  1239  				"secret_key": servicemocks.MockStaticSecretKey,
  1240  				"assume_role": map[string]any{
  1241  					"role_arn":     servicemocks.MockStsAssumeRoleArn,
  1242  					"session_name": servicemocks.MockStsAssumeRoleSessionName,
  1243  				},
  1244  			},
  1245  			ExpectedCredentialsValue: mockdata.MockStsAssumeRoleCredentials,
  1246  			MockStsEndpoints: []*servicemocks.MockEndpoint{
  1247  				servicemocks.MockStsAssumeRoleValidEndpoint,
  1248  				servicemocks.MockStsGetCallerIdentityValidEndpoint,
  1249  			},
  1250  		},
  1251  
  1252  		"from environment AWS_ACCESS_KEY_ID": {
  1253  			config: map[string]any{
  1254  				"assume_role": map[string]any{
  1255  					"role_arn":     servicemocks.MockStsAssumeRoleArn,
  1256  					"session_name": servicemocks.MockStsAssumeRoleSessionName,
  1257  				},
  1258  			},
  1259  			EnvironmentVariables: map[string]string{
  1260  				"AWS_ACCESS_KEY_ID":     servicemocks.MockEnvAccessKey,
  1261  				"AWS_SECRET_ACCESS_KEY": servicemocks.MockEnvSecretKey,
  1262  			},
  1263  			ExpectedCredentialsValue: mockdata.MockStsAssumeRoleCredentials,
  1264  			MockStsEndpoints: []*servicemocks.MockEndpoint{
  1265  				servicemocks.MockStsAssumeRoleValidEndpoint,
  1266  				servicemocks.MockStsGetCallerIdentityValidEndpoint,
  1267  			},
  1268  		},
  1269  
  1270  		"from config Profile with Ec2InstanceMetadata source": {
  1271  			config: map[string]any{
  1272  				"profile": "SharedConfigurationProfile",
  1273  			},
  1274  			EnableEc2MetadataServer:  true,
  1275  			ExpectedCredentialsValue: mockdata.MockStsAssumeRoleCredentials,
  1276  			MockStsEndpoints: []*servicemocks.MockEndpoint{
  1277  				servicemocks.MockStsAssumeRoleValidEndpoint,
  1278  				servicemocks.MockStsGetCallerIdentityValidEndpoint,
  1279  			},
  1280  			SharedConfigurationFile: fmt.Sprintf(`
  1281  [profile SharedConfigurationProfile]
  1282  credential_source = Ec2InstanceMetadata
  1283  role_arn = %[1]s
  1284  role_session_name = %[2]s
  1285  `, servicemocks.MockStsAssumeRoleArn, servicemocks.MockStsAssumeRoleSessionName),
  1286  		},
  1287  
  1288  		"from environment AWS_PROFILE with Ec2InstanceMetadata source": {
  1289  			config:                  map[string]any{},
  1290  			EnableEc2MetadataServer: true,
  1291  			EnvironmentVariables: map[string]string{
  1292  				"AWS_PROFILE": "SharedConfigurationProfile",
  1293  			},
  1294  			ExpectedCredentialsValue: mockdata.MockStsAssumeRoleCredentials,
  1295  			MockStsEndpoints: []*servicemocks.MockEndpoint{
  1296  				servicemocks.MockStsAssumeRoleValidEndpoint,
  1297  				servicemocks.MockStsGetCallerIdentityValidEndpoint,
  1298  			},
  1299  			SharedConfigurationFile: fmt.Sprintf(`
  1300  [profile SharedConfigurationProfile]
  1301  credential_source = Ec2InstanceMetadata
  1302  role_arn = %[1]s
  1303  role_session_name = %[2]s
  1304  `, servicemocks.MockStsAssumeRoleArn, servicemocks.MockStsAssumeRoleSessionName),
  1305  		},
  1306  
  1307  		"from config Profile with source profile": {
  1308  			config: map[string]any{
  1309  				"profile": "SharedConfigurationProfile",
  1310  			},
  1311  			ExpectedCredentialsValue: mockdata.MockStsAssumeRoleCredentials,
  1312  			MockStsEndpoints: []*servicemocks.MockEndpoint{
  1313  				servicemocks.MockStsAssumeRoleValidEndpoint,
  1314  				servicemocks.MockStsGetCallerIdentityValidEndpoint,
  1315  			},
  1316  			SharedConfigurationFile: fmt.Sprintf(`
  1317  [profile SharedConfigurationProfile]
  1318  role_arn = %[1]s
  1319  role_session_name = %[2]s
  1320  source_profile = SharedConfigurationSourceProfile
  1321  
  1322  [profile SharedConfigurationSourceProfile]
  1323  aws_access_key_id = SharedConfigurationSourceAccessKey
  1324  aws_secret_access_key = SharedConfigurationSourceSecretKey
  1325  `, servicemocks.MockStsAssumeRoleArn, servicemocks.MockStsAssumeRoleSessionName),
  1326  		},
  1327  
  1328  		"from environment AWS_PROFILE with source profile": {
  1329  			config: map[string]any{},
  1330  			EnvironmentVariables: map[string]string{
  1331  				"AWS_PROFILE": "SharedConfigurationProfile",
  1332  			},
  1333  			ExpectedCredentialsValue: mockdata.MockStsAssumeRoleCredentials,
  1334  			MockStsEndpoints: []*servicemocks.MockEndpoint{
  1335  				servicemocks.MockStsAssumeRoleValidEndpoint,
  1336  				servicemocks.MockStsGetCallerIdentityValidEndpoint,
  1337  			},
  1338  			SharedConfigurationFile: fmt.Sprintf(`
  1339  [profile SharedConfigurationProfile]
  1340  role_arn = %[1]s
  1341  role_session_name = %[2]s
  1342  source_profile = SharedConfigurationSourceProfile
  1343  
  1344  [profile SharedConfigurationSourceProfile]
  1345  aws_access_key_id = SharedConfigurationSourceAccessKey
  1346  aws_secret_access_key = SharedConfigurationSourceSecretKey
  1347  `, servicemocks.MockStsAssumeRoleArn, servicemocks.MockStsAssumeRoleSessionName),
  1348  		},
  1349  
  1350  		"from default profile": {
  1351  			config: map[string]any{
  1352  				"assume_role": map[string]any{
  1353  					"role_arn":     servicemocks.MockStsAssumeRoleArn,
  1354  					"session_name": servicemocks.MockStsAssumeRoleSessionName,
  1355  				},
  1356  			},
  1357  			ExpectedCredentialsValue: mockdata.MockStsAssumeRoleCredentials,
  1358  			MockStsEndpoints: []*servicemocks.MockEndpoint{
  1359  				servicemocks.MockStsAssumeRoleValidEndpoint,
  1360  				servicemocks.MockStsGetCallerIdentityValidEndpoint,
  1361  			},
  1362  			SharedCredentialsFile: `
  1363  [default]
  1364  aws_access_key_id = DefaultSharedCredentialsAccessKey
  1365  aws_secret_access_key = DefaultSharedCredentialsSecretKey
  1366  `,
  1367  		},
  1368  
  1369  		"from EC2 metadata": {
  1370  			config: map[string]any{
  1371  				"assume_role": map[string]any{
  1372  					"role_arn":     servicemocks.MockStsAssumeRoleArn,
  1373  					"session_name": servicemocks.MockStsAssumeRoleSessionName,
  1374  				},
  1375  			},
  1376  			EnableEc2MetadataServer:  true,
  1377  			ExpectedCredentialsValue: mockdata.MockStsAssumeRoleCredentials,
  1378  			MockStsEndpoints: []*servicemocks.MockEndpoint{
  1379  				servicemocks.MockStsAssumeRoleValidEndpoint,
  1380  				servicemocks.MockStsGetCallerIdentityValidEndpoint,
  1381  			},
  1382  		},
  1383  
  1384  		"from ECS credentials": {
  1385  			config: map[string]any{
  1386  				"assume_role": map[string]any{
  1387  					"role_arn":     servicemocks.MockStsAssumeRoleArn,
  1388  					"session_name": servicemocks.MockStsAssumeRoleSessionName,
  1389  				},
  1390  			},
  1391  			EnableEcsCredentialsServer: true,
  1392  			ExpectedCredentialsValue:   mockdata.MockStsAssumeRoleCredentials,
  1393  			MockStsEndpoints: []*servicemocks.MockEndpoint{
  1394  				servicemocks.MockStsAssumeRoleValidEndpoint,
  1395  				servicemocks.MockStsGetCallerIdentityValidEndpoint,
  1396  			},
  1397  		},
  1398  
  1399  		"with duration": {
  1400  			config: map[string]any{
  1401  				"access_key": servicemocks.MockStaticAccessKey,
  1402  				"secret_key": servicemocks.MockStaticSecretKey,
  1403  				"assume_role": map[string]any{
  1404  					"role_arn":     servicemocks.MockStsAssumeRoleArn,
  1405  					"session_name": servicemocks.MockStsAssumeRoleSessionName,
  1406  					"duration":     "1h",
  1407  				},
  1408  			},
  1409  			ExpectedCredentialsValue: mockdata.MockStsAssumeRoleCredentials,
  1410  			MockStsEndpoints: []*servicemocks.MockEndpoint{
  1411  				servicemocks.MockStsAssumeRoleValidEndpointWithOptions(map[string]string{"DurationSeconds": "3600"}),
  1412  				servicemocks.MockStsGetCallerIdentityValidEndpoint,
  1413  			},
  1414  		},
  1415  
  1416  		"with external ID": {
  1417  			config: map[string]any{
  1418  				"access_key": servicemocks.MockStaticAccessKey,
  1419  				"secret_key": servicemocks.MockStaticSecretKey,
  1420  				"assume_role": map[string]any{
  1421  					"role_arn":     servicemocks.MockStsAssumeRoleArn,
  1422  					"session_name": servicemocks.MockStsAssumeRoleSessionName,
  1423  					"external_id":  servicemocks.MockStsAssumeRoleExternalId,
  1424  				},
  1425  			},
  1426  			ExpectedCredentialsValue: mockdata.MockStsAssumeRoleCredentials,
  1427  			MockStsEndpoints: []*servicemocks.MockEndpoint{
  1428  				servicemocks.MockStsAssumeRoleValidEndpointWithOptions(map[string]string{"ExternalId": servicemocks.MockStsAssumeRoleExternalId}),
  1429  				servicemocks.MockStsGetCallerIdentityValidEndpoint,
  1430  			},
  1431  		},
  1432  
  1433  		"with policy": {
  1434  			config: map[string]any{
  1435  				"access_key": servicemocks.MockStaticAccessKey,
  1436  				"secret_key": servicemocks.MockStaticSecretKey,
  1437  				"assume_role": map[string]any{
  1438  					"role_arn":     servicemocks.MockStsAssumeRoleArn,
  1439  					"session_name": servicemocks.MockStsAssumeRoleSessionName,
  1440  					"policy":       mockStsAssumeRolePolicy,
  1441  				},
  1442  			},
  1443  			ExpectedCredentialsValue: mockdata.MockStsAssumeRoleCredentials,
  1444  			MockStsEndpoints: []*servicemocks.MockEndpoint{
  1445  				servicemocks.MockStsAssumeRoleValidEndpointWithOptions(map[string]string{"Policy": mockStsAssumeRolePolicy}),
  1446  				servicemocks.MockStsGetCallerIdentityValidEndpoint,
  1447  			},
  1448  		},
  1449  
  1450  		"with policy ARNs": {
  1451  			config: map[string]any{
  1452  				"access_key": servicemocks.MockStaticAccessKey,
  1453  				"secret_key": servicemocks.MockStaticSecretKey,
  1454  				"assume_role": map[string]any{
  1455  					"role_arn":     servicemocks.MockStsAssumeRoleArn,
  1456  					"session_name": servicemocks.MockStsAssumeRoleSessionName,
  1457  					"policy_arns":  []any{servicemocks.MockStsAssumeRolePolicyArn},
  1458  				},
  1459  			},
  1460  			ExpectedCredentialsValue: mockdata.MockStsAssumeRoleCredentials,
  1461  			MockStsEndpoints: []*servicemocks.MockEndpoint{
  1462  				servicemocks.MockStsAssumeRoleValidEndpointWithOptions(map[string]string{"PolicyArns.member.1.arn": servicemocks.MockStsAssumeRolePolicyArn}),
  1463  				servicemocks.MockStsGetCallerIdentityValidEndpoint,
  1464  			},
  1465  		},
  1466  
  1467  		"with tags": {
  1468  			config: map[string]any{
  1469  				"access_key": servicemocks.MockStaticAccessKey,
  1470  				"secret_key": servicemocks.MockStaticSecretKey,
  1471  				"assume_role": map[string]any{
  1472  					"role_arn":     servicemocks.MockStsAssumeRoleArn,
  1473  					"session_name": servicemocks.MockStsAssumeRoleSessionName,
  1474  					"tags": map[string]any{
  1475  						servicemocks.MockStsAssumeRoleTagKey: servicemocks.MockStsAssumeRoleTagValue,
  1476  					},
  1477  				},
  1478  			},
  1479  			ExpectedCredentialsValue: mockdata.MockStsAssumeRoleCredentials,
  1480  			MockStsEndpoints: []*servicemocks.MockEndpoint{
  1481  				servicemocks.MockStsAssumeRoleValidEndpointWithOptions(map[string]string{"Tags.member.1.Key": servicemocks.MockStsAssumeRoleTagKey, "Tags.member.1.Value": servicemocks.MockStsAssumeRoleTagValue}),
  1482  				servicemocks.MockStsGetCallerIdentityValidEndpoint,
  1483  			},
  1484  		},
  1485  
  1486  		"with transitive tags": {
  1487  			config: map[string]any{
  1488  				"access_key": servicemocks.MockStaticAccessKey,
  1489  				"secret_key": servicemocks.MockStaticSecretKey,
  1490  				"assume_role": map[string]any{
  1491  					"role_arn":     servicemocks.MockStsAssumeRoleArn,
  1492  					"session_name": servicemocks.MockStsAssumeRoleSessionName,
  1493  					"tags": map[string]any{
  1494  						servicemocks.MockStsAssumeRoleTagKey: servicemocks.MockStsAssumeRoleTagValue,
  1495  					},
  1496  					"transitive_tag_keys": []any{servicemocks.MockStsAssumeRoleTagKey},
  1497  				},
  1498  			},
  1499  			ExpectedCredentialsValue: mockdata.MockStsAssumeRoleCredentials,
  1500  			MockStsEndpoints: []*servicemocks.MockEndpoint{
  1501  				servicemocks.MockStsAssumeRoleValidEndpointWithOptions(map[string]string{"Tags.member.1.Key": servicemocks.MockStsAssumeRoleTagKey, "Tags.member.1.Value": servicemocks.MockStsAssumeRoleTagValue, "TransitiveTagKeys.member.1": servicemocks.MockStsAssumeRoleTagKey}),
  1502  				servicemocks.MockStsGetCallerIdentityValidEndpoint,
  1503  			},
  1504  		},
  1505  
  1506  		"error": {
  1507  			config: map[string]any{
  1508  				"access_key": servicemocks.MockStaticAccessKey,
  1509  				"secret_key": servicemocks.MockStaticSecretKey,
  1510  				"assume_role": map[string]any{
  1511  					"role_arn":     servicemocks.MockStsAssumeRoleArn,
  1512  					"session_name": servicemocks.MockStsAssumeRoleSessionName,
  1513  				},
  1514  			},
  1515  			MockStsEndpoints: []*servicemocks.MockEndpoint{
  1516  				servicemocks.MockStsAssumeRoleInvalidEndpointInvalidClientTokenId,
  1517  				servicemocks.MockStsGetCallerIdentityValidEndpoint,
  1518  			},
  1519  			ValidateDiags: ExpectDiagsMatching(
  1520  				tfdiags.Error,
  1521  				equalsMatcher("Cannot assume IAM Role"),
  1522  				noopMatcher{},
  1523  			),
  1524  		},
  1525  	}
  1526  
  1527  	for name, tc := range testCases {
  1528  		tc := tc
  1529  
  1530  		t.Run(name, func(t *testing.T) {
  1531  			servicemocks.InitSessionTestEnv(t)
  1532  
  1533  			ctx := context.TODO()
  1534  
  1535  			// Populate required fields
  1536  			tc.config["region"] = "us-east-1"
  1537  			tc.config["bucket"] = "bucket"
  1538  			tc.config["key"] = "key"
  1539  
  1540  			if tc.ValidateDiags == nil {
  1541  				tc.ValidateDiags = ExpectNoDiags
  1542  			}
  1543  
  1544  			if tc.EnableEc2MetadataServer {
  1545  				closeEc2Metadata := servicemocks.AwsMetadataApiMock(append(
  1546  					servicemocks.Ec2metadata_securityCredentialsEndpoints,
  1547  					servicemocks.Ec2metadata_instanceIdEndpoint,
  1548  					servicemocks.Ec2metadata_iamInfoEndpoint,
  1549  				))
  1550  				defer closeEc2Metadata()
  1551  			}
  1552  
  1553  			if tc.EnableEcsCredentialsServer {
  1554  				closeEcsCredentials := servicemocks.EcsCredentialsApiMock()
  1555  				defer closeEcsCredentials()
  1556  			}
  1557  
  1558  			ts := servicemocks.MockAwsApiServer("STS", tc.MockStsEndpoints)
  1559  			defer ts.Close()
  1560  
  1561  			tc.config["sts_endpoint"] = ts.URL
  1562  
  1563  			if tc.SharedConfigurationFile != "" {
  1564  				file, err := os.CreateTemp("", "aws-sdk-go-base-shared-configuration-file")
  1565  
  1566  				if err != nil {
  1567  					t.Fatalf("unexpected error creating temporary shared configuration file: %s", err)
  1568  				}
  1569  
  1570  				defer os.Remove(file.Name())
  1571  
  1572  				err = os.WriteFile(file.Name(), []byte(tc.SharedConfigurationFile), 0600)
  1573  
  1574  				if err != nil {
  1575  					t.Fatalf("unexpected error writing shared configuration file: %s", err)
  1576  				}
  1577  
  1578  				setSharedConfigFile(t, file.Name())
  1579  			}
  1580  
  1581  			if tc.SharedCredentialsFile != "" {
  1582  				file, err := os.CreateTemp("", "aws-sdk-go-base-shared-credentials-file")
  1583  
  1584  				if err != nil {
  1585  					t.Fatalf("unexpected error creating temporary shared credentials file: %s", err)
  1586  				}
  1587  
  1588  				defer os.Remove(file.Name())
  1589  
  1590  				err = os.WriteFile(file.Name(), []byte(tc.SharedCredentialsFile), 0600)
  1591  
  1592  				if err != nil {
  1593  					t.Fatalf("unexpected error writing shared credentials file: %s", err)
  1594  				}
  1595  
  1596  				tc.config["shared_credentials_files"] = []any{file.Name()}
  1597  				if tc.ExpectedCredentialsValue.Source == "SharedConfigCredentials" {
  1598  					tc.ExpectedCredentialsValue.Source = fmt.Sprintf("SharedConfigCredentials: %s", file.Name())
  1599  				}
  1600  
  1601  				tc.config["shared_config_files"] = []any{file.Name()}
  1602  			}
  1603  
  1604  			for k, v := range tc.EnvironmentVariables {
  1605  				t.Setenv(k, v)
  1606  			}
  1607  
  1608  			b, diags := configureBackend(t, tc.config)
  1609  
  1610  			tc.ValidateDiags(t, diags)
  1611  
  1612  			if diags.HasErrors() {
  1613  				return
  1614  			}
  1615  
  1616  			credentials, err := b.awsConfig.Credentials.Retrieve(ctx)
  1617  			if err != nil {
  1618  				t.Fatalf("Error when requesting credentials: %s", err)
  1619  			}
  1620  
  1621  			if diff := cmp.Diff(credentials, tc.ExpectedCredentialsValue, cmpopts.IgnoreFields(aws.Credentials{}, "Expires")); diff != "" {
  1622  				t.Fatalf("unexpected credentials: (- got, + expected)\n%s", diff)
  1623  			}
  1624  		})
  1625  	}
  1626  }
  1627  
  1628  func TestBackendConfig_Authentication_AssumeRoleWithWebIdentity(t *testing.T) {
  1629  	testCases := map[string]struct {
  1630  		config                          map[string]any
  1631  		SetConfig                       bool
  1632  		ExpandEnvVars                   bool
  1633  		EnvironmentVariables            map[string]string
  1634  		SetTokenFileEnvironmentVariable bool
  1635  		SharedConfigurationFile         string
  1636  		SetSharedConfigurationFile      bool
  1637  		ExpectedCredentialsValue        aws.Credentials
  1638  		ValidateDiags                   diagsValidator
  1639  		MockStsEndpoints                []*servicemocks.MockEndpoint
  1640  	}{
  1641  		"config with inline token": {
  1642  			config: map[string]any{
  1643  				"assume_role_with_web_identity": map[string]any{
  1644  					"role_arn":           servicemocks.MockStsAssumeRoleWithWebIdentityArn,
  1645  					"session_name":       servicemocks.MockStsAssumeRoleWithWebIdentitySessionName,
  1646  					"web_identity_token": servicemocks.MockWebIdentityToken,
  1647  				},
  1648  			},
  1649  			ExpectedCredentialsValue: mockdata.MockStsAssumeRoleWithWebIdentityCredentials,
  1650  			MockStsEndpoints: []*servicemocks.MockEndpoint{
  1651  				servicemocks.MockStsAssumeRoleWithWebIdentityValidEndpoint,
  1652  			},
  1653  		},
  1654  
  1655  		"config with token file": {
  1656  			config: map[string]any{
  1657  				"assume_role_with_web_identity": map[string]any{
  1658  					"role_arn":     servicemocks.MockStsAssumeRoleWithWebIdentityArn,
  1659  					"session_name": servicemocks.MockStsAssumeRoleWithWebIdentitySessionName,
  1660  				},
  1661  			},
  1662  			SetConfig:                true,
  1663  			ExpectedCredentialsValue: mockdata.MockStsAssumeRoleWithWebIdentityCredentials,
  1664  			MockStsEndpoints: []*servicemocks.MockEndpoint{
  1665  				servicemocks.MockStsAssumeRoleWithWebIdentityValidEndpoint,
  1666  			},
  1667  		},
  1668  
  1669  		"config with expanded path": {
  1670  			config: map[string]any{
  1671  				"assume_role_with_web_identity": map[string]any{
  1672  					"role_arn":     servicemocks.MockStsAssumeRoleWithWebIdentityArn,
  1673  					"session_name": servicemocks.MockStsAssumeRoleWithWebIdentitySessionName,
  1674  				},
  1675  			},
  1676  			SetConfig:                true,
  1677  			ExpandEnvVars:            true,
  1678  			ExpectedCredentialsValue: mockdata.MockStsAssumeRoleWithWebIdentityCredentials,
  1679  			MockStsEndpoints: []*servicemocks.MockEndpoint{
  1680  				servicemocks.MockStsAssumeRoleWithWebIdentityValidEndpoint,
  1681  			},
  1682  		},
  1683  
  1684  		"envvar": {
  1685  			config: map[string]any{},
  1686  			EnvironmentVariables: map[string]string{
  1687  				"AWS_ROLE_ARN":          servicemocks.MockStsAssumeRoleWithWebIdentityArn,
  1688  				"AWS_ROLE_SESSION_NAME": servicemocks.MockStsAssumeRoleWithWebIdentitySessionName,
  1689  			},
  1690  			SetTokenFileEnvironmentVariable: true,
  1691  			ExpectedCredentialsValue:        mockdata.MockStsAssumeRoleWithWebIdentityCredentials,
  1692  			MockStsEndpoints: []*servicemocks.MockEndpoint{
  1693  				servicemocks.MockStsAssumeRoleWithWebIdentityValidEndpoint,
  1694  			},
  1695  		},
  1696  
  1697  		"shared configuration file": {
  1698  			config: map[string]any{},
  1699  			SharedConfigurationFile: fmt.Sprintf(`
  1700  [default]
  1701  role_arn = %[1]s
  1702  role_session_name = %[2]s
  1703  `, servicemocks.MockStsAssumeRoleWithWebIdentityArn, servicemocks.MockStsAssumeRoleWithWebIdentitySessionName),
  1704  			SetSharedConfigurationFile: true,
  1705  			ExpectedCredentialsValue:   mockdata.MockStsAssumeRoleWithWebIdentityCredentials,
  1706  			MockStsEndpoints: []*servicemocks.MockEndpoint{
  1707  				servicemocks.MockStsAssumeRoleWithWebIdentityValidEndpoint,
  1708  			},
  1709  		},
  1710  
  1711  		"config overrides envvar": {
  1712  			config: map[string]any{
  1713  				"assume_role_with_web_identity": map[string]any{
  1714  					"role_arn":           servicemocks.MockStsAssumeRoleWithWebIdentityArn,
  1715  					"session_name":       servicemocks.MockStsAssumeRoleWithWebIdentitySessionName,
  1716  					"web_identity_token": servicemocks.MockWebIdentityToken,
  1717  				},
  1718  			},
  1719  			EnvironmentVariables: map[string]string{
  1720  				"AWS_ROLE_ARN":                servicemocks.MockStsAssumeRoleWithWebIdentityAlternateArn,
  1721  				"AWS_ROLE_SESSION_NAME":       servicemocks.MockStsAssumeRoleWithWebIdentityAlternateSessionName,
  1722  				"AWS_WEB_IDENTITY_TOKEN_FILE": "no-such-file",
  1723  			},
  1724  			ExpectedCredentialsValue: mockdata.MockStsAssumeRoleWithWebIdentityCredentials,
  1725  			MockStsEndpoints: []*servicemocks.MockEndpoint{
  1726  				servicemocks.MockStsAssumeRoleWithWebIdentityValidEndpoint,
  1727  			},
  1728  		},
  1729  
  1730  		"envvar overrides shared configuration": {
  1731  			config: map[string]any{},
  1732  			EnvironmentVariables: map[string]string{
  1733  				"AWS_ROLE_ARN":          servicemocks.MockStsAssumeRoleWithWebIdentityArn,
  1734  				"AWS_ROLE_SESSION_NAME": servicemocks.MockStsAssumeRoleWithWebIdentitySessionName,
  1735  			},
  1736  			SetTokenFileEnvironmentVariable: true,
  1737  			SharedConfigurationFile: fmt.Sprintf(`
  1738  [default]
  1739  role_arn = %[1]s
  1740  role_session_name = %[2]s
  1741  web_identity_token_file = no-such-file
  1742  `, servicemocks.MockStsAssumeRoleWithWebIdentityAlternateArn, servicemocks.MockStsAssumeRoleWithWebIdentityAlternateSessionName),
  1743  			ExpectedCredentialsValue: mockdata.MockStsAssumeRoleWithWebIdentityCredentials,
  1744  			MockStsEndpoints: []*servicemocks.MockEndpoint{
  1745  				servicemocks.MockStsAssumeRoleWithWebIdentityValidEndpoint,
  1746  			},
  1747  		},
  1748  
  1749  		"config overrides shared configuration": {
  1750  			config: map[string]any{
  1751  				"assume_role_with_web_identity": map[string]any{
  1752  					"role_arn":           servicemocks.MockStsAssumeRoleWithWebIdentityArn,
  1753  					"session_name":       servicemocks.MockStsAssumeRoleWithWebIdentitySessionName,
  1754  					"web_identity_token": servicemocks.MockWebIdentityToken,
  1755  				},
  1756  			},
  1757  			SharedConfigurationFile: fmt.Sprintf(`
  1758  [default]
  1759  role_arn = %[1]s
  1760  role_session_name = %[2]s
  1761  web_identity_token_file = no-such-file
  1762  `, servicemocks.MockStsAssumeRoleWithWebIdentityAlternateArn, servicemocks.MockStsAssumeRoleWithWebIdentityAlternateSessionName),
  1763  			ExpectedCredentialsValue: mockdata.MockStsAssumeRoleWithWebIdentityCredentials,
  1764  			MockStsEndpoints: []*servicemocks.MockEndpoint{
  1765  				servicemocks.MockStsAssumeRoleWithWebIdentityValidEndpoint,
  1766  			},
  1767  		},
  1768  
  1769  		"with duration": {
  1770  			config: map[string]any{
  1771  				"assume_role_with_web_identity": map[string]any{
  1772  					"role_arn":           servicemocks.MockStsAssumeRoleWithWebIdentityArn,
  1773  					"session_name":       servicemocks.MockStsAssumeRoleWithWebIdentitySessionName,
  1774  					"web_identity_token": servicemocks.MockWebIdentityToken,
  1775  					"duration":           "1h",
  1776  				},
  1777  			},
  1778  			ExpectedCredentialsValue: mockdata.MockStsAssumeRoleWithWebIdentityCredentials,
  1779  			MockStsEndpoints: []*servicemocks.MockEndpoint{
  1780  				servicemocks.MockStsAssumeRoleWithWebIdentityValidWithOptions(map[string]string{"DurationSeconds": "3600"}),
  1781  			},
  1782  		},
  1783  
  1784  		"with policy": {
  1785  			config: map[string]any{
  1786  				"assume_role_with_web_identity": map[string]any{
  1787  					"role_arn":           servicemocks.MockStsAssumeRoleWithWebIdentityArn,
  1788  					"session_name":       servicemocks.MockStsAssumeRoleWithWebIdentitySessionName,
  1789  					"web_identity_token": servicemocks.MockWebIdentityToken,
  1790  					"policy":             "{}",
  1791  				},
  1792  			},
  1793  			ExpectedCredentialsValue: mockdata.MockStsAssumeRoleWithWebIdentityCredentials,
  1794  			MockStsEndpoints: []*servicemocks.MockEndpoint{
  1795  				servicemocks.MockStsAssumeRoleWithWebIdentityValidWithOptions(map[string]string{"Policy": "{}"}),
  1796  			},
  1797  		},
  1798  	}
  1799  
  1800  	for name, tc := range testCases {
  1801  		tc := tc
  1802  
  1803  		t.Run(name, func(t *testing.T) {
  1804  			servicemocks.InitSessionTestEnv(t)
  1805  
  1806  			ctx := context.TODO()
  1807  
  1808  			// Populate required fields
  1809  			tc.config["region"] = "us-east-1"
  1810  			tc.config["bucket"] = "bucket"
  1811  			tc.config["key"] = "key"
  1812  
  1813  			if tc.ValidateDiags == nil {
  1814  				tc.ValidateDiags = ExpectNoDiags
  1815  			}
  1816  
  1817  			for k, v := range tc.EnvironmentVariables {
  1818  				t.Setenv(k, v)
  1819  			}
  1820  
  1821  			ts := servicemocks.MockAwsApiServer("STS", tc.MockStsEndpoints)
  1822  			defer ts.Close()
  1823  
  1824  			tc.config["sts_endpoint"] = ts.URL
  1825  
  1826  			t.Setenv("TMPDIR", t.TempDir())
  1827  
  1828  			tokenFile, err := os.CreateTemp("", "aws-sdk-go-base-web-identity-token-file")
  1829  			if err != nil {
  1830  				t.Fatalf("unexpected error creating temporary web identity token file: %s", err)
  1831  			}
  1832  			tokenFileName := tokenFile.Name()
  1833  
  1834  			defer os.Remove(tokenFileName)
  1835  
  1836  			err = os.WriteFile(tokenFileName, []byte(servicemocks.MockWebIdentityToken), 0600)
  1837  
  1838  			if err != nil {
  1839  				t.Fatalf("unexpected error writing web identity token file: %s", err)
  1840  			}
  1841  
  1842  			if tc.ExpandEnvVars {
  1843  				tmpdir := os.Getenv("TMPDIR")
  1844  				rel, err := filepath.Rel(tmpdir, tokenFileName)
  1845  				if err != nil {
  1846  					t.Fatalf("error making path relative: %s", err)
  1847  				}
  1848  				t.Logf("relative: %s", rel)
  1849  				tokenFileName = filepath.Join("$TMPDIR", rel)
  1850  				t.Logf("env tempfile: %s", tokenFileName)
  1851  			}
  1852  
  1853  			if tc.SetConfig {
  1854  				ar := tc.config["assume_role_with_web_identity"].(map[string]any)
  1855  				ar["web_identity_token_file"] = tokenFileName
  1856  			}
  1857  
  1858  			if tc.SetTokenFileEnvironmentVariable {
  1859  				t.Setenv("AWS_WEB_IDENTITY_TOKEN_FILE", tokenFileName)
  1860  			}
  1861  
  1862  			if tc.SharedConfigurationFile != "" {
  1863  				file, err := os.CreateTemp("", "aws-sdk-go-base-shared-configuration-file")
  1864  
  1865  				if err != nil {
  1866  					t.Fatalf("unexpected error creating temporary shared configuration file: %s", err)
  1867  				}
  1868  
  1869  				defer os.Remove(file.Name())
  1870  
  1871  				if tc.SetSharedConfigurationFile {
  1872  					tc.SharedConfigurationFile += fmt.Sprintf("web_identity_token_file = %s\n", tokenFileName)
  1873  				}
  1874  
  1875  				err = os.WriteFile(file.Name(), []byte(tc.SharedConfigurationFile), 0600)
  1876  
  1877  				if err != nil {
  1878  					t.Fatalf("unexpected error writing shared configuration file: %s", err)
  1879  				}
  1880  
  1881  				tc.config["shared_config_files"] = []any{file.Name()}
  1882  			}
  1883  
  1884  			tc.config["skip_credentials_validation"] = true
  1885  
  1886  			b, diags := configureBackend(t, tc.config)
  1887  
  1888  			tc.ValidateDiags(t, diags)
  1889  
  1890  			if diags.HasErrors() {
  1891  				return
  1892  			}
  1893  
  1894  			credentials, err := b.awsConfig.Credentials.Retrieve(ctx)
  1895  			if err != nil {
  1896  				t.Fatalf("Error when requesting credentials: %s", err)
  1897  			}
  1898  
  1899  			if diff := cmp.Diff(credentials, tc.ExpectedCredentialsValue, cmpopts.IgnoreFields(aws.Credentials{}, "Expires")); diff != "" {
  1900  				t.Fatalf("unexpected credentials: (- got, + expected)\n%s", diff)
  1901  			}
  1902  		})
  1903  	}
  1904  }
  1905  
  1906  func TestBackendConfig_Region(t *testing.T) {
  1907  	testCases := map[string]struct {
  1908  		config                  map[string]any
  1909  		EnvironmentVariables    map[string]string
  1910  		IMDSRegion              string
  1911  		SharedConfigurationFile string
  1912  		ExpectedRegion          string
  1913  	}{
  1914  		// NOT SUPPORTED: region is required
  1915  		// "no configuration": {
  1916  		// 	config: map[string]any{
  1917  		// 		"access_key": servicemocks.MockStaticAccessKey,
  1918  		// 		"secret_key": servicemocks.MockStaticSecretKey,
  1919  		// 	},
  1920  		// 	ExpectedRegion: "",
  1921  		// },
  1922  
  1923  		"config": {
  1924  			config: map[string]any{
  1925  				"access_key": servicemocks.MockStaticAccessKey,
  1926  				"secret_key": servicemocks.MockStaticSecretKey,
  1927  				"region":     "us-east-1",
  1928  			},
  1929  			ExpectedRegion: "us-east-1",
  1930  		},
  1931  
  1932  		"AWS_REGION": {
  1933  			config: map[string]any{
  1934  				"access_key": servicemocks.MockStaticAccessKey,
  1935  				"secret_key": servicemocks.MockStaticSecretKey,
  1936  			},
  1937  			EnvironmentVariables: map[string]string{
  1938  				"AWS_REGION": "us-east-1",
  1939  			},
  1940  			ExpectedRegion: "us-east-1",
  1941  		},
  1942  		"AWS_DEFAULT_REGION": {
  1943  			config: map[string]any{
  1944  				"access_key": servicemocks.MockStaticAccessKey,
  1945  				"secret_key": servicemocks.MockStaticSecretKey,
  1946  			},
  1947  			EnvironmentVariables: map[string]string{
  1948  				"AWS_DEFAULT_REGION": "us-east-1",
  1949  			},
  1950  			ExpectedRegion: "us-east-1",
  1951  		},
  1952  		"AWS_REGION overrides AWS_DEFAULT_REGION": {
  1953  			config: map[string]any{
  1954  				"access_key": servicemocks.MockStaticAccessKey,
  1955  				"secret_key": servicemocks.MockStaticSecretKey,
  1956  			},
  1957  			EnvironmentVariables: map[string]string{
  1958  				"AWS_REGION":         "us-east-1",
  1959  				"AWS_DEFAULT_REGION": "us-west-2",
  1960  			},
  1961  			ExpectedRegion: "us-east-1",
  1962  		},
  1963  
  1964  		// NOT SUPPORTED: region from shared configuration file
  1965  		// 		"shared configuration file": {
  1966  		// 			config: map[string]any{
  1967  		// 				"access_key": servicemocks.MockStaticAccessKey,
  1968  		// 				"secret_key": servicemocks.MockStaticSecretKey,
  1969  		// 			},
  1970  		// 			SharedConfigurationFile: `
  1971  		// [default]
  1972  		// region = us-east-1
  1973  		// `,
  1974  		// 			ExpectedRegion: "us-east-1",
  1975  		// 		},
  1976  
  1977  		// NOT SUPPORTED: region from IMDS
  1978  		// "IMDS": {
  1979  		// 	config:         map[string]any{},
  1980  		// 	IMDSRegion:     "us-east-1",
  1981  		// 	ExpectedRegion: "us-east-1",
  1982  		// },
  1983  
  1984  		"config overrides AWS_REGION": {
  1985  			config: map[string]any{
  1986  				"access_key": servicemocks.MockStaticAccessKey,
  1987  				"secret_key": servicemocks.MockStaticSecretKey,
  1988  				"region":     "us-east-1",
  1989  			},
  1990  			EnvironmentVariables: map[string]string{
  1991  				"AWS_REGION": "us-west-2",
  1992  			},
  1993  			ExpectedRegion: "us-east-1",
  1994  		},
  1995  		"config overrides AWS_DEFAULT_REGION": {
  1996  			config: map[string]any{
  1997  				"access_key": servicemocks.MockStaticAccessKey,
  1998  				"secret_key": servicemocks.MockStaticSecretKey,
  1999  				"region":     "us-east-1",
  2000  			},
  2001  			EnvironmentVariables: map[string]string{
  2002  				"AWS_DEFAULT_REGION": "us-west-2",
  2003  			},
  2004  			ExpectedRegion: "us-east-1",
  2005  		},
  2006  
  2007  		"config overrides IMDS": {
  2008  			config: map[string]any{
  2009  				"access_key": servicemocks.MockStaticAccessKey,
  2010  				"secret_key": servicemocks.MockStaticSecretKey,
  2011  				"region":     "us-west-2",
  2012  			},
  2013  			IMDSRegion:     "us-east-1",
  2014  			ExpectedRegion: "us-west-2",
  2015  		},
  2016  
  2017  		"AWS_REGION overrides shared configuration": {
  2018  			config: map[string]any{
  2019  				"access_key": servicemocks.MockStaticAccessKey,
  2020  				"secret_key": servicemocks.MockStaticSecretKey,
  2021  			},
  2022  			EnvironmentVariables: map[string]string{
  2023  				"AWS_REGION": "us-east-1",
  2024  			},
  2025  			SharedConfigurationFile: `
  2026  [default]
  2027  region = us-west-2
  2028  `,
  2029  			ExpectedRegion: "us-east-1",
  2030  		},
  2031  		"AWS_DEFAULT_REGION overrides shared configuration": {
  2032  			config: map[string]any{
  2033  				"access_key": servicemocks.MockStaticAccessKey,
  2034  				"secret_key": servicemocks.MockStaticSecretKey,
  2035  			},
  2036  			EnvironmentVariables: map[string]string{
  2037  				"AWS_DEFAULT_REGION": "us-east-1",
  2038  			},
  2039  			SharedConfigurationFile: `
  2040  [default]
  2041  region = us-west-2
  2042  `,
  2043  			ExpectedRegion: "us-east-1",
  2044  		},
  2045  
  2046  		"AWS_REGION overrides IMDS": {
  2047  			config: map[string]any{
  2048  				"access_key": servicemocks.MockStaticAccessKey,
  2049  				"secret_key": servicemocks.MockStaticSecretKey,
  2050  			},
  2051  			EnvironmentVariables: map[string]string{
  2052  				"AWS_REGION": "us-east-1",
  2053  			},
  2054  			IMDSRegion:     "us-west-2",
  2055  			ExpectedRegion: "us-east-1",
  2056  		},
  2057  	}
  2058  
  2059  	for name, tc := range testCases {
  2060  		tc := tc
  2061  
  2062  		t.Run(name, func(t *testing.T) {
  2063  			servicemocks.InitSessionTestEnv(t)
  2064  
  2065  			// Populate required fields
  2066  			tc.config["bucket"] = "bucket"
  2067  			tc.config["key"] = "key"
  2068  
  2069  			for k, v := range tc.EnvironmentVariables {
  2070  				t.Setenv(k, v)
  2071  			}
  2072  
  2073  			if tc.IMDSRegion != "" {
  2074  				closeEc2Metadata := servicemocks.AwsMetadataApiMock(append(
  2075  					servicemocks.Ec2metadata_securityCredentialsEndpoints,
  2076  					servicemocks.Ec2metadata_instanceIdEndpoint,
  2077  					servicemocks.Ec2metadata_iamInfoEndpoint,
  2078  					servicemocks.Ec2metadata_instanceIdentityEndpoint(tc.IMDSRegion),
  2079  				))
  2080  				defer closeEc2Metadata()
  2081  			}
  2082  
  2083  			sts := servicemocks.MockAwsApiServer("STS", []*servicemocks.MockEndpoint{
  2084  				servicemocks.MockStsGetCallerIdentityValidEndpoint,
  2085  			})
  2086  			defer sts.Close()
  2087  
  2088  			tc.config["sts_endpoint"] = sts.URL
  2089  
  2090  			if tc.SharedConfigurationFile != "" {
  2091  				file, err := os.CreateTemp("", "aws-sdk-go-base-shared-configuration-file")
  2092  
  2093  				if err != nil {
  2094  					t.Fatalf("unexpected error creating temporary shared configuration file: %s", err)
  2095  				}
  2096  
  2097  				defer os.Remove(file.Name())
  2098  
  2099  				err = os.WriteFile(file.Name(), []byte(tc.SharedConfigurationFile), 0600)
  2100  
  2101  				if err != nil {
  2102  					t.Fatalf("unexpected error writing shared configuration file: %s", err)
  2103  				}
  2104  
  2105  				setSharedConfigFile(t, file.Name())
  2106  			}
  2107  
  2108  			tc.config["skip_credentials_validation"] = true
  2109  
  2110  			b, diags := configureBackend(t, tc.config)
  2111  			if diags.HasErrors() {
  2112  				t.Fatalf("configuring backend: %s", diagnosticsString(diags))
  2113  			}
  2114  
  2115  			if a, e := b.awsConfig.Region, tc.ExpectedRegion; a != e {
  2116  				t.Errorf("expected Region %q, got: %q", e, a)
  2117  			}
  2118  		})
  2119  	}
  2120  }
  2121  
  2122  func TestBackendConfig_RetryMode(t *testing.T) {
  2123  	testCases := map[string]struct {
  2124  		config               map[string]any
  2125  		EnvironmentVariables map[string]string
  2126  		ExpectedMode         aws.RetryMode
  2127  	}{
  2128  		"no config": {
  2129  			config: map[string]any{
  2130  				"access_key": servicemocks.MockStaticAccessKey,
  2131  				"secret_key": servicemocks.MockStaticSecretKey,
  2132  			},
  2133  			ExpectedMode: "",
  2134  		},
  2135  
  2136  		"config": {
  2137  			config: map[string]any{
  2138  				"access_key": servicemocks.MockStaticAccessKey,
  2139  				"secret_key": servicemocks.MockStaticSecretKey,
  2140  				"retry_mode": "standard",
  2141  			},
  2142  			ExpectedMode: aws.RetryModeStandard,
  2143  		},
  2144  
  2145  		"AWS_RETRY_MODE": {
  2146  			config: map[string]any{
  2147  				"access_key": servicemocks.MockStaticAccessKey,
  2148  				"secret_key": servicemocks.MockStaticSecretKey,
  2149  			},
  2150  			EnvironmentVariables: map[string]string{
  2151  				"AWS_RETRY_MODE": "adaptive",
  2152  			},
  2153  			ExpectedMode: aws.RetryModeAdaptive,
  2154  		},
  2155  		"config overrides AWS_RETRY_MODE": {
  2156  			config: map[string]any{
  2157  				"access_key": servicemocks.MockStaticAccessKey,
  2158  				"secret_key": servicemocks.MockStaticSecretKey,
  2159  				"retry_mode": "standard",
  2160  			},
  2161  			EnvironmentVariables: map[string]string{
  2162  				"AWS_RETRY_MODE": "adaptive",
  2163  			},
  2164  			ExpectedMode: aws.RetryModeStandard,
  2165  		},
  2166  	}
  2167  
  2168  	for name, tc := range testCases {
  2169  		tc := tc
  2170  
  2171  		t.Run(name, func(t *testing.T) {
  2172  			servicemocks.InitSessionTestEnv(t)
  2173  
  2174  			// Populate required fields
  2175  			tc.config["bucket"] = "bucket"
  2176  			tc.config["key"] = "key"
  2177  			tc.config["region"] = "us-east-1"
  2178  
  2179  			for k, v := range tc.EnvironmentVariables {
  2180  				t.Setenv(k, v)
  2181  			}
  2182  
  2183  			sts := servicemocks.MockAwsApiServer("STS", []*servicemocks.MockEndpoint{
  2184  				servicemocks.MockStsGetCallerIdentityValidEndpoint,
  2185  			})
  2186  			defer sts.Close()
  2187  
  2188  			tc.config["sts_endpoint"] = sts.URL
  2189  			tc.config["skip_credentials_validation"] = true
  2190  
  2191  			b, diags := configureBackend(t, tc.config)
  2192  			if diags.HasErrors() {
  2193  				t.Fatalf("configuring backend: %s", diagnosticsString(diags))
  2194  			}
  2195  
  2196  			if a, e := b.awsConfig.RetryMode, tc.ExpectedMode; a != e {
  2197  				t.Errorf("expected mode %q, got: %q", e, a)
  2198  			}
  2199  		})
  2200  	}
  2201  }
  2202  
  2203  func setSharedConfigFile(t *testing.T, filename string) {
  2204  	t.Helper()
  2205  	t.Setenv("AWS_SDK_LOAD_CONFIG", "1")
  2206  	t.Setenv("AWS_CONFIG_FILE", filename)
  2207  }
  2208  
  2209  func configureBackend(t *testing.T, config map[string]any) (*Backend, tfdiags.Diagnostics) {
  2210  	b := New(encryption.StateEncryptionDisabled()).(*Backend)
  2211  	configSchema := populateSchema(t, b.ConfigSchema(), hcl2shim.HCL2ValueFromConfigValue(config))
  2212  
  2213  	configSchema, diags := b.PrepareConfig(configSchema)
  2214  
  2215  	if diags.HasErrors() {
  2216  		return b, diags
  2217  	}
  2218  
  2219  	confDiags := b.Configure(configSchema)
  2220  	diags = diags.Append(confDiags)
  2221  
  2222  	return b, diags
  2223  }