简体   繁体   中英

Work around AWS assume_role session expiration

I'm calling 4 actions from AWS Health API to collect all the findings using these loopy loops (I removed some DynamoDB pieces to make it clearer). The issue is that the script takes quite some time to run and ends up timing out after an hour because of the ExpiredTokenException . I already tried the DurationSeconds , and it's fixed at 3600.

Can I work around this somehow? Like splitting the function into multiple functions? Or that wouldn't work at all?

sts = boto3.client('sts')
# use STS to AssumeRole for the Organization Health Account
memberAcct = sts.assume_role(RoleArn='arn:aws:iam::x:role/Health-Role',RoleSessionName='xacct-health')
# retrieve creds from member account to create new Health Boto3 Client
xAcctAccessKey = memberAcct['Credentials']['AccessKeyId']
xAcctSecretKey = memberAcct['Credentials']['SecretAccessKey']
xAcctSeshToken = memberAcct['Credentials']['SessionToken']
health = boto3.client('health',aws_access_key_id=xAcctAccessKey,aws_secret_access_key=xAcctSecretKey,aws_session_token=xAcctSeshToken)

def health_collect():
    try:
        paginator = health.get_paginator('describe_events_for_organization')
        iterator = paginator.paginate()
        for page in iterator:
            for e in page['events']:
                eventArn = str(e['arn'])
                healthEventScope = str(e['eventScopeCode'])
                if healthEventScope == 'ACCOUNT_SPECIFIC':
                    affectedAccounts = health.describe_affected_accounts_for_organization(eventArn=eventArn)['affectedAccounts']
                    for affectedAcctId in affectedAccounts:
                        eventDetails = health.describe_event_details_for_organization(
                            organizationEventDetailFilters=[
                                {
                                    'eventArn': eventArn,
                                    'awsAccountId': affectedAcctId
                                }
                            ]
                        )
                        eventDescription = str(eventDetails['successfulSet'][0]['eventDescription']['latestDescription'])
                        entityDetails = health.describe_affected_entities_for_organization(
                            organizationEntityFilters=[
                                {
                                    'eventArn': eventArn,
                                    'awsAccountId': affectedAcctId
                                }
                            ]
                        )
                        entityValue = str(entityDetails['entities'][0]['entityValue'])
                        if entityValue == 'AWS_ACCOUNT':
                            entityValue = affectedAcctId
                        else:
                else:
                    affectedAccounts = 'ALL'
                    entityArn = 'NOT_SPECIFIC'
                    entityValue = 'NOT_SPECIFIC'
                    eventDetails = health.describe_event_details_for_organization(organizationEventDetailFilters=[{'eventArn': eventArn}])
                    eventDescription = str(eventDetails['successfulSet'][0]['eventDescription']['latestDescription'])
    except Exception as e:
        print(e)

health_collect()

There are already issues on GitHub for this problem.

refreshing sts role assumption credentials for long running operations #443

Automatically use RefreshableCredentials when appropriate #2158

Meanwhile, there is some intermediate workaround, I think you can have via RefreshableCredentials class in the botocore combined with get_session method.


...

def assumed_session(role_arn, session_name, session=None):

    if session is None:
        session = Session()

    def refresh():
     # call assume role and return a dict of
     # access_key
     # secret
     # token

    session_credentials = RefreshableCredentials.create_from_metadata(
        metadata=refresh(),
        refresh_using=refresh,
        method='sts-assume-role')

    s = get_session()
    s._credentials = session_credentials
    region = session._session.get_config_variable('region') or 'us-east-1'
    s.set_config_variable('region', region)
    return Session(botocore_session=s)

a working version of the above code can be found in this gist

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM