diff --git a/aws/resource_aws_iam_role.go b/aws/resource_aws_iam_role.go index 518a12dc0e2..439868062d9 100644 --- a/aws/resource_aws_iam_role.go +++ b/aws/resource_aws_iam_role.go @@ -285,6 +285,31 @@ func resourceAwsIamRoleDelete(d *schema.ResourceData, meta interface{}) error { } } } + + // For inline policies + rolePolicyNames := make([]*string, 0) + err = iamconn.ListRolePoliciesPages(&iam.ListRolePoliciesInput{ + RoleName: aws.String(d.Id()), + }, func(page *iam.ListRolePoliciesOutput, lastPage bool) bool { + for _, v := range page.PolicyNames { + rolePolicyNames = append(rolePolicyNames, v) + } + return len(page.PolicyNames) > 0 + }) + if err != nil { + return fmt.Errorf("Error listing inline Policies for IAM Role (%s) when trying to delete: %s", d.Id(), err) + } + if len(rolePolicyNames) > 0 { + for _, pname := range rolePolicyNames { + _, err := iamconn.DeleteRolePolicy(&iam.DeleteRolePolicyInput{ + PolicyName: pname, + RoleName: aws.String(d.Id()), + }) + if err != nil { + return fmt.Errorf("Error deleting inline policy of IAM Role %s: %s", d.Id(), err) + } + } + } } request := &iam.DeleteRoleInput{ diff --git a/aws/resource_aws_iam_role_test.go b/aws/resource_aws_iam_role_test.go index 52d22c7d913..5de50c37a01 100644 --- a/aws/resource_aws_iam_role_test.go +++ b/aws/resource_aws_iam_role_test.go @@ -138,6 +138,26 @@ func TestAccAWSIAMRole_badJSON(t *testing.T) { }) } +func TestAccAWSIAMRole_force_detach_policies(t *testing.T) { + var conf iam.GetRoleOutput + rName := acctest.RandString(10) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckAWSRoleDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAWSIAMRoleConfig_force_detach_policies(rName), + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSRoleExists("aws_iam_role.test", &conf), + testAccAddAwsIAMRolePolicy("aws_iam_role.test"), + ), + }, + }, + }) +} + func testAccCheckAWSRoleDestroy(s *terraform.State) error { iamconn := testAccProvider.Meta().(*AWSClient).iamconn @@ -210,6 +230,37 @@ func testAccCheckAWSRoleGeneratedNamePrefix(resource, prefix string) resource.Te } } +// Attach inline policy outside of terraform CRUD. +func testAccAddAwsIAMRolePolicy(n string) resource.TestCheckFunc { + return func(s *terraform.State) error { + rs, ok := s.RootModule().Resources[n] + if !ok { + return fmt.Errorf("Resource not found") + } + if rs.Primary.ID == "" { + return fmt.Errorf("No Role name is set") + } + + iamconn := testAccProvider.Meta().(*AWSClient).iamconn + + input := &iam.PutRolePolicyInput{ + RoleName: aws.String(rs.Primary.ID), + PolicyDocument: aws.String(`{ + "Version": "2012-10-17", + "Statement": { + "Effect": "Allow", + "Action": "*", + "Resource": "*" + } + }`), + PolicyName: aws.String(resource.UniqueId()), + } + + _, err := iamconn.PutRolePolicy(input) + return err + } +} + func testAccAWSIAMRoleConfig(rName string) string { return fmt.Sprintf(` resource "aws_iam_role" "role" { @@ -375,3 +426,71 @@ POLICY } `, rName) } + +func testAccAWSIAMRoleConfig_force_detach_policies(rName string) string { + return fmt.Sprintf(` +resource "aws_iam_role_policy" "test" { + name = "tf-iam-role-policy-%s" + role = "${aws_iam_role.test.id}" + + policy = <