CF support for IAM:ManagedPolicy (#3933)
This commit is contained in:
parent
6d0bcba791
commit
6b960e0d4f
@ -253,7 +253,7 @@ class PolicyVersion(object):
|
||||
return iso_8601_datetime_with_milliseconds(self.create_date)
|
||||
|
||||
|
||||
class ManagedPolicy(Policy):
|
||||
class ManagedPolicy(Policy, CloudFormationModel):
|
||||
"""Managed policy."""
|
||||
|
||||
is_attachable = True
|
||||
@ -312,6 +312,47 @@ class ManagedPolicy(Policy):
|
||||
"supplementaryConfiguration": {},
|
||||
}
|
||||
|
||||
@staticmethod
|
||||
def cloudformation_name_type():
|
||||
return None # Resource never gets named after by template PolicyName!
|
||||
|
||||
@staticmethod
|
||||
def cloudformation_type():
|
||||
return "AWS::IAM::ManagedPolicy"
|
||||
|
||||
@classmethod
|
||||
def create_from_cloudformation_json(
|
||||
cls, resource_physical_name, cloudformation_json, region_name
|
||||
):
|
||||
properties = cloudformation_json.get("Properties", {})
|
||||
policy_document = json.dumps(properties.get("PolicyDocument"))
|
||||
name = properties.get("ManagedPolicyName", resource_physical_name)
|
||||
description = properties.get("Description")
|
||||
path = properties.get("Path")
|
||||
group_names = properties.get("Groups", [])
|
||||
user_names = properties.get("Users", [])
|
||||
role_names = properties.get("Roles", [])
|
||||
|
||||
policy = iam_backend.create_policy(
|
||||
description=description,
|
||||
path=path,
|
||||
policy_document=policy_document,
|
||||
policy_name=name,
|
||||
)
|
||||
for group_name in group_names:
|
||||
iam_backend.attach_group_policy(
|
||||
group_name=group_name, policy_arn=policy.arn
|
||||
)
|
||||
for user_name in user_names:
|
||||
iam_backend.attach_user_policy(user_name=user_name, policy_arn=policy.arn)
|
||||
for role_name in role_names:
|
||||
iam_backend.attach_role_policy(role_name=role_name, policy_arn=policy.arn)
|
||||
return policy
|
||||
|
||||
@property
|
||||
def physical_resource_id(self):
|
||||
return self.arn
|
||||
|
||||
|
||||
class AWSManagedPolicy(ManagedPolicy):
|
||||
"""AWS-managed policy."""
|
||||
|
@ -125,7 +125,7 @@ class IamResponse(BaseResponse):
|
||||
entity_groups = []
|
||||
entity_users = []
|
||||
|
||||
if entity == "User":
|
||||
if not entity or entity == "User":
|
||||
users = iam_backend.list_users(path_prefix, marker, max_items)
|
||||
if users:
|
||||
for user in users:
|
||||
@ -133,7 +133,7 @@ class IamResponse(BaseResponse):
|
||||
if p == policy_arn:
|
||||
entity_users.append(user.name)
|
||||
|
||||
elif entity == "Role":
|
||||
if not entity or entity == "Role":
|
||||
roles, _ = iam_backend.list_roles(path_prefix, marker, max_items)
|
||||
if roles:
|
||||
for role in roles:
|
||||
@ -141,7 +141,7 @@ class IamResponse(BaseResponse):
|
||||
if p == policy_arn:
|
||||
entity_roles.append(role.name)
|
||||
|
||||
elif entity == "Group":
|
||||
if not entity or entity == "Group":
|
||||
groups = iam_backend.list_groups()
|
||||
if groups:
|
||||
for group in groups:
|
||||
@ -149,7 +149,7 @@ class IamResponse(BaseResponse):
|
||||
if p == policy_arn:
|
||||
entity_groups.append(group.name)
|
||||
|
||||
elif entity == "LocalManagedPolicy" or entity == "AWSManagedPolicy":
|
||||
if entity == "LocalManagedPolicy" or entity == "AWSManagedPolicy":
|
||||
users = iam_backend.list_users(path_prefix, marker, max_items)
|
||||
if users:
|
||||
for user in users:
|
||||
|
@ -2357,18 +2357,24 @@ def test_list_entities_for_policy():
|
||||
EntityFilter="Role",
|
||||
)
|
||||
assert response["PolicyRoles"] == [{"RoleName": "my-role"}]
|
||||
response["PolicyGroups"].should.equal([])
|
||||
response["PolicyUsers"].should.equal([])
|
||||
|
||||
response = conn.list_entities_for_policy(
|
||||
PolicyArn="arn:aws:iam::{}:policy/testPolicy".format(ACCOUNT_ID),
|
||||
EntityFilter="User",
|
||||
)
|
||||
assert response["PolicyUsers"] == [{"UserName": "testUser"}]
|
||||
response["PolicyGroups"].should.equal([])
|
||||
response["PolicyRoles"].should.equal([])
|
||||
|
||||
response = conn.list_entities_for_policy(
|
||||
PolicyArn="arn:aws:iam::{}:policy/testPolicy".format(ACCOUNT_ID),
|
||||
EntityFilter="Group",
|
||||
)
|
||||
assert response["PolicyGroups"] == [{"GroupName": "testGroup"}]
|
||||
response["PolicyRoles"].should.equal([])
|
||||
response["PolicyUsers"].should.equal([])
|
||||
|
||||
response = conn.list_entities_for_policy(
|
||||
PolicyArn="arn:aws:iam::{}:policy/testPolicy".format(ACCOUNT_ID),
|
||||
@ -2378,6 +2384,14 @@ def test_list_entities_for_policy():
|
||||
assert response["PolicyUsers"] == [{"UserName": "testUser"}]
|
||||
assert response["PolicyRoles"] == [{"RoleName": "my-role"}]
|
||||
|
||||
# Return everything when no entity is specified
|
||||
response = conn.list_entities_for_policy(
|
||||
PolicyArn="arn:aws:iam::{}:policy/testPolicy".format(ACCOUNT_ID)
|
||||
)
|
||||
response["PolicyGroups"].should.equal([{"GroupName": "testGroup"}])
|
||||
response["PolicyUsers"].should.equal([{"UserName": "testUser"}])
|
||||
response["PolicyRoles"].should.equal([{"RoleName": "my-role"}])
|
||||
|
||||
|
||||
@mock_iam()
|
||||
def test_create_role_no_path():
|
||||
|
@ -6,6 +6,7 @@ import pytest
|
||||
from botocore.exceptions import ClientError
|
||||
|
||||
from moto import mock_iam, mock_cloudformation, mock_s3, mock_sts
|
||||
from moto.core import ACCOUNT_ID
|
||||
|
||||
# AWS::IAM::User Tests
|
||||
@mock_iam
|
||||
@ -281,6 +282,245 @@ Outputs:
|
||||
output_user_arn.should.equal(user_description["Arn"])
|
||||
|
||||
|
||||
# AWS::IAM::ManagedPolicy Tests
|
||||
@mock_iam
|
||||
@mock_cloudformation
|
||||
def test_iam_cloudformation_create_managed_policy():
|
||||
iam_client = boto3.client("iam", region_name="us-east-1")
|
||||
cf_client = boto3.client("cloudformation", region_name="us-east-1")
|
||||
stack_name = "MyStack"
|
||||
|
||||
template = """
|
||||
Resources:
|
||||
ThePolicy:
|
||||
Type: AWS::IAM::ManagedPolicy
|
||||
Properties:
|
||||
PolicyDocument:
|
||||
Version: '2012-10-17'
|
||||
Statement:
|
||||
- Effect: Allow
|
||||
Action: s3:*
|
||||
Resource: '*'
|
||||
""".strip()
|
||||
|
||||
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")
|
||||
|
||||
policy_arn = provisioned_resource["PhysicalResourceId"]
|
||||
policy_arn.should.match(
|
||||
"arn:aws:iam::{}:policy/MyStack-ThePolicy-[A-Z0-9]+".format(ACCOUNT_ID)
|
||||
)
|
||||
expected_name = policy_arn.split("/")[1]
|
||||
|
||||
response = iam_client.list_entities_for_policy(PolicyArn=policy_arn)
|
||||
response.should.have.key("PolicyGroups").equal([])
|
||||
response.should.have.key("PolicyUsers").equal([])
|
||||
response.should.have.key("PolicyRoles").equal([])
|
||||
|
||||
policy = iam_client.get_policy(PolicyArn=policy_arn)["Policy"]
|
||||
policy.should.have.key("Arn").equal(policy_arn)
|
||||
policy.should.have.key("PolicyName").equal(expected_name)
|
||||
policy.should.have.key("Description").equal("")
|
||||
policy.should.have.key("Path").equal("/")
|
||||
|
||||
|
||||
@mock_iam
|
||||
@mock_cloudformation
|
||||
def test_iam_cloudformation_create_managed_policy_with_additional_properties():
|
||||
iam_client = boto3.client("iam", region_name="us-east-1")
|
||||
cf_client = boto3.client("cloudformation", region_name="us-east-1")
|
||||
stack_name = "MyStack"
|
||||
name = "FancyManagedPolicy"
|
||||
desc = "Custom managed policy with name"
|
||||
|
||||
template = """
|
||||
Resources:
|
||||
ThePolicy:
|
||||
Type: AWS::IAM::ManagedPolicy
|
||||
Properties:
|
||||
Description: {0}
|
||||
Path: /
|
||||
ManagedPolicyName: {1}
|
||||
PolicyDocument:
|
||||
Version: '2012-10-17'
|
||||
Statement:
|
||||
- Effect: Allow
|
||||
Action: s3:*
|
||||
Resource: '*'
|
||||
""".strip().format(
|
||||
desc, 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")
|
||||
|
||||
policy_arn = provisioned_resource["PhysicalResourceId"]
|
||||
policy_arn.should.equal("arn:aws:iam::{}:policy/{}".format(ACCOUNT_ID, name))
|
||||
|
||||
policy = iam_client.get_policy(PolicyArn=policy_arn)["Policy"]
|
||||
policy.should.have.key("Arn").equal(policy_arn)
|
||||
policy.should.have.key("Path").equal("/")
|
||||
policy.should.have.key("Description").equal(desc)
|
||||
policy.should.have.key("PolicyName").equal(name)
|
||||
|
||||
|
||||
@mock_iam
|
||||
@mock_cloudformation
|
||||
def test_iam_cloudformation_create_managed_policy_attached_to_a_group():
|
||||
iam_client = boto3.client("iam", region_name="us-east-1")
|
||||
group_name = "MyGroup"
|
||||
iam_client.create_group(GroupName=group_name)
|
||||
|
||||
cf_client = boto3.client("cloudformation", region_name="us-east-1")
|
||||
stack_name = "MyStack"
|
||||
desc = "Custom managed policy"
|
||||
|
||||
template = """
|
||||
Resources:
|
||||
ThePolicy:
|
||||
Type: AWS::IAM::ManagedPolicy
|
||||
Properties:
|
||||
Description: {0}
|
||||
Path: /
|
||||
PolicyDocument:
|
||||
Version: '2012-10-17'
|
||||
Statement:
|
||||
- Effect: Allow
|
||||
Action: s3:*
|
||||
Resource: '*'
|
||||
Groups:
|
||||
- {1}
|
||||
""".strip().format(
|
||||
desc, 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")
|
||||
|
||||
policy_arn = provisioned_resource["PhysicalResourceId"]
|
||||
policy_arn.should.match(
|
||||
"rn:aws:iam::{}:policy/MyStack-ThePolicy-[A-Z0-9]+".format(ACCOUNT_ID)
|
||||
)
|
||||
|
||||
response = iam_client.list_entities_for_policy(PolicyArn=policy_arn)
|
||||
response.should.have.key("PolicyGroups").equal([{"GroupName": group_name}])
|
||||
response.should.have.key("PolicyUsers").equal([])
|
||||
response.should.have.key("PolicyRoles").equal([])
|
||||
|
||||
|
||||
@mock_iam
|
||||
@mock_cloudformation
|
||||
def test_iam_cloudformation_create_managed_policy_attached_to_a_user():
|
||||
iam_client = boto3.client("iam", region_name="us-east-1")
|
||||
user_name = "MyUser"
|
||||
iam_client.create_user(UserName=user_name)
|
||||
|
||||
cf_client = boto3.client("cloudformation", region_name="us-east-1")
|
||||
stack_name = "MyStack"
|
||||
desc = "Custom managed policy"
|
||||
|
||||
template = """
|
||||
Resources:
|
||||
ThePolicy:
|
||||
Type: AWS::IAM::ManagedPolicy
|
||||
Properties:
|
||||
Description: {0}
|
||||
Path: /
|
||||
PolicyDocument:
|
||||
Version: '2012-10-17'
|
||||
Statement:
|
||||
- Effect: Allow
|
||||
Action: s3:*
|
||||
Resource: '*'
|
||||
Users:
|
||||
- {1}
|
||||
""".strip().format(
|
||||
desc, 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")
|
||||
|
||||
policy_arn = provisioned_resource["PhysicalResourceId"]
|
||||
policy_arn.should.match(
|
||||
"rn:aws:iam::{}:policy/MyStack-ThePolicy-[A-Z0-9]+".format(ACCOUNT_ID)
|
||||
)
|
||||
|
||||
response = iam_client.list_entities_for_policy(PolicyArn=policy_arn)
|
||||
response.should.have.key("PolicyGroups").equal([])
|
||||
response.should.have.key("PolicyUsers").equal([{"UserName": user_name}])
|
||||
response.should.have.key("PolicyRoles").equal([])
|
||||
|
||||
|
||||
@mock_iam
|
||||
@mock_cloudformation
|
||||
def test_iam_cloudformation_create_managed_policy_attached_to_a_role():
|
||||
iam_client = boto3.client("iam", region_name="us-east-1")
|
||||
role_name = "MyRole"
|
||||
iam_client.create_role(RoleName=role_name, AssumeRolePolicyDocument="some policy")
|
||||
|
||||
cf_client = boto3.client("cloudformation", region_name="us-east-1")
|
||||
stack_name = "MyStack"
|
||||
desc = "Custom managed policy"
|
||||
|
||||
template = """
|
||||
Resources:
|
||||
ThePolicy:
|
||||
Type: AWS::IAM::ManagedPolicy
|
||||
Properties:
|
||||
Description: {0}
|
||||
Path: /
|
||||
PolicyDocument:
|
||||
Version: '2012-10-17'
|
||||
Statement:
|
||||
- Effect: Allow
|
||||
Action: s3:*
|
||||
Resource: '*'
|
||||
Roles:
|
||||
- {1}
|
||||
""".strip().format(
|
||||
desc, 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")
|
||||
|
||||
policy_arn = provisioned_resource["PhysicalResourceId"]
|
||||
policy_arn.should.match(
|
||||
"rn:aws:iam::{}:policy/MyStack-ThePolicy-[A-Z0-9]+".format(ACCOUNT_ID)
|
||||
)
|
||||
|
||||
response = iam_client.list_entities_for_policy(PolicyArn=policy_arn)
|
||||
response.should.have.key("PolicyGroups").equal([])
|
||||
response.should.have.key("PolicyUsers").equal([])
|
||||
response.should.have.key("PolicyRoles").equal([{"RoleName": role_name}])
|
||||
|
||||
|
||||
# AWS::IAM::Policy Tests
|
||||
@mock_s3
|
||||
@mock_iam
|
||||
|
Loading…
x
Reference in New Issue
Block a user