import boto3 import yaml import sure # noqa from nose.tools import assert_raises from botocore.exceptions import ClientError from moto import mock_iam, mock_cloudformation, mock_s3, mock_sts # AWS::IAM::User Tests @mock_iam @mock_cloudformation def test_iam_cloudformation_create_user(): cf_client = boto3.client("cloudformation", region_name="us-east-1") stack_name = "MyStack" user_name = "MyUser" template = """ Resources: TheUser: Type: AWS::IAM::User Properties: UserName: {0} """.strip().format( user_name ) cf_client.create_stack(StackName=stack_name, TemplateBody=template) provisioned_resource = cf_client.list_stack_resources(StackName=stack_name)[ "StackResourceSummaries" ][0] provisioned_resource["LogicalResourceId"].should.equal("TheUser") provisioned_resource["PhysicalResourceId"].should.equal(user_name) @mock_iam @mock_cloudformation def test_iam_cloudformation_update_user_no_interruption(): cf_client = boto3.client("cloudformation", region_name="us-east-1") stack_name = "MyStack" template = """ Resources: TheUser: Type: AWS::IAM::User """.strip() cf_client.create_stack(StackName=stack_name, TemplateBody=template) provisioned_resource = cf_client.list_stack_resources(StackName=stack_name)[ "StackResourceSummaries" ][0] user_name = provisioned_resource["PhysicalResourceId"] iam_client = boto3.client("iam", region_name="us-east-1") user = iam_client.get_user(UserName=user_name)["User"] user["Path"].should.equal("/") path = "/MyPath/" template = """ Resources: TheUser: Type: AWS::IAM::User Properties: Path: {0} """.strip().format( path ) cf_client.update_stack(StackName=stack_name, TemplateBody=template) user = iam_client.get_user(UserName=user_name)["User"] user["Path"].should.equal(path) @mock_iam @mock_cloudformation def test_iam_cloudformation_update_user_replacement(): cf_client = boto3.client("cloudformation", region_name="us-east-1") stack_name = "MyStack" template = """ Resources: TheUser: Type: AWS::IAM::User """.strip() cf_client.create_stack(StackName=stack_name, TemplateBody=template) provisioned_resource = cf_client.list_stack_resources(StackName=stack_name)[ "StackResourceSummaries" ][0] original_user_name = provisioned_resource["PhysicalResourceId"] iam_client = boto3.client("iam", region_name="us-east-1") user = iam_client.get_user(UserName=original_user_name)["User"] user["Path"].should.equal("/") new_user_name = "MyUser" template = """ Resources: TheUser: Type: AWS::IAM::User Properties: UserName: {0} """.strip().format( new_user_name ) cf_client.update_stack(StackName=stack_name, TemplateBody=template) with assert_raises(ClientError) as e: iam_client.get_user(UserName=original_user_name) e.exception.response["Error"]["Code"].should.equal("NoSuchEntity") iam_client.get_user(UserName=new_user_name) @mock_iam @mock_cloudformation def test_iam_cloudformation_update_drop_user(): cf_client = boto3.client("cloudformation", region_name="us-east-1") stack_name = "MyStack" template = """ Resources: TheFirstUser: Type: AWS::IAM::User TheSecondUser: Type: AWS::IAM::User """.strip() cf_client.create_stack(StackName=stack_name, TemplateBody=template) provisioned_resources = cf_client.list_stack_resources(StackName=stack_name)[ "StackResourceSummaries" ] first_provisioned_user = [ resource for resource in provisioned_resources if resource["LogicalResourceId"] == "TheFirstUser" ][0] second_provisioned_user = [ resource for resource in provisioned_resources if resource["LogicalResourceId"] == "TheSecondUser" ][0] first_user_name = first_provisioned_user["PhysicalResourceId"] second_user_name = second_provisioned_user["PhysicalResourceId"] iam_client = boto3.client("iam", region_name="us-east-1") iam_client.get_user(UserName=first_user_name) iam_client.get_user(UserName=second_user_name) template = """ Resources: TheSecondUser: Type: AWS::IAM::User """.strip() cf_client.update_stack(StackName=stack_name, TemplateBody=template) provisioned_resources = cf_client.list_stack_resources(StackName=stack_name)[ "StackResourceSummaries" ] len(provisioned_resources).should.equal(1) second_provisioned_user = [ resource for resource in provisioned_resources if resource["LogicalResourceId"] == "TheSecondUser" ][0] second_user_name.should.equal(second_provisioned_user["PhysicalResourceId"]) iam_client.get_user(UserName=second_user_name) with assert_raises(ClientError) as e: iam_client.get_user(UserName=first_user_name) e.exception.response["Error"]["Code"].should.equal("NoSuchEntity") @mock_iam @mock_cloudformation def test_iam_cloudformation_delete_user(): cf_client = boto3.client("cloudformation", region_name="us-east-1") stack_name = "MyStack" user_name = "MyUser" template = """ Resources: TheUser: Type: AWS::IAM::User Properties: UserName: {} """.strip().format( user_name ) cf_client.create_stack(StackName=stack_name, TemplateBody=template) iam_client = boto3.client("iam", region_name="us-east-1") user = iam_client.get_user(UserName=user_name) cf_client.delete_stack(StackName=stack_name) with assert_raises(ClientError) as e: user = iam_client.get_user(UserName=user_name) e.exception.response["Error"]["Code"].should.equal("NoSuchEntity") @mock_iam @mock_cloudformation def test_iam_cloudformation_delete_user_having_generated_name(): cf_client = boto3.client("cloudformation", region_name="us-east-1") stack_name = "MyStack" template = """ Resources: TheUser: Type: AWS::IAM::User """.strip() cf_client.create_stack(StackName=stack_name, TemplateBody=template) provisioned_resource = cf_client.list_stack_resources(StackName=stack_name)[ "StackResourceSummaries" ][0] provisioned_resource["LogicalResourceId"].should.equal("TheUser") user_name = provisioned_resource["PhysicalResourceId"] iam_client = boto3.client("iam", region_name="us-east-1") user = iam_client.get_user(UserName=user_name) cf_client.delete_stack(StackName=stack_name) with assert_raises(ClientError) as e: user = iam_client.get_user(UserName=user_name) e.exception.response["Error"]["Code"].should.equal("NoSuchEntity") @mock_iam @mock_cloudformation def test_iam_cloudformation_user_get_attr(): cf_client = boto3.client("cloudformation", region_name="us-east-1") stack_name = "MyStack" user_name = "MyUser" template = """ Resources: TheUser: Type: AWS::IAM::User Properties: UserName: {0} Outputs: UserName: Value: !Ref TheUser UserArn: Value: !GetAtt TheUser.Arn """.strip().format( user_name ) cf_client.create_stack(StackName=stack_name, TemplateBody=template) stack_description = cf_client.describe_stacks(StackName=stack_name)["Stacks"][0] output_user_name = [ output["OutputValue"] for output in stack_description["Outputs"] if output["OutputKey"] == "UserName" ][0] output_user_arn = [ output["OutputValue"] for output in stack_description["Outputs"] if output["OutputKey"] == "UserArn" ][0] iam_client = boto3.client("iam", region_name="us-east-1") user_description = iam_client.get_user(UserName=output_user_name)["User"] output_user_arn.should.equal(user_description["Arn"]) # AWS::IAM::Policy Tests @mock_s3 @mock_iam @mock_cloudformation def test_iam_cloudformation_create_user_policy(): iam_client = boto3.client("iam", region_name="us-east-1") user_name = "MyUser" iam_client.create_user(UserName=user_name) s3_client = boto3.client("s3", region_name="us-east-1") bucket_name = "my-bucket" bucket = s3_client.create_bucket(Bucket=bucket_name) bucket_arn = "arn:aws:s3:::{0}".format(bucket_name) cf_client = boto3.client("cloudformation", region_name="us-east-1") stack_name = "MyStack" policy_name = "MyPolicy" template = """ Resources: ThePolicy: Type: AWS::IAM::Policy Properties: PolicyName: {0} PolicyDocument: Version: '2012-10-17' Statement: - Effect: Allow Action: s3:* Resource: {1} Users: - {2} """.strip().format( policy_name, bucket_arn, user_name ) cf_client.create_stack(StackName=stack_name, TemplateBody=template) provisioned_resource = cf_client.list_stack_resources(StackName=stack_name)[ "StackResourceSummaries" ][0] logical_resource_id = provisioned_resource["LogicalResourceId"] logical_resource_id.should.equal("ThePolicy") original_policy_document = yaml.load(template, Loader=yaml.FullLoader)["Resources"][ logical_resource_id ]["Properties"]["PolicyDocument"] policy = iam_client.get_user_policy(UserName=user_name, PolicyName=policy_name) policy["PolicyDocument"].should.equal(original_policy_document) @mock_s3 @mock_iam @mock_cloudformation def test_iam_cloudformation_update_user_policy(): iam_client = boto3.client("iam", region_name="us-east-1") user_name_1 = "MyUser1" iam_client.create_user(UserName=user_name_1) user_name_2 = "MyUser2" iam_client.create_user(UserName=user_name_2) s3_client = boto3.client("s3", region_name="us-east-1") bucket_name = "my-bucket" s3_client.create_bucket(Bucket=bucket_name) bucket_arn = "arn:aws:s3:::{0}".format(bucket_name) cf_client = boto3.client("cloudformation", region_name="us-east-1") stack_name = "MyStack" policy_name = "MyPolicy" template = """ Resources: ThePolicy: Type: AWS::IAM::Policy Properties: PolicyName: {0} PolicyDocument: Version: '2012-10-17' Statement: - Effect: Allow Action: s3:* Resource: {1} Users: - {2} """.strip().format( policy_name, bucket_arn, user_name_1 ) cf_client.create_stack(StackName=stack_name, TemplateBody=template) provisioned_resource = cf_client.list_stack_resources(StackName=stack_name)[ "StackResourceSummaries" ][0] logical_resource_id = provisioned_resource["LogicalResourceId"] logical_resource_id.should.equal("ThePolicy") original_policy_document = yaml.load(template, Loader=yaml.FullLoader)["Resources"][ logical_resource_id ]["Properties"]["PolicyDocument"] policy = iam_client.get_user_policy(UserName=user_name_1, PolicyName=policy_name) policy["PolicyDocument"].should.equal(original_policy_document) # Change template and user template = """ Resources: ThePolicy: Type: AWS::IAM::Policy Properties: PolicyName: {0} PolicyDocument: Version: '2012-10-17' Statement: - Effect: Allow Action: s3:ListBuckets Resource: {1} Users: - {2} """.strip().format( policy_name, bucket_arn, user_name_2 ) cf_client.update_stack(StackName=stack_name, TemplateBody=template) provisioned_resource = cf_client.list_stack_resources(StackName=stack_name)[ "StackResourceSummaries" ][0] logical_resource_id = provisioned_resource["LogicalResourceId"] logical_resource_id.should.equal("ThePolicy") original_policy_document = yaml.load(template, Loader=yaml.FullLoader)["Resources"][ logical_resource_id ]["Properties"]["PolicyDocument"] policy = iam_client.get_user_policy(UserName=user_name_2, PolicyName=policy_name) policy["PolicyDocument"].should.equal(original_policy_document) iam_client.get_user_policy.when.called_with( UserName=user_name_1, PolicyName=policy_name ).should.throw(iam_client.exceptions.NoSuchEntityException) @mock_s3 @mock_iam @mock_cloudformation def test_iam_cloudformation_delete_user_policy_having_generated_name(): iam_client = boto3.client("iam", region_name="us-east-1") user_name = "MyUser" iam_client.create_user(UserName=user_name) s3_client = boto3.client("s3", region_name="us-east-1") bucket_name = "my-bucket" bucket = s3_client.create_bucket(Bucket=bucket_name) bucket_arn = "arn:aws:s3:::{0}".format(bucket_name) cf_client = boto3.client("cloudformation", region_name="us-east-1") stack_name = "MyStack" policy_name = "MyPolicy" template = """ Resources: ThePolicy: Type: AWS::IAM::Policy Properties: PolicyName: MyPolicy PolicyDocument: Version: '2012-10-17' Statement: - Effect: Allow Action: s3:* Resource: {0} Users: - {1} """.strip().format( bucket_arn, user_name ) cf_client.create_stack(StackName=stack_name, TemplateBody=template) provisioned_resource = cf_client.list_stack_resources(StackName=stack_name)[ "StackResourceSummaries" ][0] logical_resource_id = provisioned_resource["LogicalResourceId"] logical_resource_id.should.equal("ThePolicy") original_policy_document = yaml.load(template, Loader=yaml.FullLoader)["Resources"][ logical_resource_id ]["Properties"]["PolicyDocument"] policy = iam_client.get_user_policy(UserName=user_name, PolicyName=policy_name) policy["PolicyDocument"].should.equal(original_policy_document) cf_client.delete_stack(StackName=stack_name) iam_client.get_user_policy.when.called_with( UserName=user_name, PolicyName=policy_name ).should.throw(iam_client.exceptions.NoSuchEntityException) @mock_s3 @mock_iam @mock_cloudformation def test_iam_cloudformation_create_role_policy(): iam_client = boto3.client("iam", region_name="us-east-1") role_name = "MyRole" iam_client.create_role(RoleName=role_name, AssumeRolePolicyDocument="{}") s3_client = boto3.client("s3", region_name="us-east-1") bucket_name = "my-bucket" s3_client.create_bucket(Bucket=bucket_name) bucket_arn = "arn:aws:s3:::{0}".format(bucket_name) cf_client = boto3.client("cloudformation", region_name="us-east-1") stack_name = "MyStack" policy_name = "MyPolicy" template = """ Resources: ThePolicy: Type: AWS::IAM::Policy Properties: PolicyName: {0} PolicyDocument: Version: '2012-10-17' Statement: - Effect: Allow Action: s3:* Resource: {1} Roles: - {2} """.strip().format( policy_name, bucket_arn, role_name ) cf_client.create_stack(StackName=stack_name, TemplateBody=template) provisioned_resource = cf_client.list_stack_resources(StackName=stack_name)[ "StackResourceSummaries" ][0] logical_resource_id = provisioned_resource["LogicalResourceId"] logical_resource_id.should.equal("ThePolicy") original_policy_document = yaml.load(template, Loader=yaml.FullLoader)["Resources"][ logical_resource_id ]["Properties"]["PolicyDocument"] policy = iam_client.get_role_policy(RoleName=role_name, PolicyName=policy_name) policy["PolicyDocument"].should.equal(original_policy_document) @mock_s3 @mock_iam @mock_cloudformation def test_iam_cloudformation_update_role_policy(): iam_client = boto3.client("iam", region_name="us-east-1") role_name_1 = "MyRole1" iam_client.create_role(RoleName=role_name_1, AssumeRolePolicyDocument="{}") role_name_2 = "MyRole2" iam_client.create_role(RoleName=role_name_2, AssumeRolePolicyDocument="{}") s3_client = boto3.client("s3", region_name="us-east-1") bucket_name = "my-bucket" s3_client.create_bucket(Bucket=bucket_name) bucket_arn = "arn:aws:s3:::{0}".format(bucket_name) cf_client = boto3.client("cloudformation", region_name="us-east-1") stack_name = "MyStack" policy_name = "MyPolicy" template = """ Resources: ThePolicy: Type: AWS::IAM::Policy Properties: PolicyName: {0} PolicyDocument: Version: '2012-10-17' Statement: - Effect: Allow Action: s3:* Resource: {1} Roles: - {2} """.strip().format( policy_name, bucket_arn, role_name_1 ) cf_client.create_stack(StackName=stack_name, TemplateBody=template) provisioned_resource = cf_client.list_stack_resources(StackName=stack_name)[ "StackResourceSummaries" ][0] logical_resource_id = provisioned_resource["LogicalResourceId"] logical_resource_id.should.equal("ThePolicy") original_policy_document = yaml.load(template, Loader=yaml.FullLoader)["Resources"][ logical_resource_id ]["Properties"]["PolicyDocument"] policy = iam_client.get_role_policy(RoleName=role_name_1, PolicyName=policy_name) policy["PolicyDocument"].should.equal(original_policy_document) # Change template and user template = """ Resources: ThePolicy: Type: AWS::IAM::Policy Properties: PolicyName: {0} PolicyDocument: Version: '2012-10-17' Statement: - Effect: Allow Action: s3:ListBuckets Resource: {1} Roles: - {2} """.strip().format( policy_name, bucket_arn, role_name_2 ) cf_client.update_stack(StackName=stack_name, TemplateBody=template) provisioned_resource = cf_client.list_stack_resources(StackName=stack_name)[ "StackResourceSummaries" ][0] logical_resource_id = provisioned_resource["LogicalResourceId"] logical_resource_id.should.equal("ThePolicy") original_policy_document = yaml.load(template, Loader=yaml.FullLoader)["Resources"][ logical_resource_id ]["Properties"]["PolicyDocument"] policy = iam_client.get_role_policy(RoleName=role_name_2, PolicyName=policy_name) policy["PolicyDocument"].should.equal(original_policy_document) iam_client.get_role_policy.when.called_with( RoleName=role_name_1, PolicyName=policy_name ).should.throw(iam_client.exceptions.NoSuchEntityException) @mock_s3 @mock_iam @mock_cloudformation def test_iam_cloudformation_delete_role_policy_having_generated_name(): iam_client = boto3.client("iam", region_name="us-east-1") role_name = "MyRole" iam_client.create_role(RoleName=role_name, AssumeRolePolicyDocument="{}") s3_client = boto3.client("s3", region_name="us-east-1") bucket_name = "my-bucket" s3_client.create_bucket(Bucket=bucket_name) bucket_arn = "arn:aws:s3:::{0}".format(bucket_name) cf_client = boto3.client("cloudformation", region_name="us-east-1") stack_name = "MyStack" policy_name = "MyPolicy" template = """ Resources: ThePolicy: Type: AWS::IAM::Policy Properties: PolicyName: MyPolicy PolicyDocument: Version: '2012-10-17' Statement: - Effect: Allow Action: s3:* Resource: {0} Roles: - {1} """.strip().format( bucket_arn, role_name ) cf_client.create_stack(StackName=stack_name, TemplateBody=template) provisioned_resource = cf_client.list_stack_resources(StackName=stack_name)[ "StackResourceSummaries" ][0] logical_resource_id = provisioned_resource["LogicalResourceId"] logical_resource_id.should.equal("ThePolicy") original_policy_document = yaml.load(template, Loader=yaml.FullLoader)["Resources"][ logical_resource_id ]["Properties"]["PolicyDocument"] policy = iam_client.get_role_policy(RoleName=role_name, PolicyName=policy_name) policy["PolicyDocument"].should.equal(original_policy_document) cf_client.delete_stack(StackName=stack_name) iam_client.get_role_policy.when.called_with( RoleName=role_name, PolicyName=policy_name ).should.throw(iam_client.exceptions.NoSuchEntityException) @mock_s3 @mock_iam @mock_cloudformation def test_iam_cloudformation_create_group_policy(): iam_client = boto3.client("iam", region_name="us-east-1") group_name = "MyGroup" iam_client.create_group(GroupName=group_name) s3_client = boto3.client("s3", region_name="us-east-1") bucket_name = "my-bucket" s3_client.create_bucket(Bucket=bucket_name) bucket_arn = "arn:aws:s3:::{0}".format(bucket_name) cf_client = boto3.client("cloudformation", region_name="us-east-1") stack_name = "MyStack" policy_name = "MyPolicy" template = """ Resources: ThePolicy: Type: AWS::IAM::Policy Properties: PolicyName: {0} PolicyDocument: Version: '2012-10-17' Statement: - Effect: Allow Action: s3:* Resource: {1} Groups: - {2} """.strip().format( policy_name, bucket_arn, group_name ) cf_client.create_stack(StackName=stack_name, TemplateBody=template) provisioned_resource = cf_client.list_stack_resources(StackName=stack_name)[ "StackResourceSummaries" ][0] logical_resource_id = provisioned_resource["LogicalResourceId"] logical_resource_id.should.equal("ThePolicy") original_policy_document = yaml.load(template, Loader=yaml.FullLoader)["Resources"][ logical_resource_id ]["Properties"]["PolicyDocument"] policy = iam_client.get_group_policy(GroupName=group_name, PolicyName=policy_name) policy["PolicyDocument"].should.equal(original_policy_document) @mock_s3 @mock_iam @mock_cloudformation def test_iam_cloudformation_update_group_policy(): iam_client = boto3.client("iam", region_name="us-east-1") group_name_1 = "MyGroup1" iam_client.create_group(GroupName=group_name_1) group_name_2 = "MyGroup2" iam_client.create_group(GroupName=group_name_2) s3_client = boto3.client("s3", region_name="us-east-1") bucket_name = "my-bucket" s3_client.create_bucket(Bucket=bucket_name) bucket_arn = "arn:aws:s3:::{0}".format(bucket_name) cf_client = boto3.client("cloudformation", region_name="us-east-1") stack_name = "MyStack" policy_name = "MyPolicy" template = """ Resources: ThePolicy: Type: AWS::IAM::Policy Properties: PolicyName: {0} PolicyDocument: Version: '2012-10-17' Statement: - Effect: Allow Action: s3:* Resource: {1} Groups: - {2} """.strip().format( policy_name, bucket_arn, group_name_1 ) cf_client.create_stack(StackName=stack_name, TemplateBody=template) provisioned_resource = cf_client.list_stack_resources(StackName=stack_name)[ "StackResourceSummaries" ][0] logical_resource_id = provisioned_resource["LogicalResourceId"] logical_resource_id.should.equal("ThePolicy") original_policy_document = yaml.load(template, Loader=yaml.FullLoader)["Resources"][ logical_resource_id ]["Properties"]["PolicyDocument"] policy = iam_client.get_group_policy(GroupName=group_name_1, PolicyName=policy_name) policy["PolicyDocument"].should.equal(original_policy_document) # Change template and user template = """ Resources: ThePolicy: Type: AWS::IAM::Policy Properties: PolicyName: {0} PolicyDocument: Version: '2012-10-17' Statement: - Effect: Allow Action: s3:ListBuckets Resource: {1} Groups: - {2} """.strip().format( policy_name, bucket_arn, group_name_2 ) cf_client.update_stack(StackName=stack_name, TemplateBody=template) provisioned_resource = cf_client.list_stack_resources(StackName=stack_name)[ "StackResourceSummaries" ][0] logical_resource_id = provisioned_resource["LogicalResourceId"] logical_resource_id.should.equal("ThePolicy") original_policy_document = yaml.load(template, Loader=yaml.FullLoader)["Resources"][ logical_resource_id ]["Properties"]["PolicyDocument"] policy = iam_client.get_group_policy(GroupName=group_name_2, PolicyName=policy_name) policy["PolicyDocument"].should.equal(original_policy_document) iam_client.get_group_policy.when.called_with( GroupName=group_name_1, PolicyName=policy_name ).should.throw(iam_client.exceptions.NoSuchEntityException) @mock_s3 @mock_iam @mock_cloudformation def test_iam_cloudformation_delete_group_policy_having_generated_name(): iam_client = boto3.client("iam", region_name="us-east-1") group_name = "MyGroup" iam_client.create_group(GroupName=group_name) s3_client = boto3.client("s3", region_name="us-east-1") bucket_name = "my-bucket" s3_client.create_bucket(Bucket=bucket_name) bucket_arn = "arn:aws:s3:::{0}".format(bucket_name) cf_client = boto3.client("cloudformation", region_name="us-east-1") stack_name = "MyStack" policy_name = "MyPolicy" template = """ Resources: ThePolicy: Type: AWS::IAM::Policy Properties: PolicyName: MyPolicy PolicyDocument: Version: '2012-10-17' Statement: - Effect: Allow Action: s3:* Resource: {0} Groups: - {1} """.strip().format( bucket_arn, group_name ) cf_client.create_stack(StackName=stack_name, TemplateBody=template) provisioned_resource = cf_client.list_stack_resources(StackName=stack_name)[ "StackResourceSummaries" ][0] logical_resource_id = provisioned_resource["LogicalResourceId"] logical_resource_id.should.equal("ThePolicy") original_policy_document = yaml.load(template, Loader=yaml.FullLoader)["Resources"][ logical_resource_id ]["Properties"]["PolicyDocument"] policy = iam_client.get_group_policy(GroupName=group_name, PolicyName=policy_name) policy["PolicyDocument"].should.equal(original_policy_document) cf_client.delete_stack(StackName=stack_name) iam_client.get_group_policy.when.called_with( GroupName=group_name, PolicyName=policy_name ).should.throw(iam_client.exceptions.NoSuchEntityException) # AWS::IAM::User AccessKeys @mock_iam @mock_cloudformation def test_iam_cloudformation_create_user_with_access_key(): cf_client = boto3.client("cloudformation", region_name="us-east-1") stack_name = "MyStack" template = """ Resources: TheUser: Type: AWS::IAM::User TheAccessKey: Type: AWS::IAM::AccessKey Properties: UserName: !Ref TheUser """.strip() cf_client.create_stack(StackName=stack_name, TemplateBody=template) provisioned_resources = cf_client.list_stack_resources(StackName=stack_name)[ "StackResourceSummaries" ] provisioned_user = [ resource for resource in provisioned_resources if resource["LogicalResourceId"] == "TheUser" ][0] user_name = provisioned_user["PhysicalResourceId"] provisioned_access_keys = [ resource for resource in provisioned_resources if resource["LogicalResourceId"] == "TheAccessKey" ] len(provisioned_access_keys).should.equal(1) iam_client = boto3.client("iam", region_name="us-east-1") user = iam_client.get_user(UserName=user_name)["User"] user["UserName"].should.equal(user_name) access_keys = iam_client.list_access_keys(UserName=user_name) access_keys["AccessKeyMetadata"][0]["UserName"].should.equal(user_name) @mock_sts @mock_iam @mock_cloudformation def test_iam_cloudformation_access_key_get_attr(): cf_client = boto3.client("cloudformation", region_name="us-east-1") stack_name = "MyStack" template = """ Resources: TheUser: Type: AWS::IAM::User TheAccessKey: Type: AWS::IAM::AccessKey Properties: UserName: !Ref TheUser Outputs: AccessKeyId: Value: !Ref TheAccessKey SecretKey: Value: !GetAtt TheAccessKey.SecretAccessKey """.strip() cf_client.create_stack(StackName=stack_name, TemplateBody=template) provisioned_resources = cf_client.list_stack_resources(StackName=stack_name)[ "StackResourceSummaries" ] provisioned_user = [ resource for resource in provisioned_resources if resource["LogicalResourceId"] == "TheUser" ][0] user_name = provisioned_user["PhysicalResourceId"] stack_description = cf_client.describe_stacks(StackName=stack_name)["Stacks"][0] output_access_key_id = [ output["OutputValue"] for output in stack_description["Outputs"] if output["OutputKey"] == "AccessKeyId" ][0] output_secret_key = [ output["OutputValue"] for output in stack_description["Outputs"] if output["OutputKey"] == "SecretKey" ][0] sts_client = boto3.client( "sts", aws_access_key_id=output_access_key_id, aws_secret_access_key=output_secret_key, region_name="us-east-1", ) caller_identity = sts_client.get_caller_identity() caller_identity["Arn"].split("/")[1].should.equal(user_name) pass @mock_iam @mock_cloudformation def test_iam_cloudformation_delete_users_access_key(): cf_client = boto3.client("cloudformation", region_name="us-east-1") stack_name = "MyStack" template = """ Resources: TheUser: Type: AWS::IAM::User TheAccessKey: Type: AWS::IAM::AccessKey Properties: UserName: !Ref TheUser """.strip() cf_client.create_stack(StackName=stack_name, TemplateBody=template) provisioned_resources = cf_client.list_stack_resources(StackName=stack_name)[ "StackResourceSummaries" ] provisioned_user = [ resource for resource in provisioned_resources if resource["LogicalResourceId"] == "TheUser" ][0] user_name = provisioned_user["PhysicalResourceId"] provisioned_access_key = [ resource for resource in provisioned_resources if resource["LogicalResourceId"] == "TheAccessKey" ][0] access_key_id = provisioned_access_key["PhysicalResourceId"] iam_client = boto3.client("iam", region_name="us-east-1") user = iam_client.get_user(UserName=user_name) access_keys = iam_client.list_access_keys(UserName=user_name) access_key_id.should.equal(access_keys["AccessKeyMetadata"][0]["AccessKeyId"]) cf_client.delete_stack(StackName=stack_name) iam_client.get_user.when.called_with(UserName=user_name).should.throw( iam_client.exceptions.NoSuchEntityException ) iam_client.list_access_keys.when.called_with(UserName=user_name).should.throw( iam_client.exceptions.NoSuchEntityException ) @mock_iam @mock_cloudformation def test_iam_cloudformation_delete_users_access_key(): cf_client = boto3.client("cloudformation", region_name="us-east-1") stack_name = "MyStack" template = """ Resources: TheUser: Type: AWS::IAM::User TheAccessKey: Type: AWS::IAM::AccessKey Properties: UserName: !Ref TheUser """.strip() cf_client.create_stack(StackName=stack_name, TemplateBody=template) provisioned_resources = cf_client.list_stack_resources(StackName=stack_name)[ "StackResourceSummaries" ] provisioned_user = [ resource for resource in provisioned_resources if resource["LogicalResourceId"] == "TheUser" ][0] user_name = provisioned_user["PhysicalResourceId"] provisioned_access_keys = [ resource for resource in provisioned_resources if resource["LogicalResourceId"] == "TheAccessKey" ] len(provisioned_access_keys).should.equal(1) iam_client = boto3.client("iam", region_name="us-east-1") user = iam_client.get_user(UserName=user_name)["User"] user["UserName"].should.equal(user_name) access_keys = iam_client.list_access_keys(UserName=user_name) access_keys["AccessKeyMetadata"][0]["UserName"].should.equal(user_name) cf_client.delete_stack(StackName=stack_name) iam_client.get_user.when.called_with(UserName=user_name).should.throw( iam_client.exceptions.NoSuchEntityException ) iam_client.list_access_keys.when.called_with(UserName=user_name).should.throw( iam_client.exceptions.NoSuchEntityException ) @mock_iam @mock_cloudformation def test_iam_cloudformation_update_users_access_key_no_interruption(): cf_client = boto3.client("cloudformation", region_name="us-east-1") stack_name = "MyStack" template = """ Resources: TheUser: Type: AWS::IAM::User TheAccessKey: Type: AWS::IAM::AccessKey Properties: UserName: !Ref TheUser """.strip() cf_client.create_stack(StackName=stack_name, TemplateBody=template) provisioned_resources = cf_client.list_stack_resources(StackName=stack_name)[ "StackResourceSummaries" ] provisioned_user = [ resource for resource in provisioned_resources if resource["LogicalResourceId"] == "TheUser" ][0] user_name = provisioned_user["PhysicalResourceId"] provisioned_access_key = [ resource for resource in provisioned_resources if resource["LogicalResourceId"] == "TheAccessKey" ][0] access_key_id = provisioned_access_key["PhysicalResourceId"] iam_client = boto3.client("iam", region_name="us-east-1") user = iam_client.get_user(UserName=user_name) access_keys = iam_client.list_access_keys(UserName=user_name) access_key_id.should.equal(access_keys["AccessKeyMetadata"][0]["AccessKeyId"]) template = """ Resources: TheUser: Type: AWS::IAM::User TheAccessKey: Type: AWS::IAM::AccessKey Properties: Status: Inactive """.strip() cf_client.update_stack(StackName=stack_name, TemplateBody=template) access_keys = iam_client.list_access_keys(UserName=user_name) access_keys["AccessKeyMetadata"][0]["Status"].should.equal("Inactive") @mock_iam @mock_cloudformation def test_iam_cloudformation_update_users_access_key_replacement(): cf_client = boto3.client("cloudformation", region_name="us-east-1") stack_name = "MyStack" template = """ Resources: TheUser: Type: AWS::IAM::User TheAccessKey: Type: AWS::IAM::AccessKey Properties: UserName: !Ref TheUser """.strip() cf_client.create_stack(StackName=stack_name, TemplateBody=template) provisioned_resources = cf_client.list_stack_resources(StackName=stack_name)[ "StackResourceSummaries" ] provisioned_user = [ resource for resource in provisioned_resources if resource["LogicalResourceId"] == "TheUser" ][0] user_name = provisioned_user["PhysicalResourceId"] provisioned_access_key = [ resource for resource in provisioned_resources if resource["LogicalResourceId"] == "TheAccessKey" ][0] access_key_id = provisioned_access_key["PhysicalResourceId"] iam_client = boto3.client("iam", region_name="us-east-1") user = iam_client.get_user(UserName=user_name) access_keys = iam_client.list_access_keys(UserName=user_name) access_key_id.should.equal(access_keys["AccessKeyMetadata"][0]["AccessKeyId"]) other_user_name = "MyUser" iam_client.create_user(UserName=other_user_name) template = """ Resources: TheUser: Type: AWS::IAM::User TheAccessKey: Type: AWS::IAM::AccessKey Properties: UserName: {0} """.strip().format( other_user_name ) cf_client.update_stack(StackName=stack_name, TemplateBody=template) access_keys = iam_client.list_access_keys(UserName=user_name) len(access_keys["AccessKeyMetadata"]).should.equal(0) access_keys = iam_client.list_access_keys(UserName=other_user_name) access_key_id.should_not.equal(access_keys["AccessKeyMetadata"][0]["AccessKeyId"])