Esempio n. 1
0
def test_old_model_continues_to_work():
    # This test ensures that ibm_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 ibm_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'])
Esempio n. 2
0
def test_public_apis_will_not_be_signed():
    session = Session()

    # Mimic the scenario that user does not have aws credentials setup
    session.get_credentials = mock.Mock(return_value=None)

    for service_name in PUBLIC_API_TESTS:
        client = session.create_client(service_name, REGIONS[service_name])
        for operation_name in PUBLIC_API_TESTS[service_name]:
            kwargs = PUBLIC_API_TESTS[service_name][operation_name]
            method = getattr(client, xform_name(operation_name))
            yield (_test_public_apis_will_not_be_signed, method, kwargs)
Esempio n. 3
0
    def test_assume_role_uses_correct_region(self):
        config = ('[profile A]\n'
                  'role_arn = arn:aws:iam::123456789:role/RoleA\n'
                  'source_profile = B\n\n'
                  '[profile B]\n'
                  'aws_access_key_id = abc123\n'
                  'aws_secret_access_key = def456\n')
        self.write_config(config)
        session = Session(profile='A')
        # Verify that when we configure the session with a specific region
        # that we use that region when creating the sts client.
        session.set_config_variable('region', 'cn-north-1')

        create_client, expected_creds = self.create_stubbed_sts_client(session)
        session.create_client = create_client

        resolver = create_credential_resolver(session)
        provider = resolver.get_provider('assume-role')
        creds = provider.load()
        self.assert_creds_equal(creds, expected_creds)
        self.assertEqual(self.actual_client_region, 'cn-north-1')
