How to filter AWS roles by tags in boto3?

Viewed 955

I'm trying to get list of roles with special tags

Python version 3.9

Boto3 version 1.16.25

There is my code

iam = boto3.client('iam', region_name='us-east-1')
roles = iam.list_roles()["Roles"]
print(roles)

Result:

{
   "Path":"/",
   "RoleName":"aws-***-delivery-role",
   "RoleId":"AROA****LOIO",
   "Arn":"arn:aws:iam::448*****770:role/aws-***-delivery-role",
   "CreateDate":datetime.datetime(2017,   11,   28,   21,   13,   3, "tzinfo=tzutc())",
   "AssumeRolePolicyDocument":{
      "Version":"2012-10-17",
      "Statement":[
         {
            "Sid":"",
            "Effect":"Allow",
            "Principal":{
               "Service":"firehose.amazonaws.com"
            },
            "Action":"sts:AssumeRole",
            "Condition":{
               "StringEquals":{
                  "sts:ExternalId":"448***770"
               }
            }
         }
      ]
   },
   "MaxSessionDuration":3600
}

I don't event see a tags

I have tried this code too

iam = boto3.resource('iam', region_name='us-east-1')
roles = iam.roles.all()

But the same those roles don't have tags

Only when I run this code I could see a tag and then filtrate it, but role.load() each time do API call to AWS and I have 3k roles without role.load() it doesn't work. In result it is so long

iam = boto3.resource('iam', region_name='us-east-1')
roles = iam.roles.all()
for role in roles:
    role.load()
    print(role.tags)

Please, give me some advice about it or share your experience, how can I filtrate list of roles by tags?

I sow this documentation https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/iam.html#IAM.Client.list_roles

list_roles should return JSON with tags but this doesn't work

1 Answers

The boto3 documentation incorrectly reports that list_roles() returns tags, see this GitHub issue for updates: https://github.com/boto/boto3/issues/2126.

To get the tags we need to call get_role() on each role and then filter from there. This can cause throttling so I also added a retry with exponential backoff.

import logging
from typing import Dict, Iterator, List

import botocore.client
from botocore.exceptions import ClientError
from retry import retry

# Type aliases to make it more clear what type of AWS resource is being returned
Policy = Dict
PolicyDocument = Dict
Role = Dict

logger = logging.getLogger(__package__)
logger.setLevel(logging.INFO)

RETRY_ARGS = {
    "exceptions": ClientError,
    "tries": 5,
    "delay": 5,
    "backoff": 2,
    "jitter": (2, 15)
}

class IAMHelper:
    def __init__(self, client: botocore.client):
        self.client = client

    @retry(**RETRY_ARGS)
    def get_role_details(self, role_name: str) -> Role:
        """
        Since we are making a client.get_role() call for each role to filter on tags, this method is prone to
        throttling. To counter this this method uses an exponential backoff.
        """

        logger.info("Attempting to get details for role %s", role_name)

        return self.client.get_role(RoleName=role_name).get("Role")

    def describe_roles(self) -> Iterator[Role]:
        """
        The IAM client has no `describe_roles()` method, only `list_roles()`. The output of `list_roles()` does not
        contain tags, so we need to call `get_role()` on each.

        The boto3 documentation incorrectly reports that `list_roles()` returns tags:
            https://github.com/boto/boto3/issues/2126
        """

        for page in self.client.get_paginator('list_roles').paginate():
            for role in page["Roles"]:
                yield self.get_role_details(role["RoleName"])

    def find_roles_by_tag(self, tag_key: str, tag_value: str) -> List[Role]:
        roles = []

        for role in self.describe_roles():
            for tag in role.get("Tags", []):
                if tag["Key"] == tag_key and tag["Value"] == tag_value:
                    logger.info("Found %s role with tags %s: %s", role.get("RoleName"), tag_key, tag_value)
                    roles.append(role)

        return roles
Related