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)
|
return iso_8601_datetime_with_milliseconds(self.create_date)
|
||||||
|
|
||||||
|
|
||||||
class ManagedPolicy(Policy):
|
class ManagedPolicy(Policy, CloudFormationModel):
|
||||||
"""Managed policy."""
|
"""Managed policy."""
|
||||||
|
|
||||||
is_attachable = True
|
is_attachable = True
|
||||||
@ -312,6 +312,47 @@ class ManagedPolicy(Policy):
|
|||||||
"supplementaryConfiguration": {},
|
"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):
|
class AWSManagedPolicy(ManagedPolicy):
|
||||||
"""AWS-managed policy."""
|
"""AWS-managed policy."""
|
||||||
|
@ -125,7 +125,7 @@ class IamResponse(BaseResponse):
|
|||||||
entity_groups = []
|
entity_groups = []
|
||||||
entity_users = []
|
entity_users = []
|
||||||
|
|
||||||
if entity == "User":
|
if not entity or entity == "User":
|
||||||
users = iam_backend.list_users(path_prefix, marker, max_items)
|
users = iam_backend.list_users(path_prefix, marker, max_items)
|
||||||
if users:
|
if users:
|
||||||
for user in users:
|
for user in users:
|
||||||
@ -133,7 +133,7 @@ class IamResponse(BaseResponse):
|
|||||||
if p == policy_arn:
|
if p == policy_arn:
|
||||||
entity_users.append(user.name)
|
entity_users.append(user.name)
|
||||||
|
|
||||||
elif entity == "Role":
|
if not entity or entity == "Role":
|
||||||
roles, _ = iam_backend.list_roles(path_prefix, marker, max_items)
|
roles, _ = iam_backend.list_roles(path_prefix, marker, max_items)
|
||||||
if roles:
|
if roles:
|
||||||
for role in roles:
|
for role in roles:
|
||||||
@ -141,7 +141,7 @@ class IamResponse(BaseResponse):
|
|||||||
if p == policy_arn:
|
if p == policy_arn:
|
||||||
entity_roles.append(role.name)
|
entity_roles.append(role.name)
|
||||||
|
|
||||||
elif entity == "Group":
|
if not entity or entity == "Group":
|
||||||
groups = iam_backend.list_groups()
|
groups = iam_backend.list_groups()
|
||||||
if groups:
|
if groups:
|
||||||
for group in groups:
|
for group in groups:
|
||||||
@ -149,7 +149,7 @@ class IamResponse(BaseResponse):
|
|||||||
if p == policy_arn:
|
if p == policy_arn:
|
||||||
entity_groups.append(group.name)
|
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)
|
users = iam_backend.list_users(path_prefix, marker, max_items)
|
||||||
if users:
|
if users:
|
||||||
for user in users:
|
for user in users:
|
||||||
|
@ -2357,18 +2357,24 @@ def test_list_entities_for_policy():
|
|||||||
EntityFilter="Role",
|
EntityFilter="Role",
|
||||||
)
|
)
|
||||||
assert response["PolicyRoles"] == [{"RoleName": "my-role"}]
|
assert response["PolicyRoles"] == [{"RoleName": "my-role"}]
|
||||||
|
response["PolicyGroups"].should.equal([])
|
||||||
|
response["PolicyUsers"].should.equal([])
|
||||||
|
|
||||||
response = conn.list_entities_for_policy(
|
response = conn.list_entities_for_policy(
|
||||||
PolicyArn="arn:aws:iam::{}:policy/testPolicy".format(ACCOUNT_ID),
|
PolicyArn="arn:aws:iam::{}:policy/testPolicy".format(ACCOUNT_ID),
|
||||||
EntityFilter="User",
|
EntityFilter="User",
|
||||||
)
|
)
|
||||||
assert response["PolicyUsers"] == [{"UserName": "testUser"}]
|
assert response["PolicyUsers"] == [{"UserName": "testUser"}]
|
||||||
|
response["PolicyGroups"].should.equal([])
|
||||||
|
response["PolicyRoles"].should.equal([])
|
||||||
|
|
||||||
response = conn.list_entities_for_policy(
|
response = conn.list_entities_for_policy(
|
||||||
PolicyArn="arn:aws:iam::{}:policy/testPolicy".format(ACCOUNT_ID),
|
PolicyArn="arn:aws:iam::{}:policy/testPolicy".format(ACCOUNT_ID),
|
||||||
EntityFilter="Group",
|
EntityFilter="Group",
|
||||||
)
|
)
|
||||||
assert response["PolicyGroups"] == [{"GroupName": "testGroup"}]
|
assert response["PolicyGroups"] == [{"GroupName": "testGroup"}]
|
||||||
|
response["PolicyRoles"].should.equal([])
|
||||||
|
response["PolicyUsers"].should.equal([])
|
||||||
|
|
||||||
response = conn.list_entities_for_policy(
|
response = conn.list_entities_for_policy(
|
||||||
PolicyArn="arn:aws:iam::{}:policy/testPolicy".format(ACCOUNT_ID),
|
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["PolicyUsers"] == [{"UserName": "testUser"}]
|
||||||
assert response["PolicyRoles"] == [{"RoleName": "my-role"}]
|
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()
|
@mock_iam()
|
||||||
def test_create_role_no_path():
|
def test_create_role_no_path():
|
||||||
|
@ -6,6 +6,7 @@ import pytest
|
|||||||
from botocore.exceptions import ClientError
|
from botocore.exceptions import ClientError
|
||||||
|
|
||||||
from moto import mock_iam, mock_cloudformation, mock_s3, mock_sts
|
from moto import mock_iam, mock_cloudformation, mock_s3, mock_sts
|
||||||
|
from moto.core import ACCOUNT_ID
|
||||||
|
|
||||||
# AWS::IAM::User Tests
|
# AWS::IAM::User Tests
|
||||||
@mock_iam
|
@mock_iam
|
||||||
@ -281,6 +282,245 @@ Outputs:
|
|||||||
output_user_arn.should.equal(user_description["Arn"])
|
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
|
# AWS::IAM::Policy Tests
|
||||||
@mock_s3
|
@mock_s3
|
||||||
@mock_iam
|
@mock_iam
|
||||||
|
Loading…
x
Reference in New Issue
Block a user