A configuration package to deploy common Service Control Policies (SCPs) in the master account of an AWS Organization. The SCPs are grouped for different security domains and services: See full SCP Repository to browse individual SCP policies.
AWSTemplateFormatVersion: "2010-09-09"
Description: ""
Resources:
ScpPolicy1:
Type: "Custom::ServiceControlPolicy"
Properties:
PolicyName: "scp_account_protection"
PolicyDescription: "scp_account_protection"
PolicyContents: "{\"Version\":\"2012-10-17\",\"Statement\":[{\"Action\":\"*\",\"Resource\":\"*\",\"Effect\":\"Deny\",\"Condition\":{\"StringLike\":{\"aws:PrincipalArn\":[\"arn:aws:iam::*:root\"]}}},{\"Action\":[\"organizations:LeaveOrganization\"],\"Resource\":\"*\",\"Effect\":\"Deny\"},{\"Action\":[\"aws-portal:ModifyAccount\",\"aws-portal:ModifyBilling\",\"aws-portal:ModifyPaymentMethods\"],\"Resource\":\"*\",\"Effect\":\"Deny\"}]}"
ServiceToken:
Fn::GetAtt:
- "ScpResourceLambda"
- "Arn"
ScpResourceLambdaRole:
Type: "AWS::IAM::Role"
Properties:
AssumeRolePolicyDocument:
Version: "2012-10-17"
Statement:
- Effect: "Allow"
Principal:
Service: "lambda.amazonaws.com"
Action:
- "sts:AssumeRole"
Path: "/"
ManagedPolicyArns:
- "arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole"
Policies:
- PolicyName: "scp-access"
PolicyDocument:
Statement:
- Effect: "Allow"
Action:
- "organizations:UpdatePolicy"
- "organizations:DeletePolicy"
- "organizations:CreatePolicy"
- "organizations:ListPolicies"
Resource: "*"
ScpResourceLambda:
Type: "AWS::Lambda::Function"
Properties:
Code:
ZipFile: "\n'use strict';\nconst AWS = require('aws-sdk');\nconst response = require('cfn-response');\nconst organizations = new AWS.Organizations({region: 'us-east-1'});\n\nexports.handler = (event, context, cb) => {\n console.log('Invoke:', JSON.stringify(event));\n const done = (err, data) => {\n if (err) {\n console.log('Error: ', err);\n response.send(event, context, response.FAILED, {}, 'CustomResourcePhysicalID');\n } else {\n response.send(event, context, response.SUCCESS, {}, 'CustomResourcePhysicalID');\n }\n };\n \n const updatePolicies = (policyName, policyAction) => {\n organizations.listPolicies({\n Filter: \"SERVICE_CONTROL_POLICY\"\n }, function(err, data){\n if (err) done(err);\n else {\n const policy = data.Policies.filter((policy) => (policy.Name === policyName))\n let policyId = ''\n if (policy.length > 0) \n policyId = policy[0].Id\n else\n done('policy not found')\n if (policyAction === 'Update'){\n organizations.updatePolicy({\n Content: event.ResourceProperties.PolicyContents,\n PolicyId: policyId\n }, done)\n }\n else {\n organizations.deletePolicy({\n PolicyId: policyId\n }, done)\n }\n }\n })\n }\n \n if (event.RequestType === 'Update' || event.RequestType === 'Delete') {\n updatePolicies(event.ResourceProperties.PolicyName, event.RequestType)\n \n } else if (event.RequestType === 'Create') {\n organizations.createPolicy({\n Content: event.ResourceProperties.PolicyContents, \n Description: event.ResourceProperties.PolicyDescription, \n Name: event.ResourceProperties.PolicyName, \n Type: \"SERVICE_CONTROL_POLICY\"\n }, done);\n } else {\n cb(new Error('unsupported RequestType: ', event.RequestType));\n }\n};"
Handler: "index.handler"
MemorySize: 128
Role:
Fn::GetAtt:
- "ScpResourceLambdaRole"
- "Arn"
Runtime: "nodejs12.x"
Timeout: 120
ScpPolicy2:
Type: "Custom::ServiceControlPolicy"
Properties:
PolicyName: "scp_logging_services_protection"
PolicyDescription: "scp_logging_services_protection"
PolicyContents: "{\"Version\":\"2012-10-17\",\"Statement\":[{\"Action\":[\"cloudtrail:StopLogging\",\"cloudtrail:DeleteTrail\"],\"Resource\":\"*\",\"Effect\":\"Deny\"},{\"Action\":[\"config:DeleteConfigRule\",\"config:DeleteConfigurationRecorder\",\"config:DeleteDeliveryChannel\",\"config:StopConfigurationRecorder\"],\"Resource\":\"*\",\"Effect\":\"Deny\"},{\"Action\":[\"guardduty:DeleteDetector\",\"guardduty:DeleteInvitations\",\"guardduty:DeleteIPSet\",\"guardduty:DeleteMembers\",\"guardduty:DeleteThreatIntelSet\",\"guardduty:DisassociateFromMasterAccount\",\"guardduty:DisassociateMembers\",\"guardduty:StopMonitoringMembers\",\"guardduty:UpdateDetector\"],\"Resource\":\"*\",\"Effect\":\"Deny\"},{\"Action\":[\"securityhub:DeleteInvitations\",\"securityhub:DisableSecurityHub\",\"securityhub:DisassociateFromMasterAccount\",\"securityhub:DeleteMembers\",\"securityhub:DisassociateMembers\"],\"Resource\":\"*\",\"Effect\":\"Deny\"}]}"
ServiceToken:
Fn::GetAtt:
- "ScpResourceLambda"
- "Arn"
DependsOn:
- "ScpPolicy1"
ScpPolicy3:
Type: "Custom::ServiceControlPolicy"
Properties:
PolicyName: "scp_iam_protection"
PolicyDescription: "scp_iam_protection"
PolicyContents: "{\"Version\":\"2012-10-17\",\"Statement\":[{\"Action\":[\"iam:CreateUser\",\"iam:CreateAccessKey\"],\"Resource\":[\"*\"],\"Effect\":\"Deny\"}]}"
ServiceToken:
Fn::GetAtt:
- "ScpResourceLambda"
- "Arn"
DependsOn:
- "ScpPolicy2"
ScpPolicy4:
Type: "Custom::ServiceControlPolicy"
Properties:
PolicyName: "scp_s3_protection"
PolicyDescription: "scp_s3_protection"
PolicyContents: "{\"Version\":\"2012-10-17\",\"Statement\":[{\"Action\":[\"s3:PutAccountPublicAccessBlock\"],\"Resource\":\"*\",\"Effect\":\"Deny\"}]}"
ServiceToken:
Fn::GetAtt:
- "ScpResourceLambda"
- "Arn"
DependsOn:
- "ScpPolicy3"
Parameters: {}
Metadata: {}
Conditions: {}