Created
May 24, 2021 11:44
-
-
Save vikasbajaj/c1353b1a5cdda6cbd168a24e83e86a9f to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
AWSTemplateFormatVersion: '2010-09-09' | |
Description: This template deploys IAM service control policies required for managing AWS organizations. | |
Resources: | |
LambdaExecutionRole: | |
Type: AWS::IAM::Role | |
Properties: | |
Description: IAM Role for lambda to access Redshift | |
ManagedPolicyArns: | |
- arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole | |
- arn:aws:iam::aws:policy/AWSOrganizationsFullAccess | |
AssumeRolePolicyDocument: | |
Version: 2012-10-17 | |
Statement: | |
- | |
Effect: Allow | |
Principal: | |
Service: | |
- lambda.amazonaws.com | |
Action: | |
- sts:AssumeRole | |
Path: / | |
SCP_1: | |
Type: Custom::ServiceControlPolicy | |
Properties: | |
PolicyName: SCP_WHITELIST_REGION | |
PolicyDescription: >- | |
This SCP denies access to any operations outside of the specified AWS Region, | |
except for actions in the listed services. | |
PolicyContents: >- | |
{ | |
"Version":"2012-10-17", | |
"Statement":[ | |
{ | |
"NotAction":[ | |
"iam:*", | |
"organizations:*", | |
"route53:*", | |
"budgets:*", | |
"waf:*", | |
"cloudfront:*", | |
"globalaccelerator:*", | |
"importexport:*", | |
"support:*", | |
"health:*", | |
"route53domains:*" | |
], | |
"Resource":"*", | |
"Effect":"Deny", | |
"Condition":{ | |
"StringNotEquals":{ | |
"aws:RequestedRegion":[ | |
"ap-southeast-2", | |
"ap-southeast-1" | |
] | |
} | |
} | |
} | |
] | |
} | |
ServiceToken: !GetAtt SCPOperatorLambdaFunction.Arn | |
SCP_2: | |
Type: Custom::ServiceControlPolicy | |
Properties: | |
PolicyName: SCP_DENY_ROOT_ACCOUNT | |
PolicyDescription: >- | |
This SCP prevents/restricts the root user in an AWS account from taking | |
any action, either directly as a command or through the console. | |
PolicyContents: >- | |
{ | |
"Version":"2012-10-17", | |
"Statement":[ | |
{ | |
"Action":"*", | |
"Resource":"*", | |
"Effect":"Deny", | |
"Condition":{ | |
"StringLike":{ | |
"aws:PrincipalArn":[ | |
"arn:aws:iam::*:root" | |
] | |
} | |
} | |
} | |
] | |
} | |
ServiceToken: !GetAtt SCPOperatorLambdaFunction.Arn | |
DependsOn: | |
- SCP_1 | |
SCP_3: | |
Type: Custom::ServiceControlPolicy | |
Properties: | |
PolicyName: SCP_DENY_DISABLE_CLOUDTRAIL | |
PolicyDescription: >- | |
This SCP prevents users or roles in any affected account from disabling | |
a CloudTrail log, either directly as a command or through the console. | |
PolicyContents: >- | |
{ | |
"Version":"2012-10-17", | |
"Statement":[ | |
{ | |
"Action": "cloudtrail:StopLogging", | |
"Resource":"*", | |
"Effect":"Deny" | |
} | |
] | |
} | |
ServiceToken: !GetAtt SCPOperatorLambdaFunction.Arn | |
DependsOn: | |
- SCP_2 | |
SCPOperatorLambdaFunction: | |
Type: AWS::Lambda::Function | |
Properties: | |
FunctionName: demo_scp_operator_function | |
Description: Lambda function to deploy CloudFormation custom resources for Organization SCPs. | |
Code: | |
ZipFile: |- | |
import boto3 | |
import cfnresponse as cfn | |
client = boto3.client('organizations', region_name='ap-southeast-2') | |
def handler(event, context): | |
'''Handle Lambda event from AWS CloudFormation.''' | |
try: | |
resource_action = event['RequestType'] | |
policy_name = event['ResourceProperties']['PolicyName'] | |
policy_contents = event['ResourceProperties']['PolicyContents'] | |
policy_description = event['ResourceProperties']['PolicyDescription'] | |
if resource_action == 'Create': | |
print('ACTION: {} policy'.format(resource_action)) | |
# this call creates SCP in the AWS Organization | |
response = client.create_policy( | |
Content=policy_contents, | |
Description=policy_description, | |
Name=policy_name, | |
Type='SERVICE_CONTROL_POLICY' | |
) | |
print('*******************************') | |
print(response['Policy']['PolicySummary']['Id']) | |
policy_id = response['Policy']['PolicySummary']['Id'] | |
# target_id here is a sample id for one of the OU under Organization Root | |
target_id = 'ou-z01g-43uk0frl' | |
print('RESPONSE: {}'.format(response)) | |
print('*******************************') | |
# this call attches the SCP to the specified "target_id" (target id is an OU id on which this SCP will be applied) | |
client.attach_policy( | |
PolicyId=policy_id, | |
TargetId=target_id) | |
cfn.send(event, context, cfn.SUCCESS, | |
{'Message': "Policy created successfully."}, 'CustomResourcePhysicalID') | |
elif resource_action == 'Update' or resource_action == 'Delete': | |
print('ACTION: {} policy'.format(resource_action)) | |
cfn.send(event, context, cfn.SUCCESS, | |
{'Message': "Policy modified successfully."}, 'CustomResourcePhysicalID') | |
else: | |
print('ACTION: Unexpected') | |
cfn.send(event, context, cfn.FAILED, | |
{'Message': 'Unexpected event received from CloudFormation'}, | |
'CustomResourcePhysicalID') | |
except Exception as exc: | |
print('FAILED: {}'.format(exc)) | |
cfn.send(event, context, cfn.FAILED, | |
{'Message': exc}, 'CustomResourcePhysicalID') | |
Role: !GetAtt 'LambdaExecutionRole.Arn' | |
Runtime: python3.7 | |
Handler: index.handler | |
MemorySize: 128 | |
Timeout: 120 |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Sample cloudformation template which uses Cloudformation custom resources to create and attach policies with a specific OU (represented by target_id variable)