Skip to content

Commit b8e6651

Browse files
Migrate AWS access credentials data source and tests to AWS SDK v2 (#2882)
* Migrate AWS access credentials and auth login code to AWS SDK v2 * Fix flaky retry test and close IMDS response bodies * Fix presigned request handling and test safety issues * address reviewer comments: add timeout contexts, named error constants, wrapped errors * address copilot comments: t.Fatalf, region fallback, region in test config * restore per-constant comments and update region description per reviewer feedback * address review feedback: context handling, error wrapping, test cleanup * fix: return diag.Diagnostics from ReadContext func to satisfy schema.ReadContextFunc * Cleanup comments * upgrade dependency versions * Address review comments: extract newAWSConfig helper and add empty body comment * Add changelog entry * Fix CI: pin vault version to avoid container failure * Fix CI: run Vault manually with IPC_LOCK and fix matrix * Fix Vault startup step indentation and readiness check * Fix invalid YAML formatting * Fix shellcheck warning: rename unused loop variable i to _ * fix: attach Vault container to service network for DNS resolution * AWS SDK v2 migration fixes - Restore build.yml from verified working CI run - Update IAM auth test to use SigV4 signed POST request instead of presigned GET - Remove unused dependency via go mod tidy - Fix changelog entry and minor test formatting * fix: region-specific STS endpoint, Host header, t.Fatalf for nil safety, region ambient config handling, changelog section * fix: make propagation wait cancellable and refine AWS credential validation handling * fix: tidy go modules * chore: run go mod tidy to fix duplicate aws-sdk-go-v2 entries --------- Co-authored-by: Stuti Srivastava <stuti.srivastava@hashicorp.com>
1 parent 18c0690 commit b8e6651

8 files changed

Lines changed: 260 additions & 138 deletions

.github/workflows/build.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -441,4 +441,4 @@ jobs:
441441
run: exit 0
442442
- name: failed
443443
if: ${{ contains(needs.*.result, 'failure') }}
444-
run: exit 1
444+
run: exit 1

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ FEATURES:
3535
IMPROVEMENTS:
3636

3737
* `resource/vault_token`: Added deprecation warning to guide users toward the new ephemeral `vault_token` resource for better security and batch token support. ([#2877](https://github.com/hashicorp/terraform-provider-vault/pull/2877))
38+
* Migrated AWS provider dependency from `aws-sdk-go` (v1) to `aws-sdk-go-v2` for improved performance and maintainability. ([#2882](https://github.com/hashicorp/terraform-provider-vault/pull/2882))
3839
* Replaced backend with mount in `vault_aws_access_credentials` resource's documentation and improved descriptions for a few other parameters.([#2911](https://github.com/hashicorp/terraform-provider-vault/pull/2911))
3940

4041
* Updated dependencies:

go.mod

Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,10 @@ require (
88
github.com/Azure/azure-sdk-for-go/sdk/azcore v1.22.0
99
github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.14.0
1010
github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/resources/armresources v1.2.0
11-
github.com/aws/aws-sdk-go v1.55.8
1211
github.com/aws/aws-sdk-go-v2 v1.42.0
12+
github.com/aws/aws-sdk-go-v2/config v1.32.17
13+
github.com/aws/aws-sdk-go-v2/credentials v1.19.16
14+
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.18.23
1315
github.com/aws/aws-sdk-go-v2/service/iam v1.54.5
1416
github.com/aws/aws-sdk-go-v2/service/sts v1.43.3
1517
github.com/aws/smithy-go v1.27.2
@@ -73,17 +75,14 @@ require (
7375
github.com/apparentlymart/go-textseg/v15 v15.0.0 // indirect
7476
github.com/armon/go-metrics v0.4.1 // indirect
7577
github.com/armon/go-radix v1.0.0 // indirect
76-
github.com/aws/aws-sdk-go-v2/config v1.28.5 // indirect
77-
github.com/aws/aws-sdk-go-v2/credentials v1.17.46 // indirect
78-
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.20 // indirect
7978
github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.29 // indirect
8079
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.29 // indirect
81-
github.com/aws/aws-sdk-go-v2/internal/ini v1.8.1 // indirect
8280
github.com/aws/aws-sdk-go-v2/internal/v4a v1.4.30 // indirect
8381
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.12 // indirect
8482
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.29 // indirect
85-
github.com/aws/aws-sdk-go-v2/service/sso v1.24.6 // indirect
86-
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.28.5 // indirect
83+
github.com/aws/aws-sdk-go-v2/service/signin v1.0.11 // indirect
84+
github.com/aws/aws-sdk-go-v2/service/sso v1.30.17 // indirect
85+
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.35.21 // indirect
8786
github.com/cespare/xxhash/v2 v2.3.0 // indirect
8887
github.com/cloudflare/circl v1.6.3 // indirect
8988
github.com/containerd/errdefs v1.0.0 // indirect
@@ -162,7 +161,6 @@ require (
162161
github.com/jcmturner/gofork v1.7.6 // indirect
163162
github.com/jcmturner/goidentity/v6 v6.0.1 // indirect
164163
github.com/jcmturner/rpc/v2 v2.0.3 // indirect
165-
github.com/jmespath/go-jmespath v0.4.1-0.20220621161143-b0104c826a24 // indirect
166164
github.com/joshlf/go-acl v0.0.0-20200411065538-eae00ae38531 // indirect
167165
github.com/klauspost/compress v1.18.0 // indirect
168166
github.com/kylelemons/godebug v1.1.0 // indirect

go.sum

Lines changed: 12 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -71,22 +71,18 @@ github.com/armon/go-metrics v0.4.1/go.mod h1:E6amYzXo6aW1tqzoZGT755KkbgrJsSdpwZ+
7171
github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8=
7272
github.com/armon/go-radix v1.0.0 h1:F4z6KzEeeQIMeLFa97iZU6vupzoecKdU5TX24SNppXI=
7373
github.com/armon/go-radix v1.0.0/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8=
74-
github.com/aws/aws-sdk-go v1.55.8 h1:JRmEUbU52aJQZ2AjX4q4Wu7t4uZjOu71uyNmaWlUkJQ=
75-
github.com/aws/aws-sdk-go v1.55.8/go.mod h1:ZkViS9AqA6otK+JBBNH2++sx1sgxrPKcSzPPvQkUtXk=
7674
github.com/aws/aws-sdk-go-v2 v1.42.0 h1:XvXMJTkFQtpBKIWZnmr9ZEOc2InWM2yldjXEJ/bymhA=
7775
github.com/aws/aws-sdk-go-v2 v1.42.0/go.mod h1:27+ACypSLljLAEKsCYOmrjKh83vuTRkuAe9Uv/3A4bg=
78-
github.com/aws/aws-sdk-go-v2/config v1.28.5 h1:Za41twdCXbuyyWv9LndXxZZv3QhTG1DinqlFsSuvtI0=
79-
github.com/aws/aws-sdk-go-v2/config v1.28.5/go.mod h1:4VsPbHP8JdcdUDmbTVgNL/8w9SqOkM5jyY8ljIxLO3o=
80-
github.com/aws/aws-sdk-go-v2/credentials v1.17.46 h1:AU7RcriIo2lXjUfHFnFKYsLCwgbz1E7Mm95ieIRDNUg=
81-
github.com/aws/aws-sdk-go-v2/credentials v1.17.46/go.mod h1:1FmYyLGL08KQXQ6mcTlifyFXfJVCNJTVGuQP4m0d/UA=
82-
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.20 h1:sDSXIrlsFSFJtWKLQS4PUWRvrT580rrnuLydJrCQ/yA=
83-
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.20/go.mod h1:WZ/c+w0ofps+/OUqMwWgnfrgzZH1DZO1RIkktICsqnY=
76+
github.com/aws/aws-sdk-go-v2/config v1.32.17 h1:FpL4/758/diKwqbytU0prpuiu60fgXKUWCpDJtApclU=
77+
github.com/aws/aws-sdk-go-v2/config v1.32.17/go.mod h1:OXqUMzgXytfoF9JaKkhrOYsyh72t9G+MJH8mMRaexOE=
78+
github.com/aws/aws-sdk-go-v2/credentials v1.19.16 h1:r3RJBuU7X9ibt8RHbMjWE6y60QbKBiII6wSrXnapxSU=
79+
github.com/aws/aws-sdk-go-v2/credentials v1.19.16/go.mod h1:6cx7zqDENJDbBIIWX6P8s0h6hqHC8Avbjh9Dseo27ug=
80+
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.18.23 h1:UuSfcORqNSz/ey3VPRS8TcVH2Ikf0/sC+Hdj400QI6U=
81+
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.18.23/go.mod h1:+G/OSGiOFnSOkYloKj/9M35s74LgVAdJBSD5lsFfqKg=
8482
github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.29 h1:f3vKqSo13fhTYb+JEcXwXefZQE26I1FB5eTSniU67ko=
8583
github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.29/go.mod h1:MzoLFUArKGpGD+ukmPiTPG1X5x4o6M2kq4v2dr1FiEc=
8684
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.29 h1:RdwIf/CuUsvJX3RgJagbOyotl/cxoLY4xviKuE7p2GY=
8785
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.29/go.mod h1:71wt8W2EgswdZy9Mf9KNnzxZ3TiZlv4caKghPktDOkA=
88-
github.com/aws/aws-sdk-go-v2/internal/ini v1.8.1 h1:VaRN3TlFdd6KxX1x3ILT5ynH6HvKgqdiXoTxAF4HQcQ=
89-
github.com/aws/aws-sdk-go-v2/internal/ini v1.8.1/go.mod h1:FbtygfRFze9usAadmnGJNc8KsP346kEe+y2/oyhGAGc=
9086
github.com/aws/aws-sdk-go-v2/internal/v4a v1.4.30 h1:VTGy885W5DKBxWRUJbym9hytNaYzsyaPkCHGRRMAOhU=
9187
github.com/aws/aws-sdk-go-v2/internal/v4a v1.4.30/go.mod h1:AS0HycUvJRFvTt613AYDOgO2jzw+00cVSMny8XB3yMY=
9288
github.com/aws/aws-sdk-go-v2/service/iam v1.54.5 h1:a/gAOhIOi+vHYeRU224WIXlJrLXs4Z1Qbm92vfX64jc=
@@ -95,10 +91,12 @@ github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.12 h1:ZD2+BS
9591
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.12/go.mod h1:Ms4zlcVBbXbiP7EVLhl+lgjvA/a7YphqQ3Ih3174EmI=
9692
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.29 h1:DRebniUGZ2MqiiIVmQJ04vIXr918hubdHMnarSLEWyU=
9793
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.29/go.mod h1:LfRkPCD8YHDM2E5eTkos2UpwYeZnBcVarTa8L59bJHA=
98-
github.com/aws/aws-sdk-go-v2/service/sso v1.24.6 h1:3zu537oLmsPfDMyjnUS2g+F2vITgy5pB74tHI+JBNoM=
99-
github.com/aws/aws-sdk-go-v2/service/sso v1.24.6/go.mod h1:WJSZH2ZvepM6t6jwu4w/Z45Eoi75lPN7DcydSRtJg6Y=
100-
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.28.5 h1:K0OQAsDywb0ltlFrZm0JHPY3yZp/S9OaoLU33S7vPS8=
101-
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.28.5/go.mod h1:ORITg+fyuMoeiQFiVGoqB3OydVTLkClw/ljbblMq6Cc=
94+
github.com/aws/aws-sdk-go-v2/service/signin v1.0.11 h1:TdJ+HdzOBhU8+iVAOGUTU63VXopcumCOF1paFulHWZc=
95+
github.com/aws/aws-sdk-go-v2/service/signin v1.0.11/go.mod h1:R82ZRExE/nheo0N+T8zHPcLRTcH8MGsnR3BiVGX0TwI=
96+
github.com/aws/aws-sdk-go-v2/service/sso v1.30.17 h1:7byT8HUWrgoRp6sXjxtZwgOKfhss5fW6SkLBtqzgRoE=
97+
github.com/aws/aws-sdk-go-v2/service/sso v1.30.17/go.mod h1:xNWknVi4Ezm1vg1QsB/5EWpAJURq22uqd38U8qKvOJc=
98+
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.35.21 h1:+1Kl1zx6bWi4X7cKi3VYh29h8BvsCoHQEQ6ST9X8w7w=
99+
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.35.21/go.mod h1:4vIRDq+CJB2xFAXZ+YgGUTiEft7oAQlhIs71xcSeuVg=
102100
github.com/aws/aws-sdk-go-v2/service/sts v1.43.3 h1:VrIhKRCSK1umelSgB9RghvA9RTUYeQffyAS5ApXehNI=
103101
github.com/aws/aws-sdk-go-v2/service/sts v1.43.3/go.mod h1:r8wkDOuLaaMFqFiYAb8dGY2A3gJCOujMc6CFOVC4Zhc=
104102
github.com/aws/smithy-go v1.27.2 h1:y9NPmSE6am6LjEFPfqHqG/jJk7AauQvhCJONKh7kpzk=
@@ -491,10 +489,6 @@ github.com/jhump/protoreflect v1.17.0 h1:qOEr613fac2lOuTgWN4tPAtLL7fUSbuJL5X5Xum
491489
github.com/jhump/protoreflect v1.17.0/go.mod h1:h9+vUUL38jiBzck8ck+6G/aeMX8Z4QUY/NiJPwPNi+8=
492490
github.com/jimlambrt/gldap v0.1.13 h1:jxmVQn0lfmFbM9jglueoau5LLF/IGRti0SKf0vB753M=
493491
github.com/jimlambrt/gldap v0.1.13/go.mod h1:nlC30c7xVphjImg6etk7vg7ZewHCCvl1dfAhO3ZJzPg=
494-
github.com/jmespath/go-jmespath v0.4.1-0.20220621161143-b0104c826a24 h1:liMMTbpW34dhU4az1GN0pTPADwNmvoRSeoZ6PItiqnY=
495-
github.com/jmespath/go-jmespath v0.4.1-0.20220621161143-b0104c826a24/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo=
496-
github.com/jmespath/go-jmespath/internal/testify v1.5.1 h1:shLQSRRSCCPj3f2gpwzGwWFoC7ycTf1rcQZHOlsJ6N8=
497-
github.com/jmespath/go-jmespath/internal/testify v1.5.1/go.mod h1:L3OGu8Wl2/fWfCI6z80xFu9LTZmf1ZRjMHUOPmWr69U=
498492
github.com/joshlf/go-acl v0.0.0-20200411065538-eae00ae38531 h1:hgVxRoDDPtQE68PT4LFvNlPz2nBKd3OMlGKIQ69OmR4=
499493
github.com/joshlf/go-acl v0.0.0-20200411065538-eae00ae38531/go.mod h1:fqTUQpVYBvhCNIsMXGl2GE9q6z94DIP6NtFKXCSTVbg=
500494
github.com/joshlf/testutil v0.0.0-20170608050642-b5d8aa79d93d h1:J8tJzRyiddAFF65YVgxli+TyWBi0f79Sld6rJP6CBcY=

vault/data_source_aws_access_credentials.go

Lines changed: 78 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -4,17 +4,19 @@
44
package vault
55

66
import (
7+
"context"
8+
"errors"
79
"fmt"
810
"log"
911
"time"
1012

11-
"github.com/aws/aws-sdk-go/aws"
12-
"github.com/aws/aws-sdk-go/aws/awserr"
13-
"github.com/aws/aws-sdk-go/aws/credentials"
14-
"github.com/aws/aws-sdk-go/aws/session"
15-
"github.com/aws/aws-sdk-go/service/iam"
16-
"github.com/aws/aws-sdk-go/service/sts"
13+
"github.com/aws/aws-sdk-go-v2/config"
14+
"github.com/aws/aws-sdk-go-v2/credentials"
15+
"github.com/aws/aws-sdk-go-v2/service/iam"
16+
"github.com/aws/aws-sdk-go-v2/service/sts"
17+
"github.com/aws/smithy-go"
1718
"github.com/hashicorp/go-cleanhttp"
19+
"github.com/hashicorp/terraform-plugin-sdk/v2/diag"
1820
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/retry"
1921
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
2022

@@ -39,11 +41,16 @@ const (
3941
// propagationBuffer is the added buffer of time we'll wait after N sequential successes
4042
// before returning credentials for use.
4143
propagationBuffer = 5 * time.Second
44+
45+
// AWS error codes used in credential validation
46+
awsErrorAccessDenied = "AccessDenied"
47+
awsErrorValidationError = "ValidationError"
48+
awsErrorInvalidClientToken = "InvalidClientTokenId"
4249
)
4350

4451
func awsAccessCredentialsDataSource() *schema.Resource {
4552
return &schema.Resource{
46-
Read: provider.ReadWrapper(awsAccessCredentialsDataSourceRead),
53+
ReadContext: provider.ReadContextWrapper(awsAccessCredentialsDataSourceRead),
4754

4855
Schema: map[string]*schema.Schema{
4956
"backend": {
@@ -77,47 +84,41 @@ func awsAccessCredentialsDataSource() *schema.Resource {
7784
"region": {
7885
Type: schema.TypeString,
7986
Optional: true,
80-
Description: "Region the read credentials belong to.",
87+
Description: "Region the read credentials belong to. Defaults to us-east-1 if unset.",
8188
},
8289
"access_key": {
8390
Type: schema.TypeString,
8491
Computed: true,
8592
Description: "AWS access key ID read from Vault.",
8693
Sensitive: true,
8794
},
88-
8995
"secret_key": {
9096
Type: schema.TypeString,
9197
Computed: true,
9298
Description: "AWS secret key read from Vault.",
9399
Sensitive: true,
94100
},
95-
96101
"security_token": {
97102
Type: schema.TypeString,
98103
Computed: true,
99104
Description: "AWS security token read from Vault. (Only returned if type is 'sts').",
100105
Sensitive: true,
101106
},
102-
103107
consts.FieldLeaseID: {
104108
Type: schema.TypeString,
105109
Computed: true,
106110
Description: "Lease identifier assigned by vault.",
107111
},
108-
109112
consts.FieldLeaseDuration: {
110113
Type: schema.TypeInt,
111114
Computed: true,
112115
Description: "Lease duration in seconds relative to the time in lease_start_time.",
113116
},
114-
115117
"lease_start_time": {
116118
Type: schema.TypeString,
117119
Computed: true,
118120
Description: "Time at which the lease was read, using the clock of the system where Terraform was running",
119121
},
120-
121122
consts.FieldLeaseRenewable: {
122123
Type: schema.TypeBool,
123124
Computed: true,
@@ -132,10 +133,10 @@ func awsAccessCredentialsDataSource() *schema.Resource {
132133
}
133134
}
134135

135-
func awsAccessCredentialsDataSourceRead(d *schema.ResourceData, meta interface{}) error {
136+
func awsAccessCredentialsDataSourceRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
136137
client, e := provider.GetClient(d, meta)
137138
if e != nil {
138-
return e
139+
return diag.FromErr(e)
139140
}
140141

141142
backend := d.Get("backend").(string)
@@ -156,12 +157,12 @@ func awsAccessCredentialsDataSourceRead(d *schema.ResourceData, meta interface{}
156157
log.Printf("[DEBUG] Reading %q from Vault with data %#v", path, data)
157158
secret, err := client.Logical().ReadWithData(path, data)
158159
if err != nil {
159-
return fmt.Errorf("error reading from Vault: %s", err)
160+
return diag.FromErr(fmt.Errorf("error reading AWS credentials from Vault: %w", err))
160161
}
161162
log.Printf("[DEBUG] Read %q from Vault", path)
162163

163164
if secret == nil {
164-
return fmt.Errorf("no role found at path %q", path)
165+
return diag.FromErr(fmt.Errorf("no role found at path %q", path))
165166
}
166167

167168
accessKey := secret.Data["access_key"].(string)
@@ -180,31 +181,53 @@ func awsAccessCredentialsDataSourceRead(d *schema.ResourceData, meta interface{}
180181
d.Set("lease_start_time", time.Now().Format(time.RFC3339))
181182
d.Set(consts.FieldLeaseRenewable, secret.Renewable)
182183

183-
awsConfig := &aws.Config{
184-
Credentials: credentials.NewStaticCredentials(accessKey, secretKey, securityToken),
185-
HTTPClient: cleanhttp.DefaultClient(),
184+
optFns := []func(*config.LoadOptions) error{
185+
config.WithCredentialsProvider(
186+
credentials.NewStaticCredentialsProvider(accessKey, secretKey, securityToken),
187+
),
188+
config.WithHTTPClient(cleanhttp.DefaultClient()),
186189
}
187190

191+
// If a region is explicitly provided, use it. Otherwise, allow the AWS SDK to
192+
// resolve the region from the environment or shared config. As a last resort,
193+
// fall back to us-east-1 since IAM and STS require a region in SDK v2.
194+
188195
region := d.Get("region").(string)
196+
197+
// Only set region if user explicitly provided it
189198
if region != "" {
190-
awsConfig.Region = &region
199+
optFns = append(optFns, config.WithRegion(region))
191200
}
192201

193-
sess, err := session.NewSession(awsConfig)
202+
cfg, err := config.LoadDefaultConfig(ctx, optFns...)
194203
if err != nil {
195-
return fmt.Errorf("error creating AWS session: %s", err)
204+
return diag.FromErr(fmt.Errorf("failed to load AWS SDK configuration: %w", err))
205+
}
206+
207+
// Fallback only if NOTHING provided a region
208+
if cfg.Region == "" {
209+
cfg.Region = "us-east-1"
196210
}
197211

198-
iamconn := iam.New(sess)
199-
stsconn := sts.New(sess)
212+
iamconn := iam.NewFromConfig(cfg)
213+
stsconn := sts.NewFromConfig(cfg)
200214

201215
// Different types of AWS credentials have different behavior around consistency.
202216
// See https://www.vaultproject.io/docs/secrets/aws/index.html#usage for more.
203217
if credType == "sts" {
204218
// STS credentials are immediately consistent. Let's ensure they're working.
205219
log.Printf("[DEBUG] Checking if AWS sts token %q is valid", secret.LeaseID)
206-
if _, err := stsconn.GetCallerIdentity(&sts.GetCallerIdentityInput{}); err != nil {
207-
return err
220+
221+
// Use a bounded timeout for STS validation.
222+
// GetCallerIdentity is typically sub‑second but can be delayed by network
223+
// latency or throttling; 10 seconds provides sufficient headroom while
224+
// preventing indefinite hangs in the provider.
225+
226+
stsCtx, cancel := context.WithTimeout(ctx, 10*time.Second)
227+
defer cancel()
228+
229+
if _, err := stsconn.GetCallerIdentity(stsCtx, &sts.GetCallerIdentityInput{}); err != nil {
230+
return diag.FromErr(fmt.Errorf("error validating STS credentials: %w", err))
208231
}
209232
return nil
210233
}
@@ -218,10 +241,16 @@ func awsAccessCredentialsDataSourceRead(d *schema.ResourceData, meta interface{}
218241
// validateCreds is a retry function, which will be retried until it succeeds.
219242
validateCreds := func() *retry.RetryError {
220243
log.Printf("[DEBUG] Checking if AWS creds %q are valid", secret.LeaseID)
221-
if _, err := iamconn.GetUser(nil); err != nil && isAWSAuthError(err) {
244+
245+
// Use a timeout context to bound each individual IAM validation attempt.
246+
iamCtx, cancel := context.WithTimeout(ctx, 10*time.Second)
247+
defer cancel()
248+
249+
if _, err := iamconn.GetUser(iamCtx, nil); err != nil && isAWSAuthError(err) {
222250
sequentialSuccesses = 0
223251
log.Printf("[DEBUG] AWS auth error checking if creds %q are valid, is retryable", secret.LeaseID)
224-
return retry.RetryableError(err)
252+
wrappedErr := fmt.Errorf("AWS credentials validation failed (retryable): %w", err)
253+
return retry.RetryableError(wrappedErr)
225254
} else if err != nil {
226255
log.Printf("[DEBUG] Error checking if creds %q are valid: %s", secret.LeaseID, err)
227256
return retry.NonRetryableError(err)
@@ -232,31 +261,39 @@ func awsAccessCredentialsDataSourceRead(d *schema.ResourceData, meta interface{}
232261
}
233262

234263
start := time.Now()
264+
235265
for sequentialSuccesses < sequentialSuccessesRequired {
236266
if time.Since(start) > sequentialSuccessTimeLimit {
237-
return fmt.Errorf("unable to get %d sequential successes within %.f seconds", sequentialSuccessesRequired, sequentialSuccessTimeLimit.Seconds())
267+
return diag.FromErr(fmt.Errorf(
268+
"AWS credentials did not become consistent after %d successful validations within %.f seconds",
269+
sequentialSuccessesRequired,
270+
sequentialSuccessTimeLimit.Seconds(),
271+
))
238272
}
239273
if err := retry.Retry(retryTimeOut, validateCreds); err != nil {
240-
return fmt.Errorf("error checking if credentials are valid: %s", err)
274+
return diag.FromErr(fmt.Errorf("AWS credentials validation failed after retries: %w", err))
241275
}
242276
}
243277

278+
// Use select instead of time.Sleep so that user cancellation (e.g. Ctrl+C)
279+
// is honoured during the propagation wait. time.Sleep blocks unconditionally
280+
// and cannot be interrupted by context cancellation.
244281
log.Printf("[DEBUG] Waiting an additional %.f seconds for new credentials to propagate...", propagationBuffer.Seconds())
245-
time.Sleep(propagationBuffer)
282+
select {
283+
case <-ctx.Done():
284+
return diag.FromErr(fmt.Errorf("propagation wait cancelled: %w", ctx.Err()))
285+
case <-time.After(propagationBuffer):
286+
}
246287
return nil
247288
}
248289

249290
func isAWSAuthError(err error) bool {
250-
awsErr, ok := err.(awserr.Error)
251-
if !ok {
291+
var apiErr smithy.APIError
292+
if !errors.As(err, &apiErr) {
252293
return false
253294
}
254-
switch awsErr.Code() {
255-
case "AccessDenied":
256-
return true
257-
case "ValidationError":
258-
return true
259-
case "InvalidClientTokenId":
295+
switch apiErr.ErrorCode() {
296+
case awsErrorAccessDenied, awsErrorValidationError, awsErrorInvalidClientToken:
260297
return true
261298
default:
262299
return false

0 commit comments

Comments
 (0)