From 387b80b86519d5b50cedc750c4c1518c50719066 Mon Sep 17 00:00:00 2001 From: Dirk Avery Date: Mon, 22 Feb 2021 11:53:22 -0500 Subject: [PATCH] resource/iam_role: Adjust after review --- .changelog/5904.txt | 2 +- aws/resource_aws_iam_role.go | 31 ++- aws/resource_aws_iam_role_test.go | 193 +++++++----------- .../r/iam_policy_attachment.html.markdown | 2 + website/docs/r/iam_role.html.markdown | 10 +- website/docs/r/iam_role_policy.html.markdown | 2 + .../r/iam_role_policy_attachment.markdown | 2 + 7 files changed, 109 insertions(+), 133 deletions(-) diff --git a/.changelog/5904.txt b/.changelog/5904.txt index cee17c908519..cc516468999f 100644 --- a/.changelog/5904.txt +++ b/.changelog/5904.txt @@ -1,3 +1,3 @@ ```release-note:enhancement -resource/iam_role: Add support for exclusive IAM role policies with `inline_policy` and `managed_policy_arns` arguments +resource/aws_iam_role: Add support for exclusive policy management `inline_policy` and `managed_policy_arns` arguments ``` \ No newline at end of file diff --git a/aws/resource_aws_iam_role.go b/aws/resource_aws_iam_role.go index 9d9f5a77bf24..b2451459085a 100644 --- a/aws/resource_aws_iam_role.go +++ b/aws/resource_aws_iam_role.go @@ -118,9 +118,12 @@ func resourceAwsIamRole() *schema.Resource { Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ "name": { - Type: schema.TypeString, - Optional: true, - ValidateFunc: validateIamRolePolicyName, + Type: schema.TypeString, + Optional: true, + ValidateFunc: validation.All( + validation.StringIsNotEmpty, + validateIamRolePolicyName, + ), }, "policy": { Type: schema.TypeString, @@ -275,15 +278,15 @@ func resourceAwsIamRoleRead(d *schema.ResourceData, meta interface{}) error { return err } - inlinePolicies, err := readIamInlinePolicies(*role.RoleName, meta) + inlinePolicies, err := readIamInlinePolicies(aws.StringValue(role.RoleName), meta) if err != nil { return fmt.Errorf("reading inline policies for IAM role %s, error: %s", d.Id(), err) } if err := d.Set("inline_policy", flattenIamInlinePolicies(inlinePolicies)); err != nil { - return fmt.Errorf("setting attribute_name: %w", err) + return fmt.Errorf("error setting inline_policy: %w", err) } - managedPolicies, err := readIamRolePolicyAttachments(iamconn, *role.RoleName) + managedPolicies, err := readIamRolePolicyAttachments(iamconn, aws.StringValue(role.RoleName)) if err != nil { return fmt.Errorf("reading managed policies for IAM role %s, error: %s", d.Id(), err) } @@ -393,7 +396,9 @@ func resourceAwsIamRoleUpdate(d *schema.ResourceData, meta interface{}) error { continue } - policyNames = append(policyNames, aws.String(tfMap["name"].(string))) + if v, ok := tfMap["name"].(string); ok && v != "" { + policyNames = append(policyNames, aws.String(tfMap["name"].(string))) + } } if err := deleteIamRolePolicies(iamconn, roleName, policyNames); err != nil { return fmt.Errorf("unable to delete inline policies: %w", err) @@ -651,9 +656,15 @@ func expandIamInlinePolicy(roleName string, tfMap map[string]interface{}) *iam.P } apiObject := &iam.PutRolePolicyInput{ - RoleName: aws.String(roleName), - PolicyName: aws.String(tfMap["name"].(string)), - PolicyDocument: aws.String(tfMap["policy"].(string)), + RoleName: aws.String(roleName), + } + + if v, ok := tfMap["name"].(string); ok && v != "" { + apiObject.PolicyName = aws.String(v) + } + + if v, ok := tfMap["policy"].(string); ok && v != "" { + apiObject.PolicyDocument = aws.String(v) } return apiObject diff --git a/aws/resource_aws_iam_role_test.go b/aws/resource_aws_iam_role_test.go index 09678a29a9d0..ecf53a70c9f3 100644 --- a/aws/resource_aws_iam_role_test.go +++ b/aws/resource_aws_iam_role_test.go @@ -511,7 +511,6 @@ func TestAccAWSIAMRole_policyBasicInline(t *testing.T) { Config: testAccAWSRolePolicyInlineConfig(rName, policyName1), Check: resource.ComposeTestCheckFunc( testAccCheckAWSRoleExists(resourceName, &role), - testAccCheckAWSRolePolicyCheckInline(&role, rName, []string{policyName1}), resource.TestCheckResourceAttr(resourceName, "inline_policy.#", "1"), resource.TestCheckResourceAttr(resourceName, "name", rName), resource.TestCheckResourceAttr(resourceName, "managed_policy_arns.#", "0"), @@ -521,7 +520,6 @@ func TestAccAWSIAMRole_policyBasicInline(t *testing.T) { Config: testAccAWSRolePolicyInlineConfigUpdate(rName, policyName2, policyName3), Check: resource.ComposeTestCheckFunc( testAccCheckAWSRoleExists(resourceName, &role), - testAccCheckAWSRolePolicyCheckInline(&role, rName, []string{policyName2, policyName3}), resource.TestCheckResourceAttr(resourceName, "inline_policy.#", "2"), resource.TestCheckResourceAttr(resourceName, "managed_policy_arns.#", "0"), ), @@ -530,7 +528,6 @@ func TestAccAWSIAMRole_policyBasicInline(t *testing.T) { Config: testAccAWSRolePolicyInlineConfigUpdateDown(rName, policyName3), Check: resource.ComposeTestCheckFunc( testAccCheckAWSRoleExists(resourceName, &role), - testAccCheckAWSRolePolicyCheckInline(&role, rName, []string{policyName3}), resource.TestCheckResourceAttr(resourceName, "inline_policy.#", "1"), resource.TestCheckResourceAttr(resourceName, "managed_policy_arns.#", "0"), ), @@ -558,7 +555,6 @@ func TestAccAWSIAMRole_policyBasicInlineEmpty(t *testing.T) { Config: testAccAWSRolePolicyEmptyInlineConfig(rName), Check: resource.ComposeTestCheckFunc( testAccCheckAWSRoleExists(resourceName, &role), - testAccCheckAWSRolePolicyCheckInline(&role, rName, []string{}), ), }, }, @@ -582,7 +578,6 @@ func TestAccAWSIAMRole_policyBasicManaged(t *testing.T) { Config: testAccAWSRolePolicyManagedConfig(rName, policyName1), Check: resource.ComposeTestCheckFunc( testAccCheckAWSRoleExists(resourceName, &role), - testAccCheckAWSRolePolicyCheckManaged(&role, rName, []string{policyName1}), resource.TestCheckResourceAttr(resourceName, "name", rName), resource.TestCheckResourceAttr(resourceName, "managed_policy_arns.#", "1"), ), @@ -591,7 +586,6 @@ func TestAccAWSIAMRole_policyBasicManaged(t *testing.T) { Config: testAccAWSRolePolicyManagedConfigUpdate(rName, policyName1, policyName2, policyName3), Check: resource.ComposeTestCheckFunc( testAccCheckAWSRoleExists(resourceName, &role), - testAccCheckAWSRolePolicyCheckManaged(&role, rName, []string{policyName2, policyName3}), resource.TestCheckResourceAttr(resourceName, "managed_policy_arns.#", "2"), ), }, @@ -599,7 +593,6 @@ func TestAccAWSIAMRole_policyBasicManaged(t *testing.T) { Config: testAccAWSRolePolicyManagedConfigUpdateDown(rName, policyName1, policyName2, policyName3), Check: resource.ComposeTestCheckFunc( testAccCheckAWSRoleExists(resourceName, &role), - testAccCheckAWSRolePolicyCheckManaged(&role, rName, []string{policyName3}), resource.TestCheckResourceAttr(resourceName, "managed_policy_arns.#", "1"), ), }, @@ -630,7 +623,6 @@ func TestAccAWSIAMRole_policyOutOfBandRemovalAddedBack_managedNonEmpty(t *testin Check: resource.ComposeTestCheckFunc( testAccCheckAWSRoleExists(resourceName, &role), testAccCheckAWSRolePolicyDetachManagedPolicy(&role, policyName), - testAccCheckAWSRolePolicyCheckManaged(&role, rName, []string{}), ), ExpectNonEmptyPlan: true, }, @@ -638,7 +630,6 @@ func TestAccAWSIAMRole_policyOutOfBandRemovalAddedBack_managedNonEmpty(t *testin Config: testAccAWSRolePolicyManagedConfig(rName, policyName), Check: resource.ComposeTestCheckFunc( testAccCheckAWSRoleExists(resourceName, &role), - testAccCheckAWSRolePolicyCheckManaged(&role, rName, []string{policyName}), resource.TestCheckResourceAttr(resourceName, "managed_policy_arns.#", "1"), ), }, @@ -664,7 +655,6 @@ func TestAccAWSIAMRole_policyOutOfBandRemovalAddedBack_inlineNonEmpty(t *testing Check: resource.ComposeTestCheckFunc( testAccCheckAWSRoleExists(resourceName, &role), testAccCheckAWSRolePolicyRemoveInlinePolicy(&role, policyName), - testAccCheckAWSRolePolicyCheckInline(&role, rName, []string{}), ), ExpectNonEmptyPlan: true, }, @@ -672,7 +662,6 @@ func TestAccAWSIAMRole_policyOutOfBandRemovalAddedBack_inlineNonEmpty(t *testing Config: testAccAWSRolePolicyInlineConfig(rName, policyName), Check: resource.ComposeTestCheckFunc( testAccCheckAWSRoleExists(resourceName, &role), - testAccCheckAWSRolePolicyCheckInline(&role, rName, []string{policyName}), resource.TestCheckResourceAttr(resourceName, "inline_policy.#", "1"), ), }, @@ -699,7 +688,6 @@ func TestAccAWSIAMRole_policyOutOfBandAdditionRemoved_managedNonEmpty(t *testing Check: resource.ComposeTestCheckFunc( testAccCheckAWSRoleExists(resourceName, &role), testAccCheckAWSRolePolicyAttachManagedPolicy(&role, policyName2), - testAccCheckAWSRolePolicyCheckManaged(&role, rName, []string{policyName1, policyName2}), ), ExpectNonEmptyPlan: true, }, @@ -707,7 +695,6 @@ func TestAccAWSIAMRole_policyOutOfBandAdditionRemoved_managedNonEmpty(t *testing Config: testAccAWSRolePolicyExtraManagedConfig(rName, policyName1, policyName2), Check: resource.ComposeTestCheckFunc( testAccCheckAWSRoleExists(resourceName, &role), - testAccCheckAWSRolePolicyCheckManaged(&role, rName, []string{policyName1}), resource.TestCheckResourceAttr(resourceName, "managed_policy_arns.#", "1"), ), }, @@ -734,7 +721,6 @@ func TestAccAWSIAMRole_policyOutOfBandAdditionRemoved_inlineNonEmpty(t *testing. Check: resource.ComposeTestCheckFunc( testAccCheckAWSRoleExists(resourceName, &role), testAccCheckAWSRolePolicyAddInlinePolicy(&role, policyName2), - testAccCheckAWSRolePolicyCheckInline(&role, rName, []string{policyName1, policyName2}), ), ExpectNonEmptyPlan: true, }, @@ -742,7 +728,6 @@ func TestAccAWSIAMRole_policyOutOfBandAdditionRemoved_inlineNonEmpty(t *testing. Config: testAccAWSRolePolicyInlineConfig(rName, policyName1), Check: resource.ComposeTestCheckFunc( testAccCheckAWSRoleExists(resourceName, &role), - testAccCheckAWSRolePolicyCheckInline(&role, rName, []string{policyName1}), resource.TestCheckResourceAttr(resourceName, "inline_policy.#", "1"), resource.TestCheckResourceAttr(resourceName, "managed_policy_arns.#", "0"), ), @@ -770,7 +755,6 @@ func TestAccAWSIAMRole_policyOutOfBandAdditionIgnored_inlineNonExistent(t *testi Check: resource.ComposeTestCheckFunc( testAccCheckAWSRoleExists(resourceName, &role), testAccCheckAWSRolePolicyAddInlinePolicy(&role, policyName1), - testAccCheckAWSRolePolicyCheckInline(&role, rName, []string{policyName1}), ), }, { @@ -778,14 +762,12 @@ func TestAccAWSIAMRole_policyOutOfBandAdditionIgnored_inlineNonExistent(t *testi Check: resource.ComposeTestCheckFunc( testAccCheckAWSRoleExists(resourceName, &role), testAccCheckAWSRolePolicyAddInlinePolicy(&role, policyName2), - testAccCheckAWSRolePolicyCheckInline(&role, rName, []string{policyName1, policyName2}), ), }, { Config: testAccAWSRolePolicyNoInlineConfig(rName), Check: resource.ComposeTestCheckFunc( testAccCheckAWSRoleExists(resourceName, &role), - testAccCheckAWSRolePolicyCheckInline(&role, rName, []string{policyName1, policyName2}), testAccCheckAWSRolePolicyRemoveInlinePolicy(&role, policyName1), testAccCheckAWSRolePolicyRemoveInlinePolicy(&role, policyName2), ), @@ -812,14 +794,12 @@ func TestAccAWSIAMRole_policyOutOfBandAdditionIgnored_managedNonExistent(t *test Check: resource.ComposeTestCheckFunc( testAccCheckAWSRoleExists(resourceName, &role), testAccCheckAWSRolePolicyAttachManagedPolicy(&role, policyName), - testAccCheckAWSRolePolicyCheckManaged(&role, rName, []string{policyName}), ), }, { Config: testAccAWSRolePolicyNoManagedConfig(rName, policyName), Check: resource.ComposeTestCheckFunc( testAccCheckAWSRoleExists(resourceName, &role), - testAccCheckAWSRolePolicyCheckManaged(&role, rName, []string{policyName}), testAccCheckAWSRolePolicyDetachManagedPolicy(&role, policyName), ), }, @@ -845,7 +825,6 @@ func TestAccAWSIAMRole_policyOutOfBandAdditionRemoved_inlineEmpty(t *testing.T) Check: resource.ComposeTestCheckFunc( testAccCheckAWSRoleExists(resourceName, &role), testAccCheckAWSRolePolicyAddInlinePolicy(&role, policyName), - testAccCheckAWSRolePolicyCheckInline(&role, rName, []string{policyName}), ), ExpectNonEmptyPlan: true, }, @@ -853,7 +832,6 @@ func TestAccAWSIAMRole_policyOutOfBandAdditionRemoved_inlineEmpty(t *testing.T) Config: testAccAWSRolePolicyEmptyInlineConfig(rName), Check: resource.ComposeTestCheckFunc( testAccCheckAWSRoleExists(resourceName, &role), - testAccCheckAWSRolePolicyCheckInline(&role, rName, []string{}), ), }, }, @@ -878,7 +856,6 @@ func TestAccAWSIAMRole_policyOutOfBandAdditionRemoved_managedEmpty(t *testing.T) Check: resource.ComposeTestCheckFunc( testAccCheckAWSRoleExists(resourceName, &role), testAccCheckAWSRolePolicyAttachManagedPolicy(&role, policyName), - testAccCheckAWSRolePolicyCheckManaged(&role, rName, []string{policyName}), ), ExpectNonEmptyPlan: true, }, @@ -886,7 +863,6 @@ func TestAccAWSIAMRole_policyOutOfBandAdditionRemoved_managedEmpty(t *testing.T) Config: testAccAWSRolePolicyEmptyManagedConfig(rName, policyName), Check: resource.ComposeTestCheckFunc( testAccCheckAWSRoleExists(resourceName, &role), - testAccCheckAWSRolePolicyCheckManaged(&role, rName, []string{}), ), }, }, @@ -1029,63 +1005,6 @@ func testAccCheckAWSRolePermissionsBoundary(getRoleOutput *iam.GetRoleOutput, ex } } -func testAccCheckAWSRolePolicyCheckInline(role *iam.GetRoleOutput, roleName string, inlinePolicies []string) resource.TestCheckFunc { - return func(s *terraform.State) error { - if !strings.Contains(*role.Role.RoleName, roleName) { - return fmt.Errorf("bad role: expected %s, got %s", roleName, *role.Role.RoleName) - } - - conn := testAccProvider.Meta().(*AWSClient).iamconn - - policyNames, err := readIamRolePolicyNames(conn, roleName) - if err != nil { - return fmt.Errorf("reading role (%s): %w", roleName, err) - } - - var inlinePolicyList []string - for _, name := range policyNames { - inlinePolicyList = append(inlinePolicyList, aws.StringValue(name)) - } - - if !compareStringSlices(inlinePolicyList, inlinePolicies) { - return fmt.Errorf("inline policies did not match: %s (from AWS) to %s (expected)", strings.Join(inlinePolicyList, ","), strings.Join(inlinePolicies, ",")) - } - - return nil - } -} - -func testAccCheckAWSRolePolicyCheckManaged(role *iam.GetRoleOutput, roleName string, managedPolicies []string) resource.TestCheckFunc { - return func(s *terraform.State) error { - if !strings.Contains(*role.Role.RoleName, roleName) { - return fmt.Errorf("bad role: expected %s, got %s", roleName, *role.Role.RoleName) - } - - conn := testAccProvider.Meta().(*AWSClient).iamconn - - var managedPolicyList []string - input := &iam.ListAttachedRolePoliciesInput{ - RoleName: aws.String(roleName), - } - - err := conn.ListAttachedRolePoliciesPages(input, func(page *iam.ListAttachedRolePoliciesOutput, lastPage bool) bool { - for _, v := range page.AttachedPolicies { - managedPolicyList = append(managedPolicyList, aws.StringValue(v.PolicyName)) - } - return !lastPage - }) - if err != nil && !tfawserr.ErrCodeEquals(err, iam.ErrCodeNoSuchEntityException) { - return err - } - - if !compareStringSlices(managedPolicyList, managedPolicies) { - return fmt.Errorf("managed policies did not match: %s (from AWS) to %s (expected)", strings.Join(managedPolicyList, ","), strings.Join(managedPolicies, ",")) - } - - return nil - } -} - func testAccCheckAWSRolePolicyDetachManagedPolicy(role *iam.GetRoleOutput, policyName string) resource.TestCheckFunc { return func(s *terraform.State) error { conn := testAccProvider.Meta().(*AWSClient).iamconn @@ -1212,6 +1131,8 @@ func compareStringSlices(a []string, b []string) bool { func testAccCheckIAMRoleConfig_MaxSessionDuration(rName string, maxSessionDuration int) string { return fmt.Sprintf(` +data "aws_partition" "current" {} + resource "aws_iam_role" "test" { name = "test-role-%s" path = "/" @@ -1225,7 +1146,7 @@ resource "aws_iam_role" "test" { "Effect": "Allow", "Principal": { "Service": [ - "ec2.amazonaws.com" + "ec2.${data.aws_partition.current.dns_suffix}" ] }, "Action": [ @@ -1241,6 +1162,8 @@ EOF func testAccCheckIAMRoleConfig_PermissionsBoundary(rName, permissionsBoundary string) string { return fmt.Sprintf(` +data "aws_partition" "current" {} + resource "aws_iam_role" "test" { assume_role_policy = < **NOTE:** The usage of this resource conflicts with the `aws_iam_group_policy_attachment`, `aws_iam_role_policy_attachment`, and `aws_iam_user_policy_attachment` resources and will permanently show a difference if both are defined. +~> **NOTE:** For a given role, this resource is incompatible with using [`aws_iam_role`'s](/docs/providers/aws/r/iam_role_policy_attachment.html) `managed_policy_arns` argument. If you use the `aws_iam_role`.`managed_policy_arns` argument, the `aws_iam_role` resource will take over exclusive management of the role's managed policy attachments. If you attempt to manage a role's policies by multiple means, you will get resource cycling and/or errors. + ## Example Usage ```hcl diff --git a/website/docs/r/iam_role.html.markdown b/website/docs/r/iam_role.html.markdown index a7f35057f653..e8a95f11bce5 100644 --- a/website/docs/r/iam_role.html.markdown +++ b/website/docs/r/iam_role.html.markdown @@ -10,9 +10,9 @@ description: |- Provides an IAM role. -~> *NOTE:* If policies are attached to the role via the [`aws_iam_policy_attachment` resource](/docs/providers/aws/r/iam_policy_attachment.html) and you are modifying the role `name` or `path`, the `force_detach_policies` argument must be set to `true` and applied before attempting the operation otherwise you will encounter a `DeleteConflict` error. The [`aws_iam_role_policy_attachment` resource (recommended)](/docs/providers/aws/r/iam_role_policy_attachment.html) does not have this requirement. +~> **NOTE:** If policies are attached to the role via the [`aws_iam_policy_attachment` resource](/docs/providers/aws/r/iam_policy_attachment.html) and you are modifying the role `name` or `path`, the `force_detach_policies` argument must be set to `true` and applied before attempting the operation otherwise you will encounter a `DeleteConflict` error. The [`aws_iam_role_policy_attachment` resource (recommended)](/docs/providers/aws/r/iam_role_policy_attachment.html) does not have this requirement. -~> *NOTE:* If you use this resource's `managed_policy_arns` argument or `inline_policy` configuration blocks, this resource will take over exclusive management of the role's respective policy types (e.g., both policy types if both arguments are used). These arguments are incompatible with other ways of managing a role's policies, such as [`aws_iam_policy_attachment`](/docs/providers/aws/r/iam_policy_attachment.html), [`aws_iam_role_policy_attachment`](/docs/providers/aws/r/iam_role_policy_attachment.html), and [`aws_iam_role_policy`](/docs/providers/aws/r/iam_role_policy.html). If you attempt to manage a role's policies by multiple means, you will get resource cycling and/or errors. +~> **NOTE:** If you use this resource's `managed_policy_arns` argument or `inline_policy` configuration blocks, this resource will take over exclusive management of the role's respective policy types (e.g., both policy types if both arguments are used). These arguments are incompatible with other ways of managing a role's policies, such as [`aws_iam_policy_attachment`](/docs/providers/aws/r/iam_policy_attachment.html), [`aws_iam_role_policy_attachment`](/docs/providers/aws/r/iam_role_policy_attachment.html), and [`aws_iam_role_policy`](/docs/providers/aws/r/iam_role_policy.html). If you attempt to manage a role's policies by multiple means, you will get resource cycling and/or errors. ## Example Usage @@ -197,8 +197,8 @@ The following arguments are optional: * `description` - (Optional) Description of the role. * `force_detach_policies` - (Optional) Whether to force detaching any policies the role has before destroying it. Defaults to `false`. -* `inline_policy` - (Optional) Configuration block defining an exclusive set of IAM inline policies associated with the IAM role. Defined below. -* `managed_policy_arns` - (Optional) Set of exclusive IAM managed policy ARNs to attach to the IAM role. When a configuration does not include this attribute, Terraform will ignore out-of-band policy attachments on the next `apply`. However, when you include it, Terraform will, on the next `apply`, align the role's policy attachments with this set by attaching or detaching managed policies. This includes detaching all out-of-band attachments when you include an empty set (i.e., `managed_policy_arns = []`). +* `inline_policy` - (Optional) Configuration block defining an exclusive set of IAM inline policies associated with the IAM role. Defined below. If no blocks are configured, Terraform will ignore any managing any inline policies in this resource. Configuring one empty block (i.e., `inline_policy {}`) will cause Terraform to remove _all_ inline policies. +* `managed_policy_arns` - (Optional) Set of exclusive IAM managed policy ARNs to attach to the IAM role. If this attribute is not configured, Terraform will ignore policy attachments to this resource. When configured, Terraform will align the role's managed policy attachments with this set by attaching or detaching managed policies. Configuring an empty set (i.e., `managed_policy_arns = []`) will cause Terraform to remove _all_ managed policy attachments. * `max_session_duration` - (Optional) Maximum session duration (in seconds) that you want to set for the specified role. If you do not specify a value for this setting, the default maximum of one hour is applied. This setting can have a value from 1 hour to 12 hours. * `name` - (Optional, Forces new resource) Friendly name of the role. If omitted, Terraform will assign a random, unique name. See [IAM Identifiers](https://docs.aws.amazon.com/IAM/latest/UserGuide/Using_Identifiers.html) for more information. * `name_prefix` - (Optional, Forces new resource) Creates a unique friendly name beginning with the specified prefix. Conflicts with `name`. @@ -208,8 +208,6 @@ The following arguments are optional: ### inline_policy -If the `inline_policy` configuration block is not used, Terraform will ignore the role's inline policy changes on the next `apply`. Using an empty `inline_policy` (i.e., `inline_policy {}`) will cause Terraform to remove _all_ inline policies that were added out-of-band on the next `apply`. - This configuration block supports the following: * `name` - (Required) Name of the role policy. diff --git a/website/docs/r/iam_role_policy.html.markdown b/website/docs/r/iam_role_policy.html.markdown index dc081aa826ad..bf8b105cd1e5 100644 --- a/website/docs/r/iam_role_policy.html.markdown +++ b/website/docs/r/iam_role_policy.html.markdown @@ -10,6 +10,8 @@ description: |- Provides an IAM role inline policy. +~> **NOTE:** For a given role, this resource is incompatible with using the [`aws_iam_role`](/docs/providers/aws/r/iam_role.html) resource's `inline_policy` argument. If you use `aws_iam_role`.`inline_policy` configuration blocks, the `aws_iam_role` resource will take over exclusive management of the role's inline policies. Attempting to manage a role's policies by multiple means will cause resource cycling and/or errors. + ## Example Usage ```hcl diff --git a/website/docs/r/iam_role_policy_attachment.markdown b/website/docs/r/iam_role_policy_attachment.markdown index 4c3cd7845deb..6a036316f909 100644 --- a/website/docs/r/iam_role_policy_attachment.markdown +++ b/website/docs/r/iam_role_policy_attachment.markdown @@ -12,6 +12,8 @@ Attaches a Managed IAM Policy to an IAM role ~> **NOTE:** The usage of this resource conflicts with the `aws_iam_policy_attachment` resource and will permanently show a difference if both are defined. +~> **NOTE:** For a given role, this resource is incompatible with using the [`aws_iam_role`](/docs/providers/aws/r/iam_role_policy_attachment.html) resource's `managed_policy_arns` argument. If you use the `aws_iam_role`.`managed_policy_arns` argument, the `aws_iam_role` resource will take over exclusive management of the role's managed policies. Attempting to manage a role's policies by multiple means will cause resource cycling and/or errors. + ## Example Usage ```hcl