示例#1
0
def get_session(profile_name=None, mfa_prompter=getpass, **kwargs):
    """
    Returns a boto3 session for the specified profile. If the profile is
    configured to assume a role and use MFA, then the MFA token will be used
    on the source profile rather than on the assume role profile. This is
    cached and reused to allow for using different assume role profiles with
    the same source profile without prompting for MFA tokens every time.

    """

    if profile_name:

        # Create a regular botocore session.
        botocore_session = BotocoreSession(profile=profile_name)

        # Create a custom credential provider.
        custom_provider = SourceProfileMfaCredentialProvider(profile_name, mfa_prompter)

        # Put the custom provider at the front of the resolver list,
        # so it will be checked/used before the default boto providers.
        credential_resolver = botocore_session.get_component('credential_provider')
        credential_resolver.providers.insert(0, custom_provider)

        # Use the patched botocore session when creating the boto3 session.
        kwargs['botocore_session'] = botocore_session

    return Session(**kwargs)
示例#2
0
def get_credentials(profile: str = "default",
                    environment: Optional[Environment] = None) -> Environment:
    """
    Use session cache so users don't need to use MFA while there are valid
    session tokens. This is the behavior of the AWSCLI and what we are trying to
    emulate.

    Modified with support for profiles from:
    https://github.com/boto/botocore/pull/1338/#issuecomment-368472031
    """
    # By default the cache path is ~/.aws/boto/cache
    cli_cache = (Path.home() / ".aws" / "cli" / "cache").absolute()

    # Construct botocore session with cache
    session = Session(profile=profile)
    session.get_component("credential_provider").get_provider(
        "assume-role").cache = credentials.JSONFileCache(cli_cache)

    # return credentials from session
    creds = boto3.Session(botocore_session=session,
                          profile_name=profile).get_credentials()

    return {
        "AWS_ACCESS_KEY_ID": creds.access_key,
        "AWS_SECRET_ACCESS_KEY": creds.secret_key,
        "AWS_SESSION_TOKEN": creds.token,
    }
示例#3
0
def test_old_model_continues_to_work():
    # This test ensures that botocore can load the service models as they exist
    # today.  There's a directory in tests/functional/models that is a
    # snapshot of a service model.  This test ensures that we can continue
    # to stub an API call using this model.  That way if the models ever
    # change we have a mechanism to ensure that the existing models continue
    # to work with botocore.  The test should not change (with the exception
    # of potential changes to the ClientHTTPStubber), and the files in
    # tests/functional/models should not change!
    session = Session()
    loader = session.get_component('data_loader')
    # We're adding our path to the existing search paths so we don't have to
    # copy additional data files such as _retry.json to our TEST_MODELS_DIR.
    # We only care about the service model and endpoints file not changing.
    # This also prevents us from having to make any changes to this models dir
    # if we end up adding a new data file that's needed to create clients.
    # We're adding our TEST_MODELS_DIR as the first element in the list to
    # ensure we load the endpoints.json file from TEST_MODELS_DIR.  For the
    # service model we have an extra safety net where we can choose a custom
    # client name.
    loader.search_paths.insert(0, TEST_MODELS_DIR)

    # The model dir we copied was renamed to 'custom-lambda'
    # to ensure we're loading our version of the model and not
    # the built in one.
    client = session.create_client(
        'custom-acm',
        region_name='us-west-2',
        aws_access_key_id='foo',
        aws_secret_access_key='bar',
    )
    with ClientHTTPStubber(client) as stubber:
        stubber.add_response(url='https://acm.us-west-2.amazonaws.com/',
                             headers={
                                 'x-amzn-RequestId': 'abcd',
                                 'Date': 'Fri, 26 Oct 2018 01:46:30 GMT',
                                 'Content-Length': '29',
                                 'Content-Type': 'application/x-amz-json-1.1'
                             },
                             body=b'{"CertificateSummaryList":[]}')
        response = client.list_certificates()
        assert_equal(
            response, {
                'CertificateSummaryList': [],
                'ResponseMetadata': {
                    'HTTPHeaders': {
                        'content-length': '29',
                        'content-type': 'application/x-amz-json-1.1',
                        'date': 'Fri, 26 Oct 2018 01:46:30 GMT',
                        'x-amzn-requestid': 'abcd'
                    },
                    'HTTPStatusCode': 200,
                    'RequestId': 'abcd',
                    'RetryAttempts': 0
                }
            })

    # Also verify we can use the paginators as well.
    assert_equal(client.can_paginate('list_certificates'), True)
    assert_equal(client.waiter_names, ['certificate_validated'])
