Reputation: 63
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
Upvotes: 1
Views: 1904
Reputation: 63
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
Upvotes: 1