Esempio n. 4
0
class TestAssumeRoleCredentials(BaseEnvVar):
    def setUp(self):
        self.env_original = os.environ.copy()
        self.environ_copy = os.environ.copy()
        super(TestAssumeRoleCredentials, self).setUp()
        os.environ = self.environ_copy
        # The tests rely on manipulating AWS_CONFIG_FILE,
        # but we also need to make sure we don't accidentally
        # pick up the ~/.aws/credentials file either.
        os.environ['AWS_SHARED_CREDENTIALS_FILE'] = str(uuid4())
        self.parent_session = Session()
        self.iam = self.parent_session.create_client('iam')
        self.sts = self.parent_session.create_client('sts')
        self.tempdir = tempfile.mkdtemp()
        self.config_file = os.path.join(self.tempdir, 'config')

        # A role trust policy that allows the current account to call assume
        # role on itself.
        account_id = self.sts.get_caller_identity()['Account']
        self.role_policy = {
            "Version":
            "2012-10-17",
            "Statement": [{
                "Effect": "Allow",
                "Principal": {
                    "AWS": "arn:aws:iam::%s:root" % account_id
                },
                "Action": "sts:AssumeRole"
            }]
        }

    def tearDown(self):
        super(TestAssumeRoleCredentials, self).tearDown()
        shutil.rmtree(self.tempdir)
        os.environ = self.env_original.copy()

    def random_name(self):
        return 'botocoretest-' + random_chars(10)

    def create_role(self, policy_document, policy_arn=None):
        name = self.random_name()
        response = self.iam.create_role(
            RoleName=name,
            AssumeRolePolicyDocument=json.dumps(policy_document))
        self.addCleanup(self.iam.delete_role, RoleName=name)
        if policy_arn:
            self.iam.attach_role_policy(RoleName=name, PolicyArn=policy_arn)
            self.addCleanup(self.iam.detach_role_policy,
                            RoleName=name,
                            PolicyArn=policy_arn)
        return response['Role']

    def create_user(self, policy_arns):
        name = self.random_name()
        user = self.iam.create_user(UserName=name)['User']
        self.addCleanup(self.iam.delete_user, UserName=name)

        for arn in policy_arns:
            self.iam.attach_user_policy(UserName=name, PolicyArn=arn)
            self.addCleanup(self.iam.detach_user_policy,
                            UserName=name,
                            PolicyArn=arn)

        return user

    def create_creds(self, user_name):
        creds = self.iam.create_access_key(UserName=user_name)['AccessKey']
        self.addCleanup(self.iam.delete_access_key,
                        UserName=user_name,
                        AccessKeyId=creds['AccessKeyId'])
        return creds

    def wait_for_assume_role(self,
                             role_arn,
                             access_key,
                             secret_key,
                             token=None,
                             attempts=30,
                             delay=10,
                             success_delay=1,
                             num_success=4):
        for _ in range(num_success):
            creds = self._wait_for_assume_role(role_arn, access_key,
                                               secret_key, token, attempts,
                                               delay)
            time.sleep(success_delay)
        return creds

    def _wait_for_assume_role(self, role_arn, access_key, secret_key, token,
                              attempts, delay):
        # "Why not use the policy simulator?" you might ask. The answer is
        # that the policy simulator will return success far before you can
        # actually make the calls.
        client = self.parent_session.create_client(
            'sts',
            aws_access_key_id=access_key,
            aws_secret_access_key=secret_key,
            aws_session_token=token)
        attempts_remaining = attempts
        role_session_name = random_chars(10)
        while attempts_remaining > 0:
            attempts_remaining -= 1
            try:
                result = client.assume_role(RoleArn=role_arn,
                                            RoleSessionName=role_session_name)
                return result['Credentials']
            except ClientError as e:
                code = e.response.get('Error', {}).get('Code')
                if code in ["InvalidClientTokenId", "AccessDenied"]:
                    time.sleep(delay)
                else:
                    raise

        raise Exception("Unable to assume role %s" % role_arn)

    def create_assume_policy(self, role_arn):
        policy_document = {
            "Version":
            "2012-10-17",
            "Statement": [{
                "Effect": "Allow",
                "Resource": role_arn,
                "Action": "sts:AssumeRole"
            }]
        }
        name = self.random_name()
        response = self.iam.create_policy(
            PolicyName=name, PolicyDocument=json.dumps(policy_document))
        self.addCleanup(self.iam.delete_policy,
                        PolicyArn=response['Policy']['Arn'])
        return response['Policy']['Arn']

    def assert_s3_read_only_session(self, session):
        # Calls to S3 should succeed
        s3 = session.create_client('s3')
        s3.list_buckets()

        # Calls to other services should not
        iam = session.create_client('iam')
        try:
            iam.list_groups()
            self.fail("Expected call to list_groups to fail, but it passed.")
        except ClientError as e:
            code = e.response.get('Error', {}).get('Code')
            if code != 'AccessDenied':
                raise

    def test_recursive_assume_role(self):
        # Create the final role, the one that will actually have access to s3
        final_role = self.create_role(self.role_policy, S3_READ_POLICY_ARN)

        # Create the role that can assume the final role
        middle_policy_arn = self.create_assume_policy(final_role['Arn'])
        middle_role = self.create_role(self.role_policy, middle_policy_arn)

        # Create a user that can only assume the middle-man role, and then get
        # static credentials for it.
        user_policy_arn = self.create_assume_policy(middle_role['Arn'])
        user = self.create_user([user_policy_arn])
        user_creds = self.create_creds(user['UserName'])

        # Setup the config file with the profiles we'll be using. For
        # convenience static credentials are placed here instead of putting
        # them in the credentials file.
        config = ('[default]\n'
                  'aws_access_key_id = %s\n'
                  'aws_secret_access_key = %s\n'
                  '[profile middle]\n'
                  'source_profile = default\n'
                  'role_arn = %s\n'
                  '[profile final]\n'
                  'source_profile = middle\n'
                  'role_arn = %s\n')
        config = config % (user_creds['AccessKeyId'],
                           user_creds['SecretAccessKey'], middle_role['Arn'],
                           final_role['Arn'])
        with open(self.config_file, 'w') as f:
            f.write(config)

        # Wait for IAM permissions to propagate
        middle_creds = self.wait_for_assume_role(
            role_arn=middle_role['Arn'],
            access_key=user_creds['AccessKeyId'],
            secret_key=user_creds['SecretAccessKey'],
        )
        self.wait_for_assume_role(
            role_arn=final_role['Arn'],
            access_key=middle_creds['AccessKeyId'],
            secret_key=middle_creds['SecretAccessKey'],
            token=middle_creds['SessionToken'],
        )

        # Configure our credentials file to be THE credentials file
        os.environ['AWS_CONFIG_FILE'] = self.config_file

        self.assert_s3_read_only_session(Session(profile='final'))

    def test_assume_role_with_credential_source(self):
        # Create a role with read access to S3
        role = self.create_role(self.role_policy, S3_READ_POLICY_ARN)

        # Create a user that can assume the role and get static credentials
        # for it.
        user_policy_arn = self.create_assume_policy(role['Arn'])
        user = self.create_user([user_policy_arn])
        user_creds = self.create_creds(user['UserName'])

        # Setup the config file with the profile we'll be using.
        config = ('[profile assume]\n'
                  'role_arn = %s\n'
                  'credential_source = Environment\n')
        config = config % role['Arn']
        with open(self.config_file, 'w') as f:
            f.write(config)

        # Wait for IAM permissions to propagate
        self.wait_for_assume_role(
            role_arn=role['Arn'],
            access_key=user_creds['AccessKeyId'],
            secret_key=user_creds['SecretAccessKey'],
        )

        # Setup the environment so that our new config file is THE config
        # file and add the expected credentials since we're using the
        # environment as our credential source.
        os.environ['AWS_CONFIG_FILE'] = self.config_file
        os.environ['AWS_SECRET_ACCESS_KEY'] = user_creds['SecretAccessKey']
        os.environ['AWS_ACCESS_KEY_ID'] = user_creds['AccessKeyId']

        self.assert_s3_read_only_session(Session(profile='assume'))