From 4434a2dc1d32d4215a6d0406619d249029c50d31 Mon Sep 17 00:00:00 2001 From: Dirk Avery Date: Tue, 14 Dec 2021 16:40:24 -0500 Subject: [PATCH 01/10] secretsmanager/secret: Fix equivalent policy diffs --- internal/service/secretsmanager/secret.go | 24 +++++++++++++++---- .../service/secretsmanager/secret_policy.go | 24 +++++++++++++++---- 2 files changed, 38 insertions(+), 10 deletions(-) diff --git a/internal/service/secretsmanager/secret.go b/internal/service/secretsmanager/secret.go index a3edae18d3d..f3f1f5a7af7 100644 --- a/internal/service/secretsmanager/secret.go +++ b/internal/service/secretsmanager/secret.go @@ -71,6 +71,10 @@ func ResourceSecret() *schema.Resource { Computed: true, ValidateFunc: validation.StringIsJSON, DiffSuppressFunc: verify.SuppressEquivalentPolicyDiffs, + StateFunc: func(v interface{}) string { + json, _ := structure.NormalizeJsonString(v) + return json + }, }, "recovery_window_in_days": { Type: schema.TypeInt, @@ -206,12 +210,18 @@ func resourceSecretCreate(d *schema.ResourceData, meta interface{}) error { d.SetId(aws.StringValue(output.ARN)) if v, ok := d.GetOk("policy"); ok && v.(string) != "" { + policy, err := structure.NormalizeJsonString(v.(string)) + + if err != nil { + return fmt.Errorf("policy (%s) is invalid JSON: %w", v.(string), err) + } + input := &secretsmanager.PutResourcePolicyInput{ - ResourcePolicy: aws.String(v.(string)), + ResourcePolicy: aws.String(policy), SecretId: aws.String(d.Id()), } - err := resource.Retry(tfiam.PropagationTimeout, func() *resource.RetryError { + err = resource.Retry(tfiam.PropagationTimeout, func() *resource.RetryError { _, err := conn.PutResourcePolicy(input) if tfawserr.ErrMessageContains(err, secretsmanager.ErrCodeMalformedPolicyDocumentException, "This resource policy contains an unsupported principal") { @@ -324,11 +334,15 @@ func resourceSecretRead(d *schema.ResourceData, meta interface{}) error { } if pOut.ResourcePolicy != nil { - policy, err := structure.NormalizeJsonString(aws.StringValue(pOut.ResourcePolicy)) + policyToSet, err := verify.PolicyToSet(d.Get("policy").(string), aws.StringValue(pOut.ResourcePolicy)) + if err != nil { - return fmt.Errorf("policy contains an invalid JSON: %w", err) + return err } - d.Set("policy", policy) + + d.Set("policy", policyToSet) + } else { + d.Set("policy", "") } d.Set("rotation_enabled", output.RotationEnabled) diff --git a/internal/service/secretsmanager/secret_policy.go b/internal/service/secretsmanager/secret_policy.go index 453e6e8315b..f953932255b 100644 --- a/internal/service/secretsmanager/secret_policy.go +++ b/internal/service/secretsmanager/secret_policy.go @@ -39,6 +39,10 @@ func ResourceSecretPolicy() *schema.Resource { Required: true, ValidateFunc: validation.StringIsJSON, DiffSuppressFunc: verify.SuppressEquivalentPolicyDiffs, + StateFunc: func(v interface{}) string { + json, _ := structure.NormalizeJsonString(v) + return json + }, }, "block_public_policy": { Type: schema.TypeBool, @@ -51,8 +55,14 @@ func ResourceSecretPolicy() *schema.Resource { func resourceSecretPolicyCreate(d *schema.ResourceData, meta interface{}) error { conn := meta.(*conns.AWSClient).SecretsManagerConn + policy, err := structure.NormalizeJsonString(d.Get("policy").(string)) + + if err != nil { + return fmt.Errorf("policy (%s) is invalid JSON: %w", d.Get("policy").(string), err) + } + input := &secretsmanager.PutResourcePolicyInput{ - ResourcePolicy: aws.String(d.Get("policy").(string)), + ResourcePolicy: aws.String(policy), SecretId: aws.String(d.Get("secret_arn").(string)), } @@ -63,7 +73,7 @@ func resourceSecretPolicyCreate(d *schema.ResourceData, meta interface{}) error log.Printf("[DEBUG] Setting Secrets Manager Secret resource policy; %#v", input) var res *secretsmanager.PutResourcePolicyOutput - err := resource.Retry(tfiam.PropagationTimeout, func() *resource.RetryError { + err = resource.Retry(tfiam.PropagationTimeout, func() *resource.RetryError { var err error res, err = conn.PutResourcePolicy(input) if tfawserr.ErrMessageContains(err, secretsmanager.ErrCodeMalformedPolicyDocumentException, @@ -131,11 +141,13 @@ func resourceSecretPolicyRead(d *schema.ResourceData, meta interface{}) error { } if res.ResourcePolicy != nil { - policy, err := structure.NormalizeJsonString(aws.StringValue(res.ResourcePolicy)) + policyToSet, err := verify.PolicyToSet(d.Get("policy").(string), aws.StringValue(res.ResourcePolicy)) + if err != nil { - return fmt.Errorf("policy contains an invalid JSON: %w", err) + return err } - d.Set("policy", policy) + + d.Set("policy", policyToSet) } else { d.Set("policy", "") } @@ -149,9 +161,11 @@ func resourceSecretPolicyUpdate(d *schema.ResourceData, meta interface{}) error if d.HasChanges("policy", "block_public_policy") { policy, err := structure.NormalizeJsonString(d.Get("policy").(string)) + if err != nil { return fmt.Errorf("policy contains an invalid JSON: %s", err) } + input := &secretsmanager.PutResourcePolicyInput{ ResourcePolicy: aws.String(policy), SecretId: aws.String(d.Id()), From f7701ff27ebac2bce79b7b6ee239863fc3c68f50 Mon Sep 17 00:00:00 2001 From: Dirk Avery Date: Tue, 14 Dec 2021 16:42:11 -0500 Subject: [PATCH 02/10] Add changelog --- .changelog/22217.txt | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 .changelog/22217.txt diff --git a/.changelog/22217.txt b/.changelog/22217.txt new file mode 100644 index 00000000000..402e3d86acf --- /dev/null +++ b/.changelog/22217.txt @@ -0,0 +1,7 @@ +```release-note:bug +resource/aws_secretsmanager_secret: Fix erroneous diffs in `policy` when no changes made or policies are equivalent +``` + +```release-note:bug +resource/aws_secretsmanager_secret_policy: Fix erroneous diffs in `policy` when no changes made or policies are equivalent +``` \ No newline at end of file From 2c531952e93bde2bd624aa7cacd020c7d22ee1c8 Mon Sep 17 00:00:00 2001 From: Dirk Avery Date: Tue, 14 Dec 2021 20:03:36 -0500 Subject: [PATCH 03/10] Adjust logic --- internal/service/secretsmanager/secret.go | 25 +----- .../service/secretsmanager/secret_test.go | 86 ++++++++++++------- 2 files changed, 57 insertions(+), 54 deletions(-) diff --git a/internal/service/secretsmanager/secret.go b/internal/service/secretsmanager/secret.go index f3f1f5a7af7..a1c8f99ae55 100644 --- a/internal/service/secretsmanager/secret.go +++ b/internal/service/secretsmanager/secret.go @@ -68,7 +68,6 @@ func ResourceSecret() *schema.Resource { "policy": { Type: schema.TypeString, Optional: true, - Computed: true, ValidateFunc: validation.StringIsJSON, DiffSuppressFunc: verify.SuppressEquivalentPolicyDiffs, StateFunc: func(v interface{}) string { @@ -279,28 +278,10 @@ func resourceSecretRead(d *schema.ResourceData, meta interface{}) error { SecretId: aws.String(d.Id()), } - var output *secretsmanager.DescribeSecretOutput - - err := resource.Retry(PropagationTimeout, func() *resource.RetryError { - var err error - - output, err = conn.DescribeSecret(input) - - if d.IsNewResource() && tfawserr.ErrCodeEquals(err, secretsmanager.ErrCodeResourceNotFoundException) { - return resource.RetryableError(err) - } - - if err != nil { - return resource.NonRetryableError(err) - } - - return nil + outputRaw, err := tfresource.RetryWhenNotFound(PropagationTimeout, func() (interface{}, error) { + return conn.DescribeSecret(input) }) - if tfresource.TimedOut(err) { - output, err = conn.DescribeSecret(input) - } - if !d.IsNewResource() && tfawserr.ErrCodeEquals(err, secretsmanager.ErrCodeResourceNotFoundException) { log.Printf("[WARN] Secrets Manager Secret (%s) not found, removing from state", d.Id()) d.SetId("") @@ -311,6 +292,8 @@ func resourceSecretRead(d *schema.ResourceData, meta interface{}) error { return fmt.Errorf("error reading Secrets Manager Secret (%s): %w", d.Id(), err) } + output := outputRaw.(*secretsmanager.DescribeSecretOutput) + if output == nil { return fmt.Errorf("error reading Secrets Manager Secret (%s): empty response", d.Id()) } diff --git a/internal/service/secretsmanager/secret_test.go b/internal/service/secretsmanager/secret_test.go index 088f1718663..fae5951271a 100644 --- a/internal/service/secretsmanager/secret_test.go +++ b/internal/service/secretsmanager/secret_test.go @@ -424,7 +424,7 @@ func TestAccSecretsManagerSecret_policy(t *testing.T) { CheckDestroy: testAccCheckSecretDestroy, Steps: []resource.TestStep{ { - Config: testAccSecretConfig_Policy(rName), + Config: testAccSecretPolicyConfig(rName), Check: resource.ComposeTestCheckFunc( testAccCheckSecretExists(resourceName, &secret), resource.TestMatchResourceAttr(resourceName, "policy", @@ -432,14 +432,14 @@ func TestAccSecretsManagerSecret_policy(t *testing.T) { ), }, { - Config: testAccSecretConfig_Name(rName), + Config: testAccSecretPolicyEmptyConfig(rName), Check: resource.ComposeTestCheckFunc( testAccCheckSecretExists(resourceName, &secret), resource.TestCheckResourceAttr(resourceName, "policy", ""), ), }, { - Config: testAccSecretConfig_Policy(rName), + Config: testAccSecretPolicyConfig(rName), Check: resource.ComposeTestCheckFunc( testAccCheckSecretExists(resourceName, &secret), resource.TestMatchResourceAttr(resourceName, "policy", @@ -801,47 +801,67 @@ resource "aws_secretsmanager_secret" "test" { `, rName) } -func testAccSecretConfig_Policy(rName string) string { +func testAccSecretPolicyConfig(rName string) string { return fmt.Sprintf(` resource "aws_iam_role" "test" { name = %[1]q - - assume_role_policy = < Date: Tue, 14 Dec 2021 20:11:07 -0500 Subject: [PATCH 04/10] iam/role: Fix eventual consistency role ARN --- internal/service/iam/wait.go | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/internal/service/iam/wait.go b/internal/service/iam/wait.go index 1f3cafc052a..0cb6673dcf9 100644 --- a/internal/service/iam/wait.go +++ b/internal/service/iam/wait.go @@ -26,10 +26,12 @@ const ( func waitRoleARNIsNotUniqueID(conn *iam.IAM, id string, role *iam.Role) (*iam.Role, error) { stateConf := &resource.StateChangeConf{ - Pending: []string{RoleStatusARNIsUniqueID, RoleStatusNotFound}, - Target: []string{RoleStatusARNIsARN}, - Refresh: statusRoleCreate(conn, id, role), - Timeout: PropagationTimeout, + Pending: []string{RoleStatusARNIsUniqueID, RoleStatusNotFound}, + Target: []string{RoleStatusARNIsARN}, + Refresh: statusRoleCreate(conn, id, role), + Timeout: PropagationTimeout, + NotFoundChecks: 5, + ContinuousTargetOccurence: 4, } outputRaw, err := stateConf.WaitForState() From ccea31c0b7e87a0d6a4a8f8b083f0004f91c89e0 Mon Sep 17 00:00:00 2001 From: Dirk Avery Date: Tue, 14 Dec 2021 20:13:20 -0500 Subject: [PATCH 05/10] Update changelog --- .changelog/22217.txt | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.changelog/22217.txt b/.changelog/22217.txt index 402e3d86acf..9757045f8e1 100644 --- a/.changelog/22217.txt +++ b/.changelog/22217.txt @@ -4,4 +4,8 @@ resource/aws_secretsmanager_secret: Fix erroneous diffs in `policy` when no chan ```release-note:bug resource/aws_secretsmanager_secret_policy: Fix erroneous diffs in `policy` when no changes made or policies are equivalent +``` + +```release-note:bug +resource/aws_iam_role: Fix eventual consistency problem with `arn` sometimes being a unique ID instead of the role ARN ``` \ No newline at end of file From 5c22ce85d74bbb753b9e6e6823481a0574726dba Mon Sep 17 00:00:00 2001 From: Dirk Avery Date: Tue, 14 Dec 2021 20:31:16 -0500 Subject: [PATCH 06/10] Linternational --- internal/service/secretsmanager/secret_test.go | 2 -- 1 file changed, 2 deletions(-) diff --git a/internal/service/secretsmanager/secret_test.go b/internal/service/secretsmanager/secret_test.go index fae5951271a..5ad988882a8 100644 --- a/internal/service/secretsmanager/secret_test.go +++ b/internal/service/secretsmanager/secret_test.go @@ -805,7 +805,6 @@ func testAccSecretPolicyConfig(rName string) string { return fmt.Sprintf(` resource "aws_iam_role" "test" { name = %[1]q - description = "a description" assume_role_policy = jsonencode({ Version = "2012-10-17" @@ -843,7 +842,6 @@ func testAccSecretPolicyEmptyConfig(rName string) string { return fmt.Sprintf(` resource "aws_iam_role" "test" { name = %[1]q - description = "a description" assume_role_policy = jsonencode({ Version = "2012-10-17" From d25b25aa2f135f75fc7ac1126b07488163256397 Mon Sep 17 00:00:00 2001 From: Dirk Avery Date: Wed, 15 Dec 2021 17:00:00 -0500 Subject: [PATCH 07/10] Rework secretsmanager policy diffs --- internal/service/iam/wait.go | 4 +- internal/service/secretsmanager/secret.go | 5 ++- .../service/secretsmanager/secret_policy.go | 40 +++++-------------- .../service/secretsmanager/secret_test.go | 7 +++- internal/verify/json.go | 6 ++- .../r/secretsmanager_secret.html.markdown | 2 +- ...secretsmanager_secret_policy.html.markdown | 7 +++- 7 files changed, 32 insertions(+), 39 deletions(-) diff --git a/internal/service/iam/wait.go b/internal/service/iam/wait.go index 0cb6673dcf9..e872dafc18f 100644 --- a/internal/service/iam/wait.go +++ b/internal/service/iam/wait.go @@ -30,8 +30,8 @@ func waitRoleARNIsNotUniqueID(conn *iam.IAM, id string, role *iam.Role) (*iam.Ro Target: []string{RoleStatusARNIsARN}, Refresh: statusRoleCreate(conn, id, role), Timeout: PropagationTimeout, - NotFoundChecks: 5, - ContinuousTargetOccurence: 4, + NotFoundChecks: 10, + ContinuousTargetOccurence: 5, } outputRaw, err := stateConf.WaitForState() diff --git a/internal/service/secretsmanager/secret.go b/internal/service/secretsmanager/secret.go index a1c8f99ae55..8294b8a8662 100644 --- a/internal/service/secretsmanager/secret.go +++ b/internal/service/secretsmanager/secret.go @@ -68,6 +68,7 @@ func ResourceSecret() *schema.Resource { "policy": { Type: schema.TypeString, Optional: true, + Computed: true, ValidateFunc: validation.StringIsJSON, DiffSuppressFunc: verify.SuppressEquivalentPolicyDiffs, StateFunc: func(v interface{}) string { @@ -325,7 +326,7 @@ func resourceSecretRead(d *schema.ResourceData, meta interface{}) error { d.Set("policy", policyToSet) } else { - d.Set("policy", "") + d.Set("policy", "{}") } d.Set("rotation_enabled", output.RotationEnabled) @@ -394,7 +395,7 @@ func resourceSecretUpdate(d *schema.ResourceData, meta interface{}) error { } if d.HasChange("policy") { - if v, ok := d.GetOk("policy"); ok && v.(string) != "" { + if v, ok := d.GetOk("policy"); ok && v.(string) != "" && v.(string) != "{}" { policy, err := structure.NormalizeJsonString(v.(string)) if err != nil { return fmt.Errorf("policy contains an invalid JSON: %w", err) diff --git a/internal/service/secretsmanager/secret_policy.go b/internal/service/secretsmanager/secret_policy.go index f953932255b..79606465ce1 100644 --- a/internal/service/secretsmanager/secret_policy.go +++ b/internal/service/secretsmanager/secret_policy.go @@ -71,11 +71,11 @@ func resourceSecretPolicyCreate(d *schema.ResourceData, meta interface{}) error } log.Printf("[DEBUG] Setting Secrets Manager Secret resource policy; %#v", input) - var res *secretsmanager.PutResourcePolicyOutput + var output *secretsmanager.PutResourcePolicyOutput err = resource.Retry(tfiam.PropagationTimeout, func() *resource.RetryError { var err error - res, err = conn.PutResourcePolicy(input) + output, err = conn.PutResourcePolicy(input) if tfawserr.ErrMessageContains(err, secretsmanager.ErrCodeMalformedPolicyDocumentException, "This resource policy contains an unsupported principal") { return resource.RetryableError(err) @@ -86,13 +86,13 @@ func resourceSecretPolicyCreate(d *schema.ResourceData, meta interface{}) error return nil }) if tfresource.TimedOut(err) { - res, err = conn.PutResourcePolicy(input) + output, err = conn.PutResourcePolicy(input) } if err != nil { return fmt.Errorf("error setting Secrets Manager Secret %q policy: %w", d.Id(), err) } - d.SetId(aws.StringValue(res.ARN)) + d.SetId(aws.StringValue(output.ARN)) return resourceSecretPolicyRead(d, meta) } @@ -104,28 +104,10 @@ func resourceSecretPolicyRead(d *schema.ResourceData, meta interface{}) error { SecretId: aws.String(d.Id()), } - var res *secretsmanager.GetResourcePolicyOutput - - err := resource.Retry(PropagationTimeout, func() *resource.RetryError { - var err error - - res, err = conn.GetResourcePolicy(input) - - if d.IsNewResource() && tfawserr.ErrCodeEquals(err, secretsmanager.ErrCodeResourceNotFoundException) { - return resource.RetryableError(err) - } - - if err != nil { - return resource.NonRetryableError(err) - } - - return nil + outputRaw, err := tfresource.RetryWhenNotFound(PropagationTimeout, func() (interface{}, error) { + return conn.GetResourcePolicy(input) }) - if tfresource.TimedOut(err) { - res, err = conn.GetResourcePolicy(input) - } - if !d.IsNewResource() && tfawserr.ErrCodeEquals(err, secretsmanager.ErrCodeResourceNotFoundException) { log.Printf("[WARN] Secrets Manager Secret Policy (%s) not found, removing from state", d.Id()) d.SetId("") @@ -136,12 +118,14 @@ func resourceSecretPolicyRead(d *schema.ResourceData, meta interface{}) error { return fmt.Errorf("error reading Secrets Manager Secret Policy (%s): %w", d.Id(), err) } - if res == nil { + output := outputRaw.(*secretsmanager.GetResourcePolicyOutput) + + if output == nil { return fmt.Errorf("error reading Secrets Manager Secret Policy (%s): empty response", d.Id()) } - if res.ResourcePolicy != nil { - policyToSet, err := verify.PolicyToSet(d.Get("policy").(string), aws.StringValue(res.ResourcePolicy)) + if output.ResourcePolicy != nil { + policyToSet, err := verify.PolicyToSet(d.Get("policy").(string), aws.StringValue(output.ResourcePolicy)) if err != nil { return err @@ -161,11 +145,9 @@ func resourceSecretPolicyUpdate(d *schema.ResourceData, meta interface{}) error if d.HasChanges("policy", "block_public_policy") { policy, err := structure.NormalizeJsonString(d.Get("policy").(string)) - if err != nil { return fmt.Errorf("policy contains an invalid JSON: %s", err) } - input := &secretsmanager.PutResourcePolicyInput{ ResourcePolicy: aws.String(policy), SecretId: aws.String(d.Id()), diff --git a/internal/service/secretsmanager/secret_test.go b/internal/service/secretsmanager/secret_test.go index 5ad988882a8..ad5f318b0c0 100644 --- a/internal/service/secretsmanager/secret_test.go +++ b/internal/service/secretsmanager/secret_test.go @@ -427,6 +427,7 @@ func TestAccSecretsManagerSecret_policy(t *testing.T) { Config: testAccSecretPolicyConfig(rName), Check: resource.ComposeTestCheckFunc( testAccCheckSecretExists(resourceName, &secret), + resource.TestCheckResourceAttr(resourceName, "description", "San Holo feat. Duskus"), resource.TestMatchResourceAttr(resourceName, "policy", regexp.MustCompile(`{"Action":"secretsmanager:GetSecretValue".+`)), ), @@ -435,7 +436,7 @@ func TestAccSecretsManagerSecret_policy(t *testing.T) { Config: testAccSecretPolicyEmptyConfig(rName), Check: resource.ComposeTestCheckFunc( testAccCheckSecretExists(resourceName, &secret), - resource.TestCheckResourceAttr(resourceName, "policy", ""), + resource.TestCheckResourceAttr(resourceName, "policy", "{}"), ), }, { @@ -821,6 +822,7 @@ resource "aws_iam_role" "test" { resource "aws_secretsmanager_secret" "test" { name = %[1]q + description = "San Holo feat. Duskus" policy = jsonencode({ Version = "2012-10-17" @@ -858,8 +860,9 @@ resource "aws_iam_role" "test" { resource "aws_secretsmanager_secret" "test" { name = %[1]q + description = "fred" - policy = "" + policy = "{}" } `, rName) } diff --git a/internal/verify/json.go b/internal/verify/json.go index 812f5d2e370..b57b123ab12 100644 --- a/internal/verify/json.go +++ b/internal/verify/json.go @@ -88,7 +88,11 @@ func SecondJSONUnlessEquivalent(old, new string) (string, error) { return "", nil } - if strings.TrimSpace(old) == "" { + if strings.TrimSpace(new) == "{}" { + return "{}", nil + } + + if strings.TrimSpace(old) == "" || strings.TrimSpace(old) == "{}" { return new, nil } diff --git a/website/docs/r/secretsmanager_secret.html.markdown b/website/docs/r/secretsmanager_secret.html.markdown index c0192d7b67a..2f0a31d5fef 100644 --- a/website/docs/r/secretsmanager_secret.html.markdown +++ b/website/docs/r/secretsmanager_secret.html.markdown @@ -47,7 +47,7 @@ The following arguments are supported: * `kms_key_id` - (Optional) ARN or Id of the AWS KMS customer master key (CMK) to be used to encrypt the secret values in the versions stored in this secret. If you don't specify this value, then Secrets Manager defaults to using the AWS account's default CMK (the one named `aws/secretsmanager`). If the default KMS CMK with that name doesn't yet exist, then AWS Secrets Manager creates it for you automatically the first time. * `name_prefix` - (Optional) Creates a unique name beginning with the specified prefix. Conflicts with `name`. * `name` - (Optional) Friendly name of the new secret. The secret name can consist of uppercase letters, lowercase letters, digits, and any of the following characters: `/_+=.@-` Conflicts with `name_prefix`. -* `policy` - (Optional) Valid JSON document representing a [resource policy](https://docs.aws.amazon.com/secretsmanager/latest/userguide/auth-and-access_resource-based-policies.html). For more information about building AWS IAM policy documents with Terraform, see the [AWS IAM Policy Document Guide](https://learn.hashicorp.com/terraform/aws/iam-policy). +* `policy` - (Optional) Valid JSON document representing a [resource policy](https://docs.aws.amazon.com/secretsmanager/latest/userguide/auth-and-access_resource-based-policies.html). For more information about building AWS IAM policy documents with Terraform, see the [AWS IAM Policy Document Guide](https://learn.hashicorp.com/terraform/aws/iam-policy). Removing `policy` from your configuration will not delete the policy since it could have been set by `aws_secretsmanager_secret_policy`. To delete the `policy`, set it to `"{}"` (an empty JSON document). * `recovery_window_in_days` - (Optional) Number of days that AWS Secrets Manager waits before it can delete the secret. This value can be `0` to force deletion without recovery or range from `7` to `30` days. The default value is `30`. * `replica` - (Optional) Configuration block to support secret replication. See details below. * `rotation_lambda_arn` - (Optional, **DEPRECATED**) ARN of the Lambda function that can rotate the secret. Use the `aws_secretsmanager_secret_rotation` resource to manage this configuration instead. As of version 2.67.0, removal of this configuration will no longer remove rotation due to supporting the new resource. Either import the new resource and remove the configuration or manually remove rotation. diff --git a/website/docs/r/secretsmanager_secret_policy.html.markdown b/website/docs/r/secretsmanager_secret_policy.html.markdown index b58b92fd346..7b3017c14c7 100644 --- a/website/docs/r/secretsmanager_secret_policy.html.markdown +++ b/website/docs/r/secretsmanager_secret_policy.html.markdown @@ -43,10 +43,13 @@ POLICY ## Argument Reference -The following arguments are supported: +The following arguments are required: +* `policy` - (Required) Valid JSON document representing a [resource policy](https://docs.aws.amazon.com/secretsmanager/latest/userguide/auth-and-access_resource-based-policies.html). For more information about building AWS IAM policy documents with Terraform, see the [AWS IAM Policy Document Guide](https://learn.hashicorp.com/terraform/aws/iam-policy). Unlike `aws_secretsmanager_secret`, where `policy` can be set to `"{}"` to delete the policy, `"{}"` is not a valid policy since `policy` is required. * `secret_arn` - (Required) Secret ARN. -* `policy` - (Required) A valid JSON document representing a [resource policy](https://docs.aws.amazon.com/secretsmanager/latest/userguide/auth-and-access_resource-based-policies.html). For more information about building AWS IAM policy documents with Terraform, see the [AWS IAM Policy Document Guide](https://learn.hashicorp.com/terraform/aws/iam-policy). + +The following arguments are optional: + * `block_public_policy` - (Optional) Makes an optional API call to Zelkova to validate the Resource Policy to prevent broad access to your secret. ## Attributes Reference From d6d29fb7df547d3cd3d0f8131eb49edc7dab7aaf Mon Sep 17 00:00:00 2001 From: Dirk Avery Date: Wed, 15 Dec 2021 17:05:42 -0500 Subject: [PATCH 08/10] Allow empty equivalence --- internal/verify/json.go | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/internal/verify/json.go b/internal/verify/json.go index b57b123ab12..5dcb2b7710c 100644 --- a/internal/verify/json.go +++ b/internal/verify/json.go @@ -15,6 +15,22 @@ import ( ) func SuppressEquivalentPolicyDiffs(k, old, new string, d *schema.ResourceData) bool { + if strings.TrimSpace(old) == "" && strings.TrimSpace(new) == "" { + return true + } + + if strings.TrimSpace(old) == "{}" && strings.TrimSpace(new) == "" { + return true + } + + if strings.TrimSpace(old) == "" && strings.TrimSpace(new) == "{}" { + return true + } + + if strings.TrimSpace(old) == "{}" && strings.TrimSpace(new) == "{}" { + return true + } + equivalent, err := awspolicy.PoliciesAreEquivalent(old, new) if err != nil { return false From 0bdac3736b9cbfa444567fcffb4d44a740d55111 Mon Sep 17 00:00:00 2001 From: Dirk Avery Date: Wed, 15 Dec 2021 17:10:00 -0500 Subject: [PATCH 09/10] Linterrogation --- internal/service/secretsmanager/secret_test.go | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/internal/service/secretsmanager/secret_test.go b/internal/service/secretsmanager/secret_test.go index ad5f318b0c0..b3de7245dc0 100644 --- a/internal/service/secretsmanager/secret_test.go +++ b/internal/service/secretsmanager/secret_test.go @@ -436,6 +436,7 @@ func TestAccSecretsManagerSecret_policy(t *testing.T) { Config: testAccSecretPolicyEmptyConfig(rName), Check: resource.ComposeTestCheckFunc( testAccCheckSecretExists(resourceName, &secret), + resource.TestCheckResourceAttr(resourceName, "description", "Poliça"), resource.TestCheckResourceAttr(resourceName, "policy", "{}"), ), }, @@ -821,7 +822,7 @@ resource "aws_iam_role" "test" { } resource "aws_secretsmanager_secret" "test" { - name = %[1]q + name = %[1]q description = "San Holo feat. Duskus" policy = jsonencode({ @@ -859,8 +860,8 @@ resource "aws_iam_role" "test" { } resource "aws_secretsmanager_secret" "test" { - name = %[1]q - description = "fred" + name = %[1]q + description = "Poliça" policy = "{}" } From 7ae5f1c8e66e471c2df370ecdeb3f6e0b0261650 Mon Sep 17 00:00:00 2001 From: Dirk Avery Date: Wed, 15 Dec 2021 17:24:56 -0500 Subject: [PATCH 10/10] Skip 3 region tests in GovCloud --- internal/acctest/acctest.go | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/internal/acctest/acctest.go b/internal/acctest/acctest.go index 7c1494a264d..ed282b15b61 100644 --- a/internal/acctest/acctest.go +++ b/internal/acctest/acctest.go @@ -620,6 +620,10 @@ func PreCheckMultipleRegion(t *testing.T, regions int) { } if regions >= 3 { + if thirdRegionPartition() == "aws-us-gov" || Partition() == "aws-us-gov" { + t.Skipf("wanted %d regions, partition (%s) only has 2 regions", regions, Partition()) + } + if Region() == ThirdRegion() { t.Fatalf("%s and %s must be set to different values for acceptance tests", conns.EnvVarDefaultRegion, conns.EnvVarThirdRegion) }