adding support for organizations service control policies * [Resolves #2196] - endpoints for querying organizations SC policies I have added the following mock endpoints to the Organizations service: - create_policy - list_policies - describe_policy - attach_policy - list_policies_for_target - list_targets_for_policy
This commit is contained in:
parent
a61124f774
commit
a3f6d2c110
6 changed files with 508 additions and 26 deletions
|
|
@ -5,38 +5,36 @@ import sure # noqa
|
|||
import datetime
|
||||
from moto.organizations import utils
|
||||
|
||||
EMAIL_REGEX = "^.+@[a-zA-Z0-9-.]+.[a-zA-Z]{2,3}|[0-9]{1,3}$"
|
||||
ORG_ID_REGEX = r'o-[a-z0-9]{%s}' % utils.ORG_ID_SIZE
|
||||
ROOT_ID_REGEX = r'r-[a-z0-9]{%s}' % utils.ROOT_ID_SIZE
|
||||
OU_ID_REGEX = r'ou-[a-z0-9]{%s}-[a-z0-9]{%s}' % (utils.ROOT_ID_SIZE, utils.OU_ID_SUFFIX_SIZE)
|
||||
ACCOUNT_ID_REGEX = r'[0-9]{%s}' % utils.ACCOUNT_ID_SIZE
|
||||
CREATE_ACCOUNT_STATUS_ID_REGEX = r'car-[a-z0-9]{%s}' % utils.CREATE_ACCOUNT_STATUS_ID_SIZE
|
||||
|
||||
|
||||
def test_make_random_org_id():
|
||||
org_id = utils.make_random_org_id()
|
||||
org_id.should.match(ORG_ID_REGEX)
|
||||
org_id.should.match(utils.ORG_ID_REGEX)
|
||||
|
||||
|
||||
def test_make_random_root_id():
|
||||
root_id = utils.make_random_root_id()
|
||||
root_id.should.match(ROOT_ID_REGEX)
|
||||
root_id.should.match(utils.ROOT_ID_REGEX)
|
||||
|
||||
|
||||
def test_make_random_ou_id():
|
||||
root_id = utils.make_random_root_id()
|
||||
ou_id = utils.make_random_ou_id(root_id)
|
||||
ou_id.should.match(OU_ID_REGEX)
|
||||
ou_id.should.match(utils.OU_ID_REGEX)
|
||||
|
||||
|
||||
def test_make_random_account_id():
|
||||
account_id = utils.make_random_account_id()
|
||||
account_id.should.match(ACCOUNT_ID_REGEX)
|
||||
account_id.should.match(utils.ACCOUNT_ID_REGEX)
|
||||
|
||||
|
||||
def test_make_random_create_account_status_id():
|
||||
create_account_status_id = utils.make_random_create_account_status_id()
|
||||
create_account_status_id.should.match(CREATE_ACCOUNT_STATUS_ID_REGEX)
|
||||
create_account_status_id.should.match(utils.CREATE_ACCOUNT_STATUS_ID_REGEX)
|
||||
|
||||
|
||||
def test_make_random_service_control_policy_id():
|
||||
service_control_policy_id = utils.make_random_service_control_policy_id()
|
||||
service_control_policy_id.should.match(utils.SCP_ID_REGEX)
|
||||
|
||||
|
||||
def validate_organization(response):
|
||||
|
|
@ -50,7 +48,7 @@ def validate_organization(response):
|
|||
'MasterAccountEmail',
|
||||
'MasterAccountId',
|
||||
])
|
||||
org['Id'].should.match(ORG_ID_REGEX)
|
||||
org['Id'].should.match(utils.ORG_ID_REGEX)
|
||||
org['MasterAccountId'].should.equal(utils.MASTER_ACCOUNT_ID)
|
||||
org['MasterAccountArn'].should.equal(utils.MASTER_ACCOUNT_ARN_FORMAT.format(
|
||||
org['MasterAccountId'],
|
||||
|
|
@ -72,7 +70,7 @@ def validate_roots(org, response):
|
|||
response.should.have.key('Roots').should.be.a(list)
|
||||
response['Roots'].should_not.be.empty
|
||||
root = response['Roots'][0]
|
||||
root.should.have.key('Id').should.match(ROOT_ID_REGEX)
|
||||
root.should.have.key('Id').should.match(utils.ROOT_ID_REGEX)
|
||||
root.should.have.key('Arn').should.equal(utils.ROOT_ARN_FORMAT.format(
|
||||
org['MasterAccountId'],
|
||||
org['Id'],
|
||||
|
|
@ -87,7 +85,7 @@ def validate_roots(org, response):
|
|||
def validate_organizational_unit(org, response):
|
||||
response.should.have.key('OrganizationalUnit').should.be.a(dict)
|
||||
ou = response['OrganizationalUnit']
|
||||
ou.should.have.key('Id').should.match(OU_ID_REGEX)
|
||||
ou.should.have.key('Id').should.match(utils.OU_ID_REGEX)
|
||||
ou.should.have.key('Arn').should.equal(utils.OU_ARN_FORMAT.format(
|
||||
org['MasterAccountId'],
|
||||
org['Id'],
|
||||
|
|
@ -106,13 +104,13 @@ def validate_account(org, account):
|
|||
'Name',
|
||||
'Status',
|
||||
])
|
||||
account['Id'].should.match(ACCOUNT_ID_REGEX)
|
||||
account['Id'].should.match(utils.ACCOUNT_ID_REGEX)
|
||||
account['Arn'].should.equal(utils.ACCOUNT_ARN_FORMAT.format(
|
||||
org['MasterAccountId'],
|
||||
org['Id'],
|
||||
account['Id'],
|
||||
))
|
||||
account['Email'].should.match(EMAIL_REGEX)
|
||||
account['Email'].should.match(utils.EMAIL_REGEX)
|
||||
account['JoinedMethod'].should.be.within(['INVITED', 'CREATED'])
|
||||
account['Status'].should.be.within(['ACTIVE', 'SUSPENDED'])
|
||||
account['Name'].should.be.a(six.string_types)
|
||||
|
|
@ -128,9 +126,27 @@ def validate_create_account_status(create_status):
|
|||
'RequestedTimestamp',
|
||||
'State',
|
||||
])
|
||||
create_status['Id'].should.match(CREATE_ACCOUNT_STATUS_ID_REGEX)
|
||||
create_status['AccountId'].should.match(ACCOUNT_ID_REGEX)
|
||||
create_status['Id'].should.match(utils.CREATE_ACCOUNT_STATUS_ID_REGEX)
|
||||
create_status['AccountId'].should.match(utils.ACCOUNT_ID_REGEX)
|
||||
create_status['AccountName'].should.be.a(six.string_types)
|
||||
create_status['State'].should.equal('SUCCEEDED')
|
||||
create_status['RequestedTimestamp'].should.be.a(datetime.datetime)
|
||||
create_status['CompletedTimestamp'].should.be.a(datetime.datetime)
|
||||
|
||||
def validate_policy_summary(org, summary):
|
||||
summary.should.be.a(dict)
|
||||
summary.should.have.key('Id').should.match(utils.SCP_ID_REGEX)
|
||||
summary.should.have.key('Arn').should.equal(utils.SCP_ARN_FORMAT.format(
|
||||
org['MasterAccountId'],
|
||||
org['Id'],
|
||||
summary['Id'],
|
||||
))
|
||||
summary.should.have.key('Name').should.be.a(six.string_types)
|
||||
summary.should.have.key('Description').should.be.a(six.string_types)
|
||||
summary.should.have.key('Type').should.equal('SERVICE_CONTROL_POLICY')
|
||||
summary.should.have.key('AwsManaged').should.be.a(bool)
|
||||
|
||||
def validate_service_control_policy(org, response):
|
||||
response.should.have.key('PolicySummary').should.be.a(dict)
|
||||
response.should.have.key('Content').should.be.a(six.string_types)
|
||||
validate_policy_summary(org, response['PolicySummary'])
|
||||
|
|
|
|||
|
|
@ -1,6 +1,8 @@
|
|||
from __future__ import unicode_literals
|
||||
|
||||
import boto3
|
||||
import json
|
||||
import six
|
||||
import sure # noqa
|
||||
from botocore.exceptions import ClientError
|
||||
from nose.tools import assert_raises
|
||||
|
|
@ -13,6 +15,8 @@ from .organizations_test_utils import (
|
|||
validate_organizational_unit,
|
||||
validate_account,
|
||||
validate_create_account_status,
|
||||
validate_service_control_policy,
|
||||
validate_policy_summary,
|
||||
)
|
||||
|
||||
|
||||
|
|
@ -320,3 +324,271 @@ def test_list_children_exception():
|
|||
ex.operation_name.should.equal('ListChildren')
|
||||
ex.response['Error']['Code'].should.equal('400')
|
||||
ex.response['Error']['Message'].should.contain('InvalidInputException')
|
||||
|
||||
|
||||
# Service Control Policies
|
||||
policy_doc01 = dict(
|
||||
Version='2012-10-17',
|
||||
Statement=[dict(
|
||||
Sid='MockPolicyStatement',
|
||||
Effect='Allow',
|
||||
Action='s3:*',
|
||||
Resource='*',
|
||||
)]
|
||||
)
|
||||
|
||||
@mock_organizations
|
||||
def test_create_policy():
|
||||
client = boto3.client('organizations', region_name='us-east-1')
|
||||
org = client.create_organization(FeatureSet='ALL')['Organization']
|
||||
policy = client.create_policy(
|
||||
Content=json.dumps(policy_doc01),
|
||||
Description='A dummy service control policy',
|
||||
Name='MockServiceControlPolicy',
|
||||
Type='SERVICE_CONTROL_POLICY'
|
||||
)['Policy']
|
||||
validate_service_control_policy(org, policy)
|
||||
policy['PolicySummary']['Name'].should.equal('MockServiceControlPolicy')
|
||||
policy['PolicySummary']['Description'].should.equal('A dummy service control policy')
|
||||
policy['Content'].should.equal(json.dumps(policy_doc01))
|
||||
|
||||
|
||||
@mock_organizations
|
||||
def test_describe_policy():
|
||||
client = boto3.client('organizations', region_name='us-east-1')
|
||||
org = client.create_organization(FeatureSet='ALL')['Organization']
|
||||
policy_id = client.create_policy(
|
||||
Content=json.dumps(policy_doc01),
|
||||
Description='A dummy service control policy',
|
||||
Name='MockServiceControlPolicy',
|
||||
Type='SERVICE_CONTROL_POLICY'
|
||||
)['Policy']['PolicySummary']['Id']
|
||||
policy = client.describe_policy(PolicyId=policy_id)['Policy']
|
||||
validate_service_control_policy(org, policy)
|
||||
policy['PolicySummary']['Name'].should.equal('MockServiceControlPolicy')
|
||||
policy['PolicySummary']['Description'].should.equal('A dummy service control policy')
|
||||
policy['Content'].should.equal(json.dumps(policy_doc01))
|
||||
|
||||
|
||||
@mock_organizations
|
||||
def test_describe_policy_exception():
|
||||
client = boto3.client('organizations', region_name='us-east-1')
|
||||
client.create_organization(FeatureSet='ALL')['Organization']
|
||||
policy_id = 'p-47fhe9s3'
|
||||
with assert_raises(ClientError) as e:
|
||||
response = client.describe_policy(PolicyId=policy_id)
|
||||
ex = e.exception
|
||||
ex.operation_name.should.equal('DescribePolicy')
|
||||
ex.response['Error']['Code'].should.equal('400')
|
||||
ex.response['Error']['Message'].should.contain('PolicyNotFoundException')
|
||||
with assert_raises(ClientError) as e:
|
||||
response = client.describe_policy(PolicyId='meaninglessstring')
|
||||
ex = e.exception
|
||||
ex.operation_name.should.equal('DescribePolicy')
|
||||
ex.response['Error']['Code'].should.equal('400')
|
||||
ex.response['Error']['Message'].should.contain('InvalidInputException')
|
||||
|
||||
|
||||
@mock_organizations
|
||||
def test_attach_policy():
|
||||
client = boto3.client('organizations', region_name='us-east-1')
|
||||
org = client.create_organization(FeatureSet='ALL')['Organization']
|
||||
root_id = client.list_roots()['Roots'][0]['Id']
|
||||
ou_id = client.create_organizational_unit(
|
||||
ParentId=root_id,
|
||||
Name='ou01',
|
||||
)['OrganizationalUnit']['Id']
|
||||
account_id = client.create_account(
|
||||
AccountName=mockname,
|
||||
Email=mockemail,
|
||||
)['CreateAccountStatus']['AccountId']
|
||||
policy_id = client.create_policy(
|
||||
Content=json.dumps(policy_doc01),
|
||||
Description='A dummy service control policy',
|
||||
Name='MockServiceControlPolicy',
|
||||
Type='SERVICE_CONTROL_POLICY'
|
||||
)['Policy']['PolicySummary']['Id']
|
||||
response = client.attach_policy(PolicyId=policy_id, TargetId=root_id)
|
||||
response['ResponseMetadata']['HTTPStatusCode'].should.equal(200)
|
||||
response = client.attach_policy(PolicyId=policy_id, TargetId=ou_id)
|
||||
response['ResponseMetadata']['HTTPStatusCode'].should.equal(200)
|
||||
response = client.attach_policy(PolicyId=policy_id, TargetId=account_id)
|
||||
response['ResponseMetadata']['HTTPStatusCode'].should.equal(200)
|
||||
|
||||
|
||||
@mock_organizations
|
||||
def test_attach_policy_exception():
|
||||
client = boto3.client('organizations', region_name='us-east-1')
|
||||
client.create_organization(FeatureSet='ALL')['Organization']
|
||||
root_id='r-dj873'
|
||||
ou_id='ou-gi99-i7r8eh2i2'
|
||||
account_id='126644886543'
|
||||
policy_id = client.create_policy(
|
||||
Content=json.dumps(policy_doc01),
|
||||
Description='A dummy service control policy',
|
||||
Name='MockServiceControlPolicy',
|
||||
Type='SERVICE_CONTROL_POLICY'
|
||||
)['Policy']['PolicySummary']['Id']
|
||||
with assert_raises(ClientError) as e:
|
||||
response = client.attach_policy(PolicyId=policy_id, TargetId=root_id)
|
||||
ex = e.exception
|
||||
ex.operation_name.should.equal('AttachPolicy')
|
||||
ex.response['Error']['Code'].should.equal('400')
|
||||
ex.response['Error']['Message'].should.contain('OrganizationalUnitNotFoundException')
|
||||
with assert_raises(ClientError) as e:
|
||||
response = client.attach_policy(PolicyId=policy_id, TargetId=ou_id)
|
||||
ex = e.exception
|
||||
ex.operation_name.should.equal('AttachPolicy')
|
||||
ex.response['Error']['Code'].should.equal('400')
|
||||
ex.response['Error']['Message'].should.contain('OrganizationalUnitNotFoundException')
|
||||
with assert_raises(ClientError) as e:
|
||||
response = client.attach_policy(PolicyId=policy_id, TargetId=account_id)
|
||||
ex = e.exception
|
||||
ex.operation_name.should.equal('AttachPolicy')
|
||||
ex.response['Error']['Code'].should.equal('400')
|
||||
ex.response['Error']['Message'].should.contain('AccountNotFoundException')
|
||||
with assert_raises(ClientError) as e:
|
||||
response = client.attach_policy(PolicyId=policy_id, TargetId='meaninglessstring')
|
||||
ex = e.exception
|
||||
ex.operation_name.should.equal('AttachPolicy')
|
||||
ex.response['Error']['Code'].should.equal('400')
|
||||
ex.response['Error']['Message'].should.contain('InvalidInputException')
|
||||
|
||||
|
||||
@mock_organizations
|
||||
def test_list_polices():
|
||||
client = boto3.client('organizations', region_name='us-east-1')
|
||||
org = client.create_organization(FeatureSet='ALL')['Organization']
|
||||
for i in range(0,4):
|
||||
client.create_policy(
|
||||
Content=json.dumps(policy_doc01),
|
||||
Description='A dummy service control policy',
|
||||
Name='MockServiceControlPolicy' + str(i),
|
||||
Type='SERVICE_CONTROL_POLICY'
|
||||
)
|
||||
response = client.list_policies(Filter='SERVICE_CONTROL_POLICY')
|
||||
for policy in response['Policies']:
|
||||
validate_policy_summary(org, policy)
|
||||
|
||||
|
||||
@mock_organizations
|
||||
def test_list_policies_for_target():
|
||||
client = boto3.client('organizations', region_name='us-east-1')
|
||||
org = client.create_organization(FeatureSet='ALL')['Organization']
|
||||
root_id = client.list_roots()['Roots'][0]['Id']
|
||||
ou_id = client.create_organizational_unit(
|
||||
ParentId=root_id,
|
||||
Name='ou01',
|
||||
)['OrganizationalUnit']['Id']
|
||||
account_id = client.create_account(
|
||||
AccountName=mockname,
|
||||
Email=mockemail,
|
||||
)['CreateAccountStatus']['AccountId']
|
||||
policy_id = client.create_policy(
|
||||
Content=json.dumps(policy_doc01),
|
||||
Description='A dummy service control policy',
|
||||
Name='MockServiceControlPolicy',
|
||||
Type='SERVICE_CONTROL_POLICY'
|
||||
)['Policy']['PolicySummary']['Id']
|
||||
client.attach_policy(PolicyId=policy_id, TargetId=ou_id)
|
||||
response = client.list_policies_for_target(
|
||||
TargetId=ou_id,
|
||||
Filter='SERVICE_CONTROL_POLICY',
|
||||
)
|
||||
for policy in response['Policies']:
|
||||
validate_policy_summary(org, policy)
|
||||
client.attach_policy(PolicyId=policy_id, TargetId=account_id)
|
||||
response = client.list_policies_for_target(
|
||||
TargetId=account_id,
|
||||
Filter='SERVICE_CONTROL_POLICY',
|
||||
)
|
||||
for policy in response['Policies']:
|
||||
validate_policy_summary(org, policy)
|
||||
|
||||
|
||||
@mock_organizations
|
||||
def test_list_policies_for_target_exception():
|
||||
client = boto3.client('organizations', region_name='us-east-1')
|
||||
client.create_organization(FeatureSet='ALL')['Organization']
|
||||
ou_id='ou-gi99-i7r8eh2i2'
|
||||
account_id='126644886543'
|
||||
with assert_raises(ClientError) as e:
|
||||
response = client.list_policies_for_target(
|
||||
TargetId=ou_id,
|
||||
Filter='SERVICE_CONTROL_POLICY',
|
||||
)
|
||||
ex = e.exception
|
||||
ex.operation_name.should.equal('ListPoliciesForTarget')
|
||||
ex.response['Error']['Code'].should.equal('400')
|
||||
ex.response['Error']['Message'].should.contain('OrganizationalUnitNotFoundException')
|
||||
with assert_raises(ClientError) as e:
|
||||
response = client.list_policies_for_target(
|
||||
TargetId=account_id,
|
||||
Filter='SERVICE_CONTROL_POLICY',
|
||||
)
|
||||
ex = e.exception
|
||||
ex.operation_name.should.equal('ListPoliciesForTarget')
|
||||
ex.response['Error']['Code'].should.equal('400')
|
||||
ex.response['Error']['Message'].should.contain('AccountNotFoundException')
|
||||
with assert_raises(ClientError) as e:
|
||||
response = client.list_policies_for_target(
|
||||
TargetId='meaninglessstring',
|
||||
Filter='SERVICE_CONTROL_POLICY',
|
||||
)
|
||||
ex = e.exception
|
||||
ex.operation_name.should.equal('ListPoliciesForTarget')
|
||||
ex.response['Error']['Code'].should.equal('400')
|
||||
ex.response['Error']['Message'].should.contain('InvalidInputException')
|
||||
|
||||
|
||||
@mock_organizations
|
||||
def test_list_targets_for_policy():
|
||||
client = boto3.client('organizations', region_name='us-east-1')
|
||||
org = client.create_organization(FeatureSet='ALL')['Organization']
|
||||
root_id = client.list_roots()['Roots'][0]['Id']
|
||||
ou_id = client.create_organizational_unit(
|
||||
ParentId=root_id,
|
||||
Name='ou01',
|
||||
)['OrganizationalUnit']['Id']
|
||||
account_id = client.create_account(
|
||||
AccountName=mockname,
|
||||
Email=mockemail,
|
||||
)['CreateAccountStatus']['AccountId']
|
||||
policy_id = client.create_policy(
|
||||
Content=json.dumps(policy_doc01),
|
||||
Description='A dummy service control policy',
|
||||
Name='MockServiceControlPolicy',
|
||||
Type='SERVICE_CONTROL_POLICY'
|
||||
)['Policy']['PolicySummary']['Id']
|
||||
client.attach_policy(PolicyId=policy_id, TargetId=root_id)
|
||||
client.attach_policy(PolicyId=policy_id, TargetId=ou_id)
|
||||
client.attach_policy(PolicyId=policy_id, TargetId=account_id)
|
||||
response = client.list_targets_for_policy(PolicyId=policy_id)
|
||||
for target in response['Targets']:
|
||||
target.should.be.a(dict)
|
||||
target.should.have.key('Name').should.be.a(six.string_types)
|
||||
target.should.have.key('Arn').should.be.a(six.string_types)
|
||||
target.should.have.key('TargetId').should.be.a(six.string_types)
|
||||
target.should.have.key('Type').should.be.within(
|
||||
['ROOT', 'ORGANIZATIONAL_UNIT', 'ACCOUNT']
|
||||
)
|
||||
|
||||
|
||||
@mock_organizations
|
||||
def test_list_targets_for_policy_exception():
|
||||
client = boto3.client('organizations', region_name='us-east-1')
|
||||
client.create_organization(FeatureSet='ALL')['Organization']
|
||||
policy_id = 'p-47fhe9s3'
|
||||
with assert_raises(ClientError) as e:
|
||||
response = client.list_targets_for_policy(PolicyId=policy_id)
|
||||
ex = e.exception
|
||||
ex.operation_name.should.equal('ListTargetsForPolicy')
|
||||
ex.response['Error']['Code'].should.equal('400')
|
||||
ex.response['Error']['Message'].should.contain('PolicyNotFoundException')
|
||||
with assert_raises(ClientError) as e:
|
||||
response = client.list_targets_for_policy(PolicyId='meaninglessstring')
|
||||
ex = e.exception
|
||||
ex.operation_name.should.equal('ListTargetsForPolicy')
|
||||
ex.response['Error']['Code'].should.equal('400')
|
||||
ex.response['Error']['Message'].should.contain('InvalidInputException')
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue