From 2ff9c2c2c7c33286a803c720879b6b1476dcb3b2 Mon Sep 17 00:00:00 2001 From: Atsushi Ishibashi Date: Mon, 20 Nov 2017 11:49:48 +0900 Subject: [PATCH 1/4] WIP --- aws/resource_aws_iam_role.go | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/aws/resource_aws_iam_role.go b/aws/resource_aws_iam_role.go index 518a12dc0e27..457519b49477 100644 --- a/aws/resource_aws_iam_role.go +++ b/aws/resource_aws_iam_role.go @@ -285,6 +285,25 @@ func resourceAwsIamRoleDelete(d *schema.ResourceData, meta interface{}) error { } } } + // For inline policies + inlinePoliciesResp, err := iamconn.ListRolePolicies(&iam.ListRolePoliciesInput{ + RoleName: aws.String(d.Id()), + }) + if err != nil { + return fmt.Errorf("Error listing inline Policies for IAM Role (%s) when trying to delete: %s", d.Id(), err) + } + // Loop and remove the Policies from the Role + if len(inlinePoliciesResp.PolicyNames) > 0 { + for _, i := range policiesResp.AttachedPolicies { + _, err := iamconn.DetachRolePolicy(&iam.DetachRolePolicyInput{ + PolicyArn: i.PolicyArn, + RoleName: aws.String(d.Id()), + }) + if err != nil { + return fmt.Errorf("Error deleting IAM Role %s: %s", d.Id(), err) + } + } + } } request := &iam.DeleteRoleInput{ From 543b8860b9e0e62845375f4ee488dd1b8a9de73b Mon Sep 17 00:00:00 2001 From: Atsushi Ishibashi Date: Tue, 21 Nov 2017 11:16:02 +0900 Subject: [PATCH 2/4] Delete inline policy when force_detach_policies=true --- aws/resource_aws_iam_role.go | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/aws/resource_aws_iam_role.go b/aws/resource_aws_iam_role.go index 457519b49477..e8c089b4d8fc 100644 --- a/aws/resource_aws_iam_role.go +++ b/aws/resource_aws_iam_role.go @@ -294,13 +294,13 @@ func resourceAwsIamRoleDelete(d *schema.ResourceData, meta interface{}) error { } // Loop and remove the Policies from the Role if len(inlinePoliciesResp.PolicyNames) > 0 { - for _, i := range policiesResp.AttachedPolicies { - _, err := iamconn.DetachRolePolicy(&iam.DetachRolePolicyInput{ - PolicyArn: i.PolicyArn, - RoleName: aws.String(d.Id()), + for _, i := range inlinePoliciesResp.PolicyNames { + _, err := iamconn.DeleteRolePolicy(&iam.DeleteRolePolicyInput{ + PolicyName: aws.String(i), + RoleName: aws.String(d.Id()), }) if err != nil { - return fmt.Errorf("Error deleting IAM Role %s: %s", d.Id(), err) + return fmt.Errorf("Error deleting inline policy of IAM Role %s: %s", d.Id(), err) } } } From 0a49da8387bab3cba95f187f2f3b5a7fb13fa622 Mon Sep 17 00:00:00 2001 From: Atsushi Ishibashi Date: Tue, 21 Nov 2017 11:55:45 +0900 Subject: [PATCH 3/4] Add TestAccAWSIAMRole_force_detach_policies for testacc --- aws/resource_aws_iam_role.go | 4 +- aws/resource_aws_iam_role_test.go | 87 +++++++++++++++++++++++++++++++ 2 files changed, 89 insertions(+), 2 deletions(-) diff --git a/aws/resource_aws_iam_role.go b/aws/resource_aws_iam_role.go index e8c089b4d8fc..f1b9d982dc09 100644 --- a/aws/resource_aws_iam_role.go +++ b/aws/resource_aws_iam_role.go @@ -294,9 +294,9 @@ func resourceAwsIamRoleDelete(d *schema.ResourceData, meta interface{}) error { } // Loop and remove the Policies from the Role if len(inlinePoliciesResp.PolicyNames) > 0 { - for _, i := range inlinePoliciesResp.PolicyNames { + for _, pname := range inlinePoliciesResp.PolicyNames { _, err := iamconn.DeleteRolePolicy(&iam.DeleteRolePolicyInput{ - PolicyName: aws.String(i), + PolicyName: pname, RoleName: aws.String(d.Id()), }) if err != nil { diff --git a/aws/resource_aws_iam_role_test.go b/aws/resource_aws_iam_role_test.go index 52d22c7d9136..a190037ba7d6 100644 --- a/aws/resource_aws_iam_role_test.go +++ b/aws/resource_aws_iam_role_test.go @@ -138,6 +138,25 @@ 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), + ), + }, + }, + }) +} + func testAccCheckAWSRoleDestroy(s *terraform.State) error { iamconn := testAccProvider.Meta().(*AWSClient).iamconn @@ -375,3 +394,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 = < Date: Thu, 28 Dec 2017 17:23:43 +0900 Subject: [PATCH 4/4] Use paging, modify test --- aws/resource_aws_iam_role.go | 14 ++++++++++---- aws/resource_aws_iam_role_test.go | 32 +++++++++++++++++++++++++++++++ 2 files changed, 42 insertions(+), 4 deletions(-) diff --git a/aws/resource_aws_iam_role.go b/aws/resource_aws_iam_role.go index f1b9d982dc09..439868062d97 100644 --- a/aws/resource_aws_iam_role.go +++ b/aws/resource_aws_iam_role.go @@ -285,16 +285,22 @@ func resourceAwsIamRoleDelete(d *schema.ResourceData, meta interface{}) error { } } } + // For inline policies - inlinePoliciesResp, err := iamconn.ListRolePolicies(&iam.ListRolePoliciesInput{ + 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) } - // Loop and remove the Policies from the Role - if len(inlinePoliciesResp.PolicyNames) > 0 { - for _, pname := range inlinePoliciesResp.PolicyNames { + if len(rolePolicyNames) > 0 { + for _, pname := range rolePolicyNames { _, err := iamconn.DeleteRolePolicy(&iam.DeleteRolePolicyInput{ PolicyName: pname, RoleName: aws.String(d.Id()), diff --git a/aws/resource_aws_iam_role_test.go b/aws/resource_aws_iam_role_test.go index a190037ba7d6..5de50c37a01d 100644 --- a/aws/resource_aws_iam_role_test.go +++ b/aws/resource_aws_iam_role_test.go @@ -151,6 +151,7 @@ func TestAccAWSIAMRole_force_detach_policies(t *testing.T) { Config: testAccAWSIAMRoleConfig_force_detach_policies(rName), Check: resource.ComposeTestCheckFunc( testAccCheckAWSRoleExists("aws_iam_role.test", &conf), + testAccAddAwsIAMRolePolicy("aws_iam_role.test"), ), }, }, @@ -229,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" {