provider/aws: Delete access keys before deleting IAM user (#7766)

* provider/aws: Delete access keys before deleting IAM user

* provider/aws: Put IAM key removal behind force_destroy option

* provider/aws: Move all access key deletion under force_destroy

* Add iam_user force_destroy to website

* provider/aws: Improve clarity of looping over pages in delete IAM user
This commit is contained in:
David Tolnay 2016-07-25 00:15:03 -07:00 committed by Radek Simko
parent 9539b25966
commit ad62f09061
2 changed files with 48 additions and 26 deletions

View File

@ -48,6 +48,12 @@ func resourceAwsIamUser() *schema.Resource {
Default: "/", Default: "/",
ForceNew: true, ForceNew: true,
}, },
"force_destroy": &schema.Schema{
Type: schema.TypeBool,
Optional: true,
Default: false,
Description: "Delete user even if it has non-Terraform-managed IAM access keys",
},
}, },
} }
} }
@ -132,39 +138,25 @@ func resourceAwsIamUserUpdate(d *schema.ResourceData, meta interface{}) error {
} }
return nil return nil
} }
func resourceAwsIamUserDelete(d *schema.ResourceData, meta interface{}) error { func resourceAwsIamUserDelete(d *schema.ResourceData, meta interface{}) error {
iamconn := meta.(*AWSClient).iamconn iamconn := meta.(*AWSClient).iamconn
// IAM Users must be removed from all groups before they can be deleted // IAM Users must be removed from all groups before they can be deleted
var groups []string var groups []string
var marker *string listGroups := &iam.ListGroupsForUserInput{
truncated := aws.Bool(true) UserName: aws.String(d.Id()),
}
for *truncated == true { pageOfGroups := func(page *iam.ListGroupsForUserOutput, lastPage bool) (shouldContinue bool) {
listOpts := iam.ListGroupsForUserInput{ for _, g := range page.Groups {
UserName: aws.String(d.Id()),
}
if marker != nil {
listOpts.Marker = marker
}
r, err := iamconn.ListGroupsForUser(&listOpts)
if err != nil {
return err
}
for _, g := range r.Groups {
groups = append(groups, *g.GroupName) groups = append(groups, *g.GroupName)
} }
return !lastPage
// if there's a marker present, we need to save it for pagination }
if r.Marker != nil { err := iamconn.ListGroupsForUserPages(listGroups, pageOfGroups)
*marker = *r.Marker if err != nil {
} return fmt.Errorf("Error removing user %q from all groups: %s", d.Id(), err)
*truncated = *r.IsTruncated
} }
for _, g := range groups { for _, g := range groups {
// use iam group membership func to remove user from all groups // use iam group membership func to remove user from all groups
log.Printf("[DEBUG] Removing IAM User %s from IAM Group %s", d.Id(), g) log.Printf("[DEBUG] Removing IAM User %s from IAM Group %s", d.Id(), g)
@ -173,6 +165,33 @@ func resourceAwsIamUserDelete(d *schema.ResourceData, meta interface{}) error {
} }
} }
// All access keys for the user must be removed
if d.Get("force_destroy").(bool) {
var accessKeys []string
listAccessKeys := &iam.ListAccessKeysInput{
UserName: aws.String(d.Id()),
}
pageOfAccessKeys := func(page *iam.ListAccessKeysOutput, lastPage bool) (shouldContinue bool) {
for _, k := range page.AccessKeyMetadata {
accessKeys = append(accessKeys, *k.AccessKeyId)
}
return !lastPage
}
err = iamconn.ListAccessKeysPages(listAccessKeys, pageOfAccessKeys)
if err != nil {
return fmt.Errorf("Error removing access keys of user %s: %s", d.Id(), err)
}
for _, k := range accessKeys {
_, err := iamconn.DeleteAccessKey(&iam.DeleteAccessKeyInput{
UserName: aws.String(d.Id()),
AccessKeyId: aws.String(k),
})
if err != nil {
return fmt.Errorf("Error deleting access key %s: %s", k, err)
}
}
}
request := &iam.DeleteUserInput{ request := &iam.DeleteUserInput{
UserName: aws.String(d.Id()), UserName: aws.String(d.Id()),
} }

View File

@ -48,6 +48,9 @@ The following arguments are supported:
* `name` - (Required) The user's name. * `name` - (Required) The user's name.
* `path` - (Optional, default "/") Path in which to create the user. * `path` - (Optional, default "/") Path in which to create the user.
* `force_destroy` - (Optional, default false) When destroying this user, destroy
even if it has non-Terraform-managed IAM access keys. Without `force_destroy`
a user with non-Terraform-managed access keys will fail to be destroyed.
## Attributes Reference ## Attributes Reference