botoboto3

AWS: Boto3: AssumeRole example which includes role usage


I'm trying to use the AssumeRole in such a way that i'm traversing multiple accounts and retrieving assets for those accounts. I've made it to this point:

import boto3
stsclient = boto3.client('sts')

assumedRoleObject = sts_client.assume_role(
RoleArn="arn:aws:iam::account-of-role-to-assume:role/name-of-role",
RoleSessionName="AssumeRoleSession1")

Great, i have the assumedRoleObject. But now i want to use that to list things like ELBs or something that isn't a built-in low level resource.

How does one go about doing that? If i may ask - please code out a full example, so that everyone can benefit.


Solution

  • To get a session with an assumed role:

    import botocore
    import boto3
    import datetime
    from dateutil.tz import tzlocal
    
    assume_role_cache: dict = {}
    def assumed_role_session(role_arn: str, base_session: botocore.session.Session = None):
        base_session = base_session or boto3.session.Session()._session
        fetcher = botocore.credentials.AssumeRoleCredentialFetcher(
            client_creator = base_session.create_client,
            source_credentials = base_session.get_credentials(),
            role_arn = role_arn,
            extra_args = {
            #    'RoleSessionName': None # set this if you want something non-default
            }
        )
        creds = botocore.credentials.DeferredRefreshableCredentials(
            method = 'assume-role',
            refresh_using = fetcher.fetch_credentials,
            time_fetcher = lambda: datetime.datetime.now(tzlocal())
        )
        botocore_session = botocore.session.Session()
        botocore_session._credentials = creds
        return boto3.Session(botocore_session = botocore_session)
    
    # usage:
    session = assumed_role_session('arn:aws:iam::ACCOUNTID:role/ROLE_NAME')
    ec2 = session.client('ec2') # ... etc.
    

    The resulting session's credentials will be automatically refreshed when required which is quite nice.

    Note: my previous answer was outright wrong but I can't delete it, so I've replaced it with a better and working answer.