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'])
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)
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')
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'))