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: "/",
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
}
func resourceAwsIamUserDelete(d *schema.ResourceData, meta interface{}) error {
iamconn := meta.(*AWSClient).iamconn
// IAM Users must be removed from all groups before they can be deleted
var groups []string
var marker *string
truncated := aws.Bool(true)
for *truncated == true {
listOpts := iam.ListGroupsForUserInput{
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 {
listGroups := &iam.ListGroupsForUserInput{
UserName: aws.String(d.Id()),
}
pageOfGroups := func(page *iam.ListGroupsForUserOutput, lastPage bool) (shouldContinue bool) {
for _, g := range page.Groups {
groups = append(groups, *g.GroupName)
}
// if there's a marker present, we need to save it for pagination
if r.Marker != nil {
*marker = *r.Marker
}
*truncated = *r.IsTruncated
return !lastPage
}
err := iamconn.ListGroupsForUserPages(listGroups, pageOfGroups)
if err != nil {
return fmt.Errorf("Error removing user %q from all groups: %s", d.Id(), err)
}
for _, g := range 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)
@ -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{
UserName: aws.String(d.Id()),
}

View File

@ -48,6 +48,9 @@ The following arguments are supported:
* `name` - (Required) The user's name.
* `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
@ -65,4 +68,4 @@ IAM Users can be imported using the `name`, e.g.
```
$ terraform import aws_iam_user.lb loadbalancer
```
```