Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Save vikasbajaj/c1353b1a5cdda6cbd168a24e83e86a9f to your computer and use it in GitHub Desktop.
Save vikasbajaj/c1353b1a5cdda6cbd168a24e83e86a9f to your computer and use it in GitHub Desktop.
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
@vikasbajaj
Copy link
Author

Sample cloudformation template which uses Cloudformation custom resources to create and attach policies with a specific OU (represented by target_id variable)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment