Skip to content

Commit ca378c6

Browse files
authored
Merge pull request #44876 from josnyder-2/b-aws_secretsmanager_secret_version_no-get-secret-value
`aws_secretsmanager_secret_version`: Avoid `GetSecretValue` calls for write-only secret versions
2 parents 7bf88b2 + aae0605 commit ca378c6

File tree

4 files changed

+342
-25
lines changed

4 files changed

+342
-25
lines changed

.changelog/44876.txt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
```release-note:bug
2+
resource/aws_secretsmanager_secret_version: Avoid sending GetSecretValue calls when the secret is write-only
3+
```

internal/service/secretsmanager/exports_test.go

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,8 @@ var (
1010
ResourceSecretRotation = resourceSecretRotation
1111
ResourceSecretVersion = resourceSecretVersion
1212

13-
FindSecretByID = findSecretByID
14-
FindSecretPolicyByID = findSecretPolicyByID
15-
FindSecretVersionByTwoPartKey = findSecretVersionByTwoPartKey
13+
FindSecretByID = findSecretByID
14+
FindSecretPolicyByID = findSecretPolicyByID
15+
FindSecretVersionByTwoPartKey = findSecretVersionByTwoPartKey
16+
FindSecretVersionEntryByTwoPartKey = findSecretVersionEntryByTwoPartKey
1617
)

internal/service/secretsmanager/secret_version.go