示例#4
0
def test_old_model_continues_to_work():
    # This test ensures that botocore can load the service models as they exist
    # today.  There's a directory in tests/functional/models that is a
    # snapshot of a service model.  This test ensures that we can continue
    # to stub an API call using this model.  That way if the models ever
    # change we have a mechanism to ensure that the existing models continue
    # to work with botocore.  The test should not change (with the exception
    # of potential changes to the ClientHTTPStubber), and the files in
    # tests/functional/models should not change!
    session = Session()
    loader = session.get_component('data_loader')
    # We're adding our path to the existing search paths so we don't have to
    # copy additional data files such as _retry.json to our FIXED_MODELS_DIR.
    # We only care about the service model and endpoints file not changing.
    # This also prevents us from having to make any changes to this models dir
    # if we end up adding a new data file that's needed to create clients.
    # We're adding our FIXED_MODELS_DIR as the first element in the list to
    # ensure we load the endpoints.json file from FIXED_MODELS_DIR.  For the
    # service model we have an extra safety net where we can choose a custom
    # client name.
    loader.search_paths.insert(0, FIXED_MODELS_DIR)

    # The model dir we copied was renamed to 'custom-lambda'
    # to ensure we're loading our version of the model and not
    # the built in one.
    client = session.create_client(
        'custom-acm', region_name='us-west-2',
        aws_access_key_id='foo', aws_secret_access_key='bar',
    )
    with ClientHTTPStubber(client) as stubber:
        stubber.add_response(
            url='https://acm.us-west-2.amazonaws.com/',
            headers={'x-amzn-RequestId': 'abcd',
                     'Date': 'Fri, 26 Oct 2018 01:46:30 GMT',
                     'Content-Length': '29',
                     'Content-Type': 'application/x-amz-json-1.1'},
            body=b'{"CertificateSummaryList":[]}')
        response = client.list_certificates()
        assert_equal(
            response,
            {'CertificateSummaryList': [],
             'ResponseMetadata': {
                 'HTTPHeaders': {
                     'content-length': '29',
                     'content-type': 'application/x-amz-json-1.1',
                     'date': 'Fri, 26 Oct 2018 01:46:30 GMT',
                     'x-amzn-requestid': 'abcd'},
                 'HTTPStatusCode': 200,
                 'RequestId': 'abcd',
                 'RetryAttempts': 0}
             }
        )

    # Also verify we can use the paginators as well.
    assert_equal(client.can_paginate('list_certificates'), True)
    assert_equal(client.waiter_names, ['certificate_validated'])
示例#5
0
    def create_session(self, profile=None):
        session = Session(profile=profile)

        # We have to set bogus credentials here or otherwise we'll trigger
        # an early credential chain resolution.
        sts = session.create_client(
            'sts',
            aws_access_key_id='spam',
            aws_secret_access_key='eggs',
        )
        stubber = Stubber(sts)
        stubber.activate()
        assume_role_provider = AssumeRoleProvider(
            load_config=lambda: session.full_config,
            client_creator=lambda *args, **kwargs: sts,
            cache={},
            profile_name=profile,
            credential_sourcer=CanonicalNameCredentialSourcer([
                self.env_provider, self.container_provider,
                self.metadata_provider
            ])
        )

        component_name = 'credential_provider'
        resolver = session.get_component(component_name)
        available_methods = [p.METHOD for p in resolver.providers]
        replacements = {
            'env': self.env_provider,
            'iam-role': self.metadata_provider,
            'container-role': self.container_provider,
            'assume-role': assume_role_provider
        }
        for name, provider in replacements.items():
            try:
                index = available_methods.index(name)
            except ValueError:
                # The provider isn't in the session
                continue

            resolver.providers[index] = provider

        session.register_component(
            'credential_provider', resolver
        )
        return session, stubber
示例#6
0
    def create_session(self, profile=None):
        session = Session(profile=profile)

        # We have to set bogus credentials here or otherwise we'll trigger
        # an early credential chain resolution.
        sts = session.create_client(
            'sts',
            aws_access_key_id='spam',
            aws_secret_access_key='eggs',
        )
        self.mock_client_creator.return_value = sts
        stubber = Stubber(sts)
        stubber.activate()
        assume_role_provider = AssumeRoleProvider(
            load_config=lambda: session.full_config,
            client_creator=self.mock_client_creator,
            cache={},
            profile_name=profile,
            credential_sourcer=CanonicalNameCredentialSourcer([
                self.env_provider, self.container_provider,
                self.metadata_provider
            ]),
            profile_provider_builder=ProfileProviderBuilder(session),
        )

        component_name = 'credential_provider'
        resolver = session.get_component(component_name)
        available_methods = [p.METHOD for p in resolver.providers]
        replacements = {
            'env': self.env_provider,
            'iam-role': self.metadata_provider,
            'container-role': self.container_provider,
            'assume-role': assume_role_provider
        }
        for name, provider in replacements.items():
            try:
                index = available_methods.index(name)
            except ValueError:
                # The provider isn't in the session
                continue

            resolver.providers[index] = provider

        session.register_component('credential_provider', resolver)
        return session, stubber
示例#7
0
    def reconfigure(self, profile=None):

        if profile is None:
            return

        # See awscli/clidriver.py
        session = Session()
        load_plugins(session.full_config.get('plugins', {}),
                     event_hooks=session.get_component('event_emitter'))

        driver = CLIDriver(session=session)
        driver._command_table = driver._build_command_table()
        driver._command_table["configure"] = ConfigureCommand(
            session,
            prompter=InteractivePrompter(self.console)
        )

        driver.main(args=["configure", "--profile", profile])
示例#8
0
def _patch_boto(session: boto.Session):
    parser_factory = session.get_component('response_parser_factory')
    parser_factory.set_parser_defaults(timestamp_parser=_parse_timestamp)