Skip to content

Commit

Permalink
r/aws_iam_user_login_profile: prevent password_reset_required persist…
Browse files Browse the repository at this point in the history
…ent diff

This change fixes persistent differences observed when a user login profile is initially configured with `password_reset_required` set to true. Once the user logs in and resets their password successfully, the remote value switches to `false` as the user has completed the initial reset task. Instead of writing the remote value to state on every read operation (triggering a diff and forced re-creation as soon as the password is reset), we now store the initial value on creation only. This makes the implementation consistent with our own existing documentation for the argument, which states:

> password_reset_required - (Optional) Whether the user should be forced to reset the generated password on resource creation. Only applies on resource creation.

Before:

```console
% make testacc PKG=iam TESTS=TestAccIAMUserLoginProfile_passwordResetRequired
==> Checking that code complies with gofmt requirements...
TF_ACC=1 go1.21.8 test ./internal/service/iam/... -v -count 1 -parallel 20 -run='TestAccIAMUserLoginProfile_passwordResetRequired'  -timeout 360m
=== RUN   TestAccIAMUserLoginProfile_passwordResetRequired
=== PAUSE TestAccIAMUserLoginProfile_passwordResetRequired
=== CONT  TestAccIAMUserLoginProfile_passwordResetRequired
    user_login_profile_test.go:303: Step 1/2 error: After applying this test step, the refresh plan was not empty.
        stdout

        Terraform used the selected providers to generate the following execution
        plan. Resource actions are indicated with the following symbols:
        -/+ destroy and then create replacement

        Terraform will perform the following actions:

          # aws_iam_user_login_profile.test must be replaced
        -/+ resource "aws_iam_user_login_profile" "test" {
          <snip>
              + password                = (known after apply)
              ~ password_reset_required = false -> true # forces replacement
                # (3 unchanged attributes hidden)
            }

        Plan: 1 to add, 0 to change, 1 to destroy.
--- FAIL: TestAccIAMUserLoginProfile_passwordResetRequired (26.74s)
FAIL
FAIL    github.com/hashicorp/terraform-provider-aws/internal/service/iam        32.422s
```

After:

```console
% make testacc PKG=iam TESTS=TestAccIAMUserLoginProfile_passwordResetRequired
==> Checking that code complies with gofmt requirements...
TF_ACC=1 go1.21.8 test ./internal/service/iam/... -v -count 1 -parallel 20 -run='TestAccIAMUserLoginProfile_passwordResetRequired'  -timeout 360m

--- PASS: TestAccIAMUserLoginProfile_passwordResetRequired (20.63s)
PASS
ok      github.com/hashicorp/terraform-provider-aws/internal/service/iam        26.258s
```

```console
% make testacc PKG=iam TESTS=TestAccIAMUserLoginProfile_
==> Checking that code complies with gofmt requirements...
TF_ACC=1 go1.21.8 test ./internal/service/iam/... -v -count 1 -parallel 20 -run='TestAccIAMUserLoginProfile_'  -timeout 360m

--- PASS: TestAccIAMUserLoginProfile_keybaseDoesntExist (11.51s)
--- PASS: TestAccIAMUserLoginProfile_nogpg (12.95s)
--- PASS: TestAccIAMUserLoginProfile_passwordLength (13.72s)
--- PASS: TestAccIAMUserLoginProfile_keybase (14.21s)
--- PASS: TestAccIAMUserLoginProfile_notAKey (15.64s)
--- PASS: TestAccIAMUserLoginProfile_disappears (21.50s)
--- PASS: TestAccIAMUserLoginProfile_basic (21.57s)
--- PASS: TestAccIAMUserLoginProfile_passwordResetRequired (21.70s)
PASS
ok      github.com/hashicorp/terraform-provider-aws/internal/service/iam        27.247s
```
  • Loading branch information