Lines changed: 99 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -151,7 +151,7 @@ func resourceSecretVersionCreate(ctx context.Context, d *schema.ResourceData, me
151151
d.SetId(secretVersionCreateResourceID(secretID, versionID))
152152

153153
_, err = tfresource.RetryWhenNotFound(ctx, propagationTimeout, func(ctx context.Context) (any, error) {
154-
return findSecretVersionByTwoPartKey(ctx, conn, secretID, versionID)
154+
return findSecretVersionForExistence(ctx, conn, secretID, versionID, secretStringWO != "")
155155
})
156156

157157
if err != nil {
@@ -161,6 +161,25 @@ func resourceSecretVersionCreate(ctx context.Context, d *schema.ResourceData, me
161161
return append(diags, resourceSecretVersionRead(ctx, d, meta)...)
162162
}
163163

164+
type secretVersionExistsOutput struct {
165+
VersionStages []string
166+
}
167+
168+
func findSecretVersionForExistence(ctx context.Context, conn *secretsmanager.Client, secretID, versionID string, hasWriteOnly bool) (*secretVersionExistsOutput, error) {
169+
if hasWriteOnly {
170+
_, output, err := findSecretVersionEntryByTwoPartKey(ctx, conn, secretID, versionID)
171+
if err != nil {
172+
return nil, err
173+
}
174+
return &secretVersionExistsOutput{VersionStages: output.VersionStages}, nil
175+
}
176+
output, err := findSecretVersionByTwoPartKey(ctx, conn, secretID, versionID)
177+
if err != nil {
178+
return nil, err
179+
}
180+
return &secretVersionExistsOutput{VersionStages: output.VersionStages}, nil
181+
}
182+
164183
func resourceSecretVersionRead(ctx context.Context, d *schema.ResourceData, meta any) diag.Diagnostics {
165184
var diags diag.Diagnostics
166185
conn := meta.(*conns.AWSClient).SecretsManagerClient(ctx)
@@ -170,42 +189,56 @@ func resourceSecretVersionRead(ctx context.Context, d *schema.ResourceData, meta
170189
return sdkdiag.AppendFromErr(diags, err)
171190
}
172191

173-
output, err := findSecretVersionByTwoPartKey(ctx, conn, secretID, versionID)
192+
hasWriteOnly := flex.HasWriteOnlyValue(d, "secret_string_wo")
193+
secretStringWO, di := flex.GetWriteOnlyStringValue(d, cty.GetAttrPath("secret_string_wo"))
194+
diags = append(diags, di...)
195+
if diags.HasError() {
196+
return diags
197+
}
174198

199+
if secretStringWO != "" {
200+
hasWriteOnly = true
201+
}
202+
203+
d.Set("secret_id", secretID)
204+
205+
if hasWriteOnly {
206+
arn, versionEntry, err := findSecretVersionEntryByTwoPartKey(ctx, conn, secretID, versionID)
207+
if !d.IsNewResource() && tfresource.NotFound(err) {
208+
log.Printf("[WARN] Secrets Manager Secret Version (%s) not found, removing from state", d.Id())
209+
d.SetId("")
210+
return diags
211+
}
212+
if err != nil {
213+
return sdkdiag.AppendErrorf(diags, "reading Secrets Manager Secret Version (%s): %s", d.Id(), err)
214+
}
215+
216+
d.Set(names.AttrARN, arn)
217+
d.Set("secret_binary", nil)
218+
d.Set("secret_string", nil)
219+
d.Set("version_id", versionEntry.VersionId)
220+
d.Set("version_stages", versionEntry.VersionStages)
221+
d.Set("has_secret_string_wo", true)
222+
223+
return diags
224+
}
225+
226+
output, err := findSecretVersionByTwoPartKey(ctx, conn, secretID, versionID)
175227
if !d.IsNewResource() && tfresource.NotFound(err) {
176228
log.Printf("[WARN] Secrets Manager Secret Version (%s) not found, removing from state", d.Id())
177229
d.SetId("")
178230
return diags
179231
}
180-
181232
if err != nil {
182233
return sdkdiag.AppendErrorf(diags, "reading Secrets Manager Secret Version (%s): %s", d.Id(), err)
183234
}
184235

185236
d.Set(names.AttrARN, output.ARN)
186237
d.Set("secret_binary", inttypes.Base64EncodeOnce(output.SecretBinary))
187-
d.Set("secret_id", secretID)
188238
d.Set("secret_string", output.SecretString)
189239
d.Set("version_id", output.VersionId)
190240
d.Set("version_stages", output.VersionStages)
191241

192-
// unset secret_string if the value is configured as write-only
193-
hasWriteOnly := flex.HasWriteOnlyValue(d, "secret_string_wo")
194-
secretStringWO, di := flex.GetWriteOnlyStringValue(d, cty.GetAttrPath("secret_string_wo"))
195-
diags = append(diags, di...)
196-
if diags.HasError() {
197-
return diags
198-
}
199-
200-
if secretStringWO != "" {
201-
hasWriteOnly = true
202-
}
203-
204-
if hasWriteOnly {
205-
d.Set("has_secret_string_wo", true)
206-
d.Set("secret_string", nil)
207-
}
208-
209242
return diags
210243
}
211244

@@ -335,7 +368,8 @@ func resourceSecretVersionDelete(ctx context.Context, d *schema.ResourceData, me
335368
}
336369

337370
_, err = tfresource.RetryUntilNotFound(ctx, propagationTimeout, func(ctx context.Context) (any, error) {
338-
output, err := findSecretVersionByTwoPartKey(ctx, conn, secretID, versionID)
371+
hasWriteOnly := flex.HasWriteOnlyValue(d, "secret_string_wo")
372+
output, err := findSecretVersionForExistence(ctx, conn, secretID, versionID, hasWriteOnly)
339373

340374
if err != nil {
341375
return nil, err
@@ -355,6 +389,49 @@ func resourceSecretVersionDelete(ctx context.Context, d *schema.ResourceData, me
355389
return diags
356390
}
357391

392+
func findSecretVersionEntryByTwoPartKey(ctx context.Context, conn *secretsmanager.Client, secretID, versionID string) (*string, *types.SecretVersionsListEntry, error) {
393+
input := &secretsmanager.ListSecretVersionIdsInput{
394+
SecretId: aws.String(secretID),
395+
IncludeDeprecated: aws.Bool(true),
396+
}
397+
398+
paginator := secretsmanager.NewListSecretVersionIdsPaginator(conn, input)
399+
400+
for paginator.HasMorePages() {
401+
page, err := paginator.NextPage(ctx)
402+
403+
if errs.IsA[*types.ResourceNotFoundException](err) ||
404+
errs.IsAErrorMessageContains[*types.InvalidRequestException](err, "because it was deleted") ||
405+
errs.IsAErrorMessageContains[*types.InvalidRequestException](err, "because it was marked for deletion") {
406+
return nil, nil, &retry.NotFoundError{
407+
LastError: err,
408+
LastRequest: input,
409+
}
410+
}
411+
412+
if err != nil {
413+
return nil, nil, err
414+
}
415+
416+
if page == nil {
417+
continue
418+
}
419+
420+
for i := range page.Versions {
421+
version := &page.Versions[i]
422+
423+
if aws.ToString(version.VersionId) == versionID {
424+
return page.ARN, version, nil
425+
}
426+
}
427+
}
428+
429+
return nil, nil, &retry.NotFoundError{
430+
LastError: tfresource.NewEmptyResultError(input),
431+
LastRequest: input,
432+
}
433+
}
434+
358435
func findSecretVersion(ctx context.Context, conn *secretsmanager.Client, input *secretsmanager.GetSecretValueInput) (*secretsmanager.GetSecretValueOutput, error) {
359436
output, err := conn.GetSecretValue(ctx, input)
360437

0 commit comments

Comments
 (0)