gruntwork-io / cloud-nuke

A tool for cleaning up your cloud accounts by nuking (deleting) all resources within it
https://gruntwork.io/
MIT License
2.81k stars 358 forks source link

Tag filtering on IAM Users doesn't work #763

Closed jfharden closed 3 months ago

jfharden commented 3 months ago

if I apply a tag of cloud-nuke-excluded to an IAM user (or any tag of my choice and configured in the config.yaml file), the user does not get excluded from a cleanup

If I use the aws cli I can see the user (the user is mine):

        {
            "Path": "/",
            "UserName": "jonathan.harden",
            "UserId": "<REDACTED>",
            "Arn": "arn:aws:iam::<REDACTED>:user/jonathan.harden",
            "CreateDate": "2021-07-26T13:15:55+00:00",
            "PasswordLastUsed": "2024-08-16T12:50:25+00:00"
        },

and if I run get-user I can see the tags:

$ aws iam get-user
{
    "User": {
        "Path": "/",
        "UserName": "jonathan.harden",
        "UserId": "<REDACTED>",
        "Arn": "arn:aws:iam::<REDACTED>:user/jonathan.harden",
        "CreateDate": "2021-07-26T13:15:55+00:00",
        "PasswordLastUsed": "2024-08-16T12:50:25+00:00",
        "Tags": [
            {
                "Key": "cloud-nuke-excluded",
                "Value": "true"
            }
        ]
    }
}

If I run cloud-nuke aws in dry run the user is still going to be nuked:

 $ cat config.yaml
IAMUsers:
  excluded:
    tag: "cloud-nuke-excluded"

 $ cloud-nuke aws --dry-run --region global --config config.yaml --resource-type iam

# AWS Resource Query Parameters
┌──────────────────────────────────┐
| Query Parameter         | Value  |
| -------------------------------- |
| Target Regions          | global |
| Target Resource Types   | iam    |
| List Unaliased KMS Keys | false  |
└──────────────────────────────────┘

 INFO  Found 17 iam resources in global
 INFO  Done searching for resources
 INFO  Found total of 17 resources

# Found AWS Resources
┌─────────────────────────────────────────────────────┐
| Resource Type | Region | Identifier       | Nukable |
| --------------------------------------------------- |
<REDACTED>
| iam           | global | jonathan.harden  | -       |
<REDACTED>
└─────────────────────────────────────────────────────┘

To investigate this further I did a local build of cloud-nuke with some additional logging in where the user is retrieved and their tags used:

$ git diff master -U5
diff --git a/aws/resources/iam.go b/aws/resources/iam.go
index 4ca86f2..947127b 100644
--- a/aws/resources/iam.go
+++ b/aws/resources/iam.go
@@ -23,10 +23,12 @@ func (iu *IAMUsers) getAll(c context.Context, configObj config.Config) ([]*strin
        input := &iam.ListUsersInput{}

        var userNames []*string
        err := iu.Client.ListUsersPagesWithContext(iu.Context, input, func(page *iam.ListUsersOutput, lastPage bool) bool {
                for _, user := range page.Users {
+                       fmt.Printf("\n%+v\n", user)
+                       fmt.Printf("%+v\n\n", user.Tags)
                        if configObj.IAMUsers.ShouldInclude(config.ResourceValue{
                                Name: user.UserName,
                                Time: user.CreateDate,
                                Tags: util.ConvertIAMTagsToMap(user.Tags),
                        }) {

The output from that shows my user, but shows there are no Tags returned from the ListUsers command

{
  Arn: "arn:aws:iam::<REDACTED>:user/jonathan.harden",
  CreateDate: 2021-07-26 13:15:55 +0000 UTC,
  PasswordLastUsed: 2024-08-16 12:50:25 +0000 UTC,
  Path: "/",
  UserId: "<REDACTED>",
  UserName: "jonathan.harden"
}
[]

I believe the problem is the AWS API does not return tags on a list users called (in spite of the documentation), see the same issue being reported in boto3 https://github.com/boto/boto3/issues/1855. As such calling user.Tags in the context of a ListUsersOutput always returns an empty array.