jar-b committed Apr 15, 2024
1 parent 5f8e44c commit 8104ef9
Show file tree
Hide file tree
Showing 3 changed files with 61 additions and 6 deletions.
3 changes: 3 additions & 0 deletions .changelog/36926.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
```release-note:bug
resource/aws_iam_user_login_profile: Fix forced re-creation when `password_reset_required` is `true` and initial password reset is completed
```
8 changes: 2 additions & 6 deletions internal/service/iam/user_login_profile.go
Original file line number Diff line number Diff line change
Expand Up @@ -176,7 +176,7 @@ func resourceUserLoginProfileCreate(ctx context.Context, d *schema.ResourceData,
d.Set("password", initialPassword)
}

return diags
return append(diags, resourceUserLoginProfileRead(ctx, d, meta)...)
}

func resourceUserLoginProfileRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
Expand Down Expand Up @@ -223,11 +223,7 @@ func resourceUserLoginProfileRead(ctx context.Context, d *schema.ResourceData, m
return sdkdiag.AppendErrorf(diags, "reading IAM User Login Profile (%s): empty response", d.Id())
}

loginProfile := output.LoginProfile

d.Set("user", loginProfile.UserName)
d.Set("password_reset_required", loginProfile.PasswordResetRequired)

d.Set("user", output.LoginProfile.UserName)
return diags
}

Expand Down
56 changes: 56 additions & 0 deletions internal/service/iam/user_login_profile_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -293,6 +293,47 @@ func TestAccIAMUserLoginProfile_disappears(t *testing.T) {
})
}

func TestAccIAMUserLoginProfile_passwordResetRequired(t *testing.T) {
ctx := acctest.Context(t)
var conf iam.GetLoginProfileOutput

resourceName := "aws_iam_user_login_profile.test"
rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix)

resource.ParallelTest(t, resource.TestCase{
PreCheck: func() { acctest.PreCheck(ctx, t) },
ErrorCheck: acctest.ErrorCheck(t, names.IAMServiceID),
ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories,
CheckDestroy: testAccCheckUserLoginProfileDestroy(ctx),
Steps: []resource.TestStep{
{
Config: testAccUserLoginProfileConfig_passwordResetRequired(rName, testPubKey1),
Check: resource.ComposeTestCheckFunc(
testAccCheckUserLoginProfileExists(ctx, resourceName, &conf),
testDecryptPasswordAndTest(ctx, resourceName, "aws_iam_access_key.test", testPrivKey1),
resource.TestCheckResourceAttrSet(resourceName, "encrypted_password"),
resource.TestCheckResourceAttrSet(resourceName, "key_fingerprint"),
resource.TestCheckResourceAttr(resourceName, "password_length", "20"),
resource.TestCheckResourceAttr(resourceName, "password_reset_required", "true"),
resource.TestCheckResourceAttr(resourceName, "pgp_key", testPubKey1+"\n"),
),
},
{
ResourceName: resourceName,
ImportState: true,
ImportStateVerify: true,
ImportStateVerifyIgnore: []string{
"encrypted_password",
"key_fingerprint",
"password_length",
"password_reset_required",
"pgp_key",
},
},
},
})
}

func testAccCheckUserLoginProfileDestroy(ctx context.Context) resource.TestCheckFunc {
return func(s *terraform.State) error {
conn := acctest.Provider.Meta().(*conns.AWSClient).IAMClient(ctx)
Expand Down Expand Up @@ -458,6 +499,21 @@ EOF
`, passwordLength, pgpKey))
}

func testAccUserLoginProfileConfig_passwordResetRequired(rName, pgpKey string) string {
return acctest.ConfigCompose(
testAccUserLoginProfileConfig_base(rName),
fmt.Sprintf(`
resource "aws_iam_user_login_profile" "test" {
user = aws_iam_user.test.name
password_reset_required = true
pgp_key = <<EOF
%s
EOF
}
`, pgpKey))
}

func testAccUserLoginProfileConfig_required(rName, pgpKey string) string {
return acctest.ConfigCompose(testAccUserLoginProfileConfig_base(rName), fmt.Sprintf(`
resource "aws_iam_user_login_profile" "test" {
Expand Down

0 comments on commit 8104ef9

Please sign in to comment.