AWS: Boto3: пример AssumeRole, который включает использование роли

Я пытаюсь использовать AssumeRole таким образом, чтобы я просматривал несколько учетных записей и извлекал активы для этих учетных записей. Я дошел до этого:

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")

Отлично, у меня есть ПредполагаемыйРолеОбъект. Но теперь я хочу использовать это, чтобы перечислить такие вещи, как ELB или что-то, что не является встроенным ресурсом низкого уровня.

Как это сделать? Если я могу спросить - пожалуйста, напишите полный пример, чтобы все могли извлечь выгоду.


person mumbles    schedule 25.05.2017    source источник


Ответы (7)


Чтобы получить сеанс с предполагаемой ролью:

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.

Учетные данные результирующего сеанса будут автоматически обновляться при необходимости, что довольно хорошо.

Примечание: мой предыдущий ответ был совершенно неправильным, но я не могу его удалить, поэтому заменил его на лучший и рабочий ответ.

person Jarrad    schedule 23.08.2017
comment
Почему это приемлемое решение, если оно не работает? - person Mike Conigliaro; 08.11.2018
comment
Не говоря уже о AWS SDK, это может вызвать python-ic error, поскольку я не вижу аргументов с именем role_arn в _ 4_ класс - person y2k-shubham; 28.01.2019
comment
Это очень хорошо работает !!! - person Georg Zimmer; 17.12.2020

Вот фрагмент кода из официальной документации AWS. где создается s3 ресурс для перечисления всех s3 сегментов. boto3 ресурсы или клиенты для других служб могут быть созданы аналогичным образом.

# 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)
person Vinay    schedule 15.07.2019

Вы можете взять на себя роль, используя токен STS, например:

class Boto3STSService(object):
    def __init__(self, arn):
        sess = Session(aws_access_key_id=ARN_ACCESS_KEY,
                       aws_secret_access_key=ARN_SECRET_KEY)
        sts_connection = sess.client('sts')
        assume_role_object = sts_connection.assume_role(
            RoleArn=arn, RoleSessionName=ARN_ROLE_SESSION_NAME,
            DurationSeconds=3600)
        self.credentials = assume_role_object['Credentials']

Это даст вам временный ключ доступа и секретные ключи с токеном сеанса. С этими временными учетными данными вы можете получить доступ к любой службе. Например, если вы хотите получить доступ к ELB, вы можете использовать следующий код:

self.tmp_credentials = Boto3STSService(arn).credentials

def get_boto3_session(self):
    tmp_access_key = self.tmp_credentials['AccessKeyId']
    tmp_secret_key = self.tmp_credentials['SecretAccessKey']
    security_token = self.tmp_credentials['SessionToken']

    boto3_session = Session(
        aws_access_key_id=tmp_access_key,
        aws_secret_access_key=tmp_secret_key, aws_session_token=security_token
    )
    return boto3_session

def get_elb_boto3_connection(self, region):
    sess = self.get_boto3_session()
    elb_conn = sess.client(service_name='elb', region_name=region)
    return elb_conn
person upaang saxena    schedule 26.05.2017

Если вам нужна функциональная реализация, я остановился на следующем:

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())

person billkw    schedule 22.05.2019
comment
Это дает мне An error occurred (InvalidClientTokenId) when calling the AssumeRole operation: The security token included in the request is invalid. - person shredding; 02.03.2020

со ссылкой на решение @jarrad, которое не работает по состоянию на февраль 2021 года, и как решение, которое не использует STS явным образом см. следующее


import boto3
import botocore.session
from botocore.credentials import AssumeRoleCredentialFetcher, DeferredRefreshableCredentials


def get_boto3_session(assume_role_arn=None):
    session = boto3.Session(aws_access_key_id="abc", aws_secret_access_key="def")
    if not assume_role_arn:
        return session

    fetcher = AssumeRoleCredentialFetcher(
        client_creator=_get_client_creator(session),
        source_credentials=session.get_credentials(),
        role_arn=assume_role_arn,
    )
    botocore_session = botocore.session.Session()
    botocore_session._credentials = DeferredRefreshableCredentials(
        method='assume-role',
        refresh_using=fetcher.fetch_credentials
    )

    return boto3.Session(botocore_session=botocore_session)


def _get_client_creator(session):
    def client_creator(service_name, **kwargs):
        return session.client(service_name, **kwargs)

    return client_creator

person Sar009    schedule 24.02.2021

Предполагая, что 1) файл ~/.aws/config или ~/.aws/credentials заполнен каждой из ролей, которые вы хотите принять, и что 2) роль по умолчанию имеет AssumeRole, определенную в ее политике IAM для каждой из этих ролей, тогда вы можете просто (в псевдокоде ) сделать следующее и не надо возиться с СТС:

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 ]

person eatsfood    schedule 28.04.2020

После нескольких дней поиска это самое простое решение, которое я нашел. объяснил здесь, но нет примера использования.

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)

Это переключит роль по умолчанию, которую вы будете использовать. Чтобы профиль не использовался по умолчанию, просто не назначайте его для boto3.DEFAULT_SESSION. но вместо этого сделайте следующее.

testing_profile = boto3.session.Session(profile_name='mainTesting')
s3 = testing_profile.resource('s3')

for bucket in s3.buckets.all():
    print(bucket)

Важно отметить, что учетные данные .aws нужно указывать определенным образом.

[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

Я не знаю почему, но ключ mfa_serial должен быть в ролях, чтобы это работало, а не в исходной учетной записи, что имеет больше смысла.

person meh Man    schedule 22.06.2020