Adding support for specifying a PermissionsBoundary ARN in calls to i… (#2182)
* Adding support for specifying a PermissionsBoundary ARN in calls to iam.create_role Closes #2181 * Correcting whitespace error * Adding support for Role PermissionsBoundary to be returned from calls to list_roles * Raise ClientError when a bad permissions boundary ARN is supplied
This commit is contained in:
parent
33efe07b43
commit
b8ba7980a0
@ -9,6 +9,7 @@ from cryptography import x509
|
||||
from cryptography.hazmat.backends import default_backend
|
||||
|
||||
import pytz
|
||||
from moto.core.exceptions import RESTError
|
||||
from moto.core import BaseBackend, BaseModel
|
||||
from moto.core.utils import iso_8601_datetime_without_milliseconds
|
||||
|
||||
@ -131,7 +132,7 @@ class InlinePolicy(Policy):
|
||||
|
||||
class Role(BaseModel):
|
||||
|
||||
def __init__(self, role_id, name, assume_role_policy_document, path):
|
||||
def __init__(self, role_id, name, assume_role_policy_document, path, permissions_boundary):
|
||||
self.id = role_id
|
||||
self.name = name
|
||||
self.assume_role_policy_document = assume_role_policy_document
|
||||
@ -141,6 +142,7 @@ class Role(BaseModel):
|
||||
self.create_date = datetime.now(pytz.utc)
|
||||
self.tags = {}
|
||||
self.description = ""
|
||||
self.permissions_boundary = permissions_boundary
|
||||
|
||||
@classmethod
|
||||
def create_from_cloudformation_json(cls, resource_name, cloudformation_json, region_name):
|
||||
@ -150,6 +152,7 @@ class Role(BaseModel):
|
||||
role_name=resource_name,
|
||||
assume_role_policy_document=properties['AssumeRolePolicyDocument'],
|
||||
path=properties.get('Path', '/'),
|
||||
permissions_boundary=properties.get('PermissionsBoundary', '')
|
||||
)
|
||||
|
||||
policies = properties.get('Policies', [])
|
||||
@ -470,6 +473,8 @@ class IAMBackend(BaseBackend):
|
||||
self.managed_policies = self._init_managed_policies()
|
||||
self.account_aliases = []
|
||||
self.saml_providers = {}
|
||||
self.policy_arn_regex = re.compile(
|
||||
r'^arn:aws:iam::[0-9]*:policy/.*$')
|
||||
super(IAMBackend, self).__init__()
|
||||
|
||||
def _init_managed_policies(self):
|
||||
@ -587,9 +592,12 @@ class IAMBackend(BaseBackend):
|
||||
|
||||
return policies, marker
|
||||
|
||||
def create_role(self, role_name, assume_role_policy_document, path):
|
||||
def create_role(self, role_name, assume_role_policy_document, path, permissions_boundary):
|
||||
role_id = random_resource_id()
|
||||
role = Role(role_id, role_name, assume_role_policy_document, path)
|
||||
if permissions_boundary and not self.policy_arn_regex.match(permissions_boundary):
|
||||
raise RESTError('InvalidParameterValue', 'Value ({}) for parameter PermissionsBoundary is invalid.'.format(permissions_boundary))
|
||||
|
||||
role = Role(role_id, role_name, assume_role_policy_document, path, permissions_boundary)
|
||||
self.roles[role_id] = role
|
||||
return role
|
||||
|
||||
|
@ -175,9 +175,11 @@ class IamResponse(BaseResponse):
|
||||
path = self._get_param('Path')
|
||||
assume_role_policy_document = self._get_param(
|
||||
'AssumeRolePolicyDocument')
|
||||
permissions_boundary = self._get_param(
|
||||
'PermissionsBoundary')
|
||||
|
||||
role = iam_backend.create_role(
|
||||
role_name, assume_role_policy_document, path)
|
||||
role_name, assume_role_policy_document, path, permissions_boundary)
|
||||
template = self.response_template(CREATE_ROLE_TEMPLATE)
|
||||
return template.render(role=role)
|
||||
|
||||
@ -1000,6 +1002,12 @@ CREATE_ROLE_TEMPLATE = """<CreateRoleResponse xmlns="https://iam.amazonaws.com/d
|
||||
<AssumeRolePolicyDocument>{{ role.assume_role_policy_document }}</AssumeRolePolicyDocument>
|
||||
<CreateDate>{{ role.create_date }}</CreateDate>
|
||||
<RoleId>{{ role.id }}</RoleId>
|
||||
{% if role.permissions_boundary %}
|
||||
<PermissionsBoundary>
|
||||
<PermissionsBoundaryType>PermissionsBoundaryPolicy</PermissionsBoundaryType>
|
||||
<PermissionsBoundaryArn>{{ role.permissions_boundary }}</PermissionsBoundaryArn>
|
||||
</PermissionsBoundary>
|
||||
{% endif %}
|
||||
</Role>
|
||||
</CreateRoleResult>
|
||||
<ResponseMetadata>
|
||||
@ -1102,6 +1110,12 @@ LIST_ROLES_TEMPLATE = """<ListRolesResponse xmlns="https://iam.amazonaws.com/doc
|
||||
<AssumeRolePolicyDocument>{{ role.assume_role_policy_document }}</AssumeRolePolicyDocument>
|
||||
<CreateDate>{{ role.create_date }}</CreateDate>
|
||||
<RoleId>{{ role.id }}</RoleId>
|
||||
{% if role.permissions_boundary %}
|
||||
<PermissionsBoundary>
|
||||
<PermissionsBoundaryType>PermissionsBoundaryPolicy</PermissionsBoundaryType>
|
||||
<PermissionsBoundaryArn>{{ role.permissions_boundary }}</PermissionsBoundaryArn>
|
||||
</PermissionsBoundary>
|
||||
{% endif %}
|
||||
</member>
|
||||
{% endfor %}
|
||||
</Roles>
|
||||
|
@ -128,7 +128,6 @@ def test_create_role_and_instance_profile():
|
||||
profile = conn.create_instance_profile('my-other-profile')
|
||||
profile.path.should.equal('/')
|
||||
|
||||
|
||||
@mock_iam_deprecated()
|
||||
def test_remove_role_from_instance_profile():
|
||||
conn = boto.connect_iam()
|
||||
@ -358,7 +357,7 @@ def test_list_policy_versions():
|
||||
versions = conn.list_policy_versions(
|
||||
PolicyArn="arn:aws:iam::123456789012:policy/TestListPolicyVersions")
|
||||
versions.get('Versions')[0].get('VersionId').should.equal('v1')
|
||||
|
||||
|
||||
conn.create_policy_version(
|
||||
PolicyArn="arn:aws:iam::123456789012:policy/TestListPolicyVersions",
|
||||
PolicyDocument='{"second":"policy"}')
|
||||
@ -1292,4 +1291,22 @@ def test_create_role_no_path():
|
||||
conn = boto3.client('iam', region_name='us-east-1')
|
||||
resp = conn.create_role(RoleName='my-role', AssumeRolePolicyDocument='some policy', Description='test')
|
||||
resp.get('Role').get('Arn').should.equal('arn:aws:iam::123456789012:role/my-role')
|
||||
resp.get('Role').should_not.have.key('PermissionsBoundary')
|
||||
|
||||
@mock_iam()
|
||||
def test_create_role_with_permissions_boundary():
|
||||
conn = boto3.client('iam', region_name='us-east-1')
|
||||
boundary = 'arn:aws:iam::123456789012:policy/boundary'
|
||||
resp = conn.create_role(RoleName='my-role', AssumeRolePolicyDocument='some policy', Description='test', PermissionsBoundary=boundary)
|
||||
expected = {
|
||||
'PermissionsBoundaryType': 'PermissionsBoundaryPolicy',
|
||||
'PermissionsBoundaryArn': boundary
|
||||
}
|
||||
resp.get('Role').get('PermissionsBoundary').should.equal(expected)
|
||||
|
||||
invalid_boundary_arn = 'arn:aws:iam::123456789:not_a_boundary'
|
||||
with assert_raises(ClientError):
|
||||
conn.create_role(RoleName='bad-boundary', AssumeRolePolicyDocument='some policy', Description='test', PermissionsBoundary=invalid_boundary_arn)
|
||||
|
||||
# Ensure the PermissionsBoundary is included in role listing as well
|
||||
conn.list_roles().get('Roles')[0].get('PermissionsBoundary').should.equal(expected)
|
||||
|
Loading…
Reference in New Issue
Block a user