AWS: Boto3: AssumeRole example which includes role usage

前端 未结 7 1397
梦毁少年i
梦毁少年i 2020-12-14 18:28

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:



        
相关标签:
7条回答
  • 2020-12-14 18:58

    After a few days of searching, this is the simplest solution I have found. explained here but does not have a usage example.

    import boto3
    
    
    for profile in boto3.Session().available_profiles:
    
        boto3.DEFAULT_SESSION = boto3.session.Session(profile_name=profile)
    
        s3 = boto3.resource('s3')
    
        for bucket in s3.buckets.all():
            print(bucket)
    

    This will switch the default role you will be using. To not make the profile the default, just do not assign it to boto3.DEFAULT_SESSION. but instead, do the following.

    testing_profile = boto3.session.Session(profile_name='mainTesting')
    s3 = testing_profile.resource('s3')
    
    for bucket in s3.buckets.all():
        print(bucket)
    

    Important to note that the .aws credentials need to be set in a specific way.

    [default]
    aws_access_key_id = default_access_id
    aws_secret_access_key = default_access_key
    
    [main]
    aws_access_key_id = main_profile_access_id
    aws_secret_access_key = main_profile_access_key
    
    [mainTesting]
    source_profile = main
    role_arn = Testing role arn
    mfa_serial = mfa_arn_for_main_role
    
    [mainProduction]
    source_profile = main
    role_arn = Production role arn
    mfa_serial = mfa_arn_for_main_role
    

    I don't know why but the mfa_serial key has to be on the roles for this to work instead of the source account which would make more sense.

    0 讨论(0)
  • 2020-12-14 19:00
    import json
    import boto3
    
    
    roleARN = 'arn:aws:iam::account-of-role-to-assume:role/name-of-role'
    client = boto3.client('sts')
    response = client.assume_role(RoleArn=roleARN, 
                                  RoleSessionName='RoleSessionName', 
                                  DurationSeconds=900)
    
    dynamodb_client = boto3.client('dynamodb', region_name='us-east-1',
                        aws_access_key_id=response['Credentials']['AccessKeyId'],
                        aws_secret_access_key=response['Credentials']['SecretAccessKey'],
                        aws_session_token = response['Credentials']['SessionToken'])
    
    response = dynamodb_client.get_item(
    Key={
        'key1': {
            'S': '1',
        },
        'key2': {
            'S': '2',
        },
    },
    TableName='TestTable')
    print(response)
    
    0 讨论(0)
  • 2020-12-14 19:00

    Assuming that 1) the ~/.aws/config or ~/.aws/credentials file is populated with each of the roles that you wish to assume and that 2) the default role has AssumeRole defined in its IAM policy for each of those roles, then you can simply (in psuedo-code) do the following and not have to fuss with STS:

    import boto3
    
    # get all of the roles from the AWS config/credentials file using a config file parser
    profiles = get_profiles()
    
    for profile in profiles:
    
        # this is only used to fetch the available regions
        initial_session = boto3.Session(profile_name=profile)
    
        # get the regions
        regions = boto3.Session.get_available_regions('ec2')
    
        # cycle through the regions, setting up session, resource and client objects
        for region in regions:
            boto3_session = boto3.Session(profile_name=profile, region_name=region)
            boto3_resource = boto3_session.resource(service_name='s3', region_name=region)
            boto3_client = boto3_sessoin.client(service_name='s3', region_name=region)
    
            [ do something interesting with your session/resource/client here ]
    
    
    • Credential Setup (boto3 - Shared Credentials File)
    • Assume Role Setup (AWS)
    0 讨论(0)
  • 2020-12-14 19:05

    Here's a code snippet from the official AWS documentation where an s3 resource is created for listing all s3 buckets. boto3 resources or clients for other services can be built in a similar fashion.

    # create an STS client object that represents a live connection to the 
    # STS service
    sts_client = boto3.client('sts')
    
    # Call the assume_role method of the STSConnection object and pass the role
    # ARN and a role session name.
    assumed_role_object=sts_client.assume_role(
        RoleArn="arn:aws:iam::account-of-role-to-assume:role/name-of-role",
        RoleSessionName="AssumeRoleSession1"
    )
    
    # From the response that contains the assumed role, get the temporary 
    # credentials that can be used to make subsequent API calls
    credentials=assumed_role_object['Credentials']
    
    # Use the temporary credentials that AssumeRole returns to make a 
    # connection to Amazon S3  
    s3_resource=boto3.resource(
        's3',
        aws_access_key_id=credentials['AccessKeyId'],
        aws_secret_access_key=credentials['SecretAccessKey'],
        aws_session_token=credentials['SessionToken'],
    )
    
    # Use the Amazon S3 resource object that is now configured with the 
    # credentials to access your S3 buckets. 
    for bucket in s3_resource.buckets.all():
        print(bucket.name)
    
    0 讨论(0)
  • 2020-12-14 19:13

    If you want a functional implementation, this is what I settled on:

    def filter_none_values(kwargs: dict) -> dict:
        """Returns a new dictionary excluding items where value was None"""
        return {k: v for k, v in kwargs.items() if v is not None}
    
    
    def assume_session(
        role_session_name: str,
        role_arn: str,
        duration_seconds: Optional[int] = None,
        region_name: Optional[str] = None,
    ) -> boto3.Session:
        """
        Returns a session with the given name and role.
        If not specified, duration will be set by AWS, probably at 1 hour.
        If not specified, region will be left unset.
        Region can be overridden by each client or resource spawned from this session.
        """
        assume_role_kwargs = filter_none_values(
            {
                "RoleSessionName": role_session_name,
                "RoleArn": role_arn,
                "DurationSeconds": duration_seconds,
            }
        )
        credentials = boto3.client("sts").assume_role(**assume_role_kwargs)["Credentials"]
        create_session_kwargs = filter_none_values(
            {
                "aws_access_key_id": credentials["AccessKeyId"],
                "aws_secret_access_key": credentials["SecretAccessKey"],
                "aws_session_token": credentials["SessionToken"],
                "region_name": region_name,
            }
        )
        return boto3.Session(**create_session_kwargs)
    
    
    def main() -> None:
        session = assume_session(
            "MyCustomSessionName",
            "arn:aws:iam::XXXXXXXXXXXX:role/TheRoleIWantToAssume",
            region_name="us-east-1",
        )
        client = session.client(service_name="ec2")
        print(client.describe_key_pairs())
    
    
    0 讨论(0)
  • 2020-12-14 19:15

    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.

    0 讨论(0)
提交回复
热议问题