- AWS Prescriptive Guidance
- Goal
- Prerequisites and limitations
- Architecture
- Tools
- Best practices
- Control Behavior And Guidance
- Setup
- Deployment
- Useful Commands
- IAM policy
- Trust policy
- Authors
- Security
- License
For a complete guide, prerequisites and instructions for using this AWS Prescriptive Guidance pattern, see Deploy and manage AWS Control Tower controls by using AWS CDK and AWS CloudFormation.
This pattern describes how to use AWS CloudFormation and AWS Cloud Development Kit (AWS CDK) to implement and administer preventive, detective, and proactive AWS Control Tower controls as infrastructure as code (IaC). A control (also known as a guardrail) is a high-level rule that provides ongoing governance for your overall AWS Control Tower environment. For example, you can use controls to require logging for your AWS accounts and then configure automatic notifications if specific security-related events occur.
AWS Control Tower helps you implement preventive, detective, and proactive controls that govern your AWS resources and monitor compliance across multiple AWS accounts. Each control enforces a single rule. In this pattern, you use a provided IaC template to specify which controls you want to deploy in your environment.
AWS Control Tower controls apply to an entire organizational unit (OU), and the control affects every AWS account within the OU. Therefore, when users perform any action in any account in your landing zone, the action is subject to the controls that govern the OU.
Implementing AWS Control Tower controls helps establish a strong security foundation for your AWS landing zone. By using this pattern to deploy the controls as IaC through CloudFormation and AWS CDK, you can standardize the controls in your landing zone and more efficiently deploy and manage them. This solution uses cdk_nag to scan the AWS CDK application during deployment. This tool checks the application for adherence to AWS best practices.
To deploy AWS Control Tower controls as IaC, you can also use HashiCorp Terraform instead of AWS CDK. For more information, see Deploy and manage AWS Control Tower controls by using Terraform.
This pattern is recommended for users who have experience with AWS Control Tower, CloudFormation, AWS CDK, and AWS Organizations.
-
Active AWS accounts managed as an organization in AWS Organizations and an AWS Control Tower landing zone. For instructions, see Create an account structure (AWS Well-Architected Labs).
-
AWS Command Line Interface (AWS CLI), installed and configured.
-
Node package manager (npm), installed and configured for the AWS CDK.
-
Prerequisites for AWS CDK.
-
Permissions to assume an existing AWS Identity and Access Management (IAM) role in a deployment account.
-
Permissions to assume an IAM role in the organization’s management account that that can be used to bootstrap AWS CDK. The role must have permissions to modify and deploy CloudFormation resources. For more information, see Bootstrapping in the AWS CDK documentation.
-
Permissions to create IAM roles and policies in the organization’s management account. For more information, see Permissions required to access IAM resources in the IAM documentation.
-
Apply the service control policy (SCP)-based control with the identifier CT.CLOUDFORMATION.PR.1. This SCP must be activated to deploy proactive controls. For instructions, see Disallow management of resource types, modules, and hooks within the AWS CloudFormation registry.
- This pattern provides instructions for deploying this solution across AWS accounts, from a deployment account to the organization’s management account. For testing purposes, you can deploy this solution directly in the management account, but instructions for this configuration are not explicitly provided.
This section provides a high-level overview of this solution and the architecture established by the sample code. The following diagram shows controls deployed across the various accounts in the OU.
AWS Control Tower controls are categorized according to their behavior and their guidance.
There are three primary types of control behaviors:
-
Preventive controls are designed to prevent actions from occurring. These are implemented with service control policies (SCPs) in AWS Organizations. The status of a preventive control is either enforced or not enabled. Preventive controls are supported in all AWS Regions.
-
Detective controls are designed to detect specific events when they occur and log the action in CloudTrail. These are implemented with AWS Config rules. The status of a detective control is either clear, in violation, or not enabled. Detective controls apply only in those AWS Regions supported by AWS Control Tower.
-
Proactive controls scan resources that would be provisioned by AWS CloudFormation and check whether they are compliant with your company policies and objectives. Resources that are not compliant will not be provisioned. These are implemented with AWS CloudFormation hooks. The status of a proactive control is PASS, FAIL, or SKIP.
Control guidance refers to the recommended practice for how to apply each control to your OUs. AWS Control Tower provides three categories of guidance: mandatory, strongly recommended, and elective. The guidance of a control is independent of its behavior. For more information, see Control behavior and guidance.
-
AWS Cloud Development Kit (AWS CDK) is a software development framework that helps you define and provision AWS Cloud infrastructure in code. The AWS CDK Toolkit is the primary tool for interacting with your AWS CDK app.
-
AWS CloudFormation helps you set up AWS resources, provision them quickly and consistently, and manage them throughout their lifecycle across AWS accounts and Regions.
-
AWS Config provides a detailed view of the resources in your AWS account and how they’re configured. It helps you identify how resources are related to one another and how their configurations have changed over time.
-
AWS Control Tower helps you set up and govern an AWS multi-account environment, following prescriptive best practices.
-
AWS Organizations is an account management service that helps you consolidate multiple AWS accounts into an organization that you create and centrally manage.
-
cdk_nag is an open-source tool that uses a combination of rule packs to check AWS Cloud Development Kit (AWS CDK) applications for adherence to best practices.
-
npm is a software registry that runs in a Node.js environment and is used to share or borrow packages and manage deployment of private packages.
-
Python is a general-purpose computer programming language.
-
Adhere to the principle of least-privilege (IAM documentation). The sample IAM policy and trust policy provided in this pattern include the minimum permissions required, and the AWS CDK stacks created in the management account are restricted by these permissions.
-
Adhere to the Best practices for AWS Control Tower administrators (AWS Control Tower documentation).
-
Adhere to the Best practices for developing and deploying cloud infrastructure with the AWS CDK (AWS CDK documentation).
-
When bootstrapping the AWS CDK, customize the bootstrap template to define policies and the trusted accounts that should have the ability to read and write to any resource in the management account. For more information, see Customizing bootstrapping.
-
Use code analysis tools, such as cfn_nag, to scan the generated CloudFormation templates. The cfn-nag tool looks for patterns in CloudFormation templates that might indicate the infrastructure is not secure. You can also use cdk-nag to check your CloudFormation templates by using the cloudformation-include module.
Controls are categorized according to their behavior and their guidance.
To deploy this solution, you need
Name | Version |
---|---|
AWS Control Tower | >= 3.0 |
Python | >= 3.9 |
npm | >= 8.9.0 |
The cdk.json
file tells the CDK Toolkit how to execute the code.
The package.json
requires npm
to be already installed.
-
Create an IAM policy in the management account with the permissions defined in IAM policy in the Additional information section. For instructions, see Creating IAM policies in the IAM documentation. Make note of the Amazon Resource Name (ARN) of the policy. The following is an example ARN.
arn:aws:iam::<MANAGEMENT-ACCOUNT-ID>:policy/<POLICY-NAME>
-
Create an IAM role in the management account, attach the IAM permission policy that you created in the previous step, and attach the custom trust policy in Trust policy in the Additional information section. For instructions, see Creating a role using custom trust policies in the IAM documentation. The following is an example ARN for the new role.
arn:aws:iam:: MANAGEMENT-ACCOUNT-ID:role/ROLE-NAME
-
In the management account, assume a role that has permissions to bootstrap AWS CDK.
-
Enter the following command, replacing the following:
<MANAGEMENT-ACCOUNT-ID>
is the ID of the organization’s management account.<AWS-CONTROL-TOWER-REGION>
is the AWS Region where Control Tower is deployed. For a complete list of Region codes, see Regional endpoints in AWS General Reference.<DEPLOYMENT-ACCOUNT-ID>
is the ID of the deployment account.<DEPLOYMENT-ROLE-NAME>
is the name of the IAM role you are using the deployment account.<POLICY-NAME>
is the name of the policy you created in the management account.
$ npx cdk bootstrap aws://MANAGEMENT-ACCOUNT-ID/AWS-CONTROL-TOWER-REGION \ --trust arn:aws:iam::DEPLOYMENT-ACCOUNT-ID:role/DEPLOYMENT-ROLE-NAME \ --cloudformation-execution-policies arn:aws:iam::MANAGEMENT-ACCOUNT-ID:policy/POLICY-NAME
The following is an example of an updated constants.py file.
ACCOUNT_ID = 111122223333
AWS_CONTROL_TOWER_REGION = us-east-2
ROLE_ARN = "arn:aws:iam::111122223333:role/CT-Controls-Role"
GUARDRAILS_CONFIGURATION = [
{
"Enable-Control": {
"AWS-GR_ENCRYPTED_VOLUMES",
...
},
"OrganizationalUnitIds": ["ou-1111-11111111", "ou-2222-22222222"...],
},
{
"Enable-Control": {
"AWS-GR_SUBNET_AUTO_ASSIGN_PUBLIC_IP_DISABLED",
...
},
"OrganizationalUnitIds": ["ou-2222-22222222"...],
},
]
-
In the cloned repository, open the constants.py file.
-
In the
ACCOUNT_ID
parameter, enter the ID of your management account. -
In the
<AWS-CONTROL-TOWER-REGION>
parameter, enter AWS Region where AWS Control Tower is deployed. -
In the
ROLE_ARN
parameter, enter the ARN of the role you created in the management account. -
In the
GUARDRAILS_CONFIGURATION
section, in theEnable-Control
parameter, enter the control API identifiers. Enter the identifier in double quotation marks, and separate multiple identifiers with commas. Each control has a unique API identifier for each Region in which AWS Control Tower is available. To find the control identifier, do the following:- In Tables of control metadata, locate the control you want to enable.
- In the Control API identifiers, by Region column, locate the API identifier for the Region in which you are making the API call, such as
arn:aws:controltower:us-east-1::control/AWS-GR_ENCRYPTED_VOLUMES
. - Extract the control identifier from the Regional identifier, such as
AWS-GR_ENCRYPTED_VOLUMES
.
-
In the
GUARDRAILS_CONFIGURATION
section, in theOrganizationalUnitIds
parameter, enter the ID of the organizational unit where you want to enable the control, such asou-1111-11111111
. Enter the ID in double quotation marks, and separate multiple IDs with commas. For more information about how to retrieve OU IDs, see Viewing the details of an OU. -
Save and close the constants.py file. For an example of an updated constants.py file, see the Additional information section of this pattern.
-
In the deployment account, assume the IAM role that has permissions to deploy the AWS CDK stacks in the management account. For more information about assuming an IAM role in the AWS CLI, see Use an IAM role in the AWS CLI.
-
If you are using Linux or MacOS:
- Enter the following command to create a virtual environment.
$ python3 -m venv .venv
- After the virtual environment is created, enter the following command to activate it.
$ source .venv/bin/activate
- Enter the following command to create a virtual environment.
-
If you are using Windows:
- Enter the following command to activate a virtual environment.
% .venv\Scripts\activate.bat
- Enter the following command to activate a virtual environment.
-
After the virtual environment is activated, enter the following command to run the install_deps.sh script. This script installs the required dependencies.
$ ./scripts/install_deps.sh
-
Enter the following command to synthesize and deploy the CloudFormation stack.
$ npx cdk synth $ npx cdk deploy
npx cdk ls
list all stacks in the appnpx cdk synth
emits the synthesized CloudFormation templatenpx cdk deploy
deploy this stacknpx cdk destroy
destroy this stacknpx cdk diff
compare deployed stack with current statenpx cdk docs
open CDK documentation
The following sample policy allows the minimum actions required to enable or disable AWS Control Tower controls when deploying AWS CDK stacks from a deployment account to the management account.
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"controltower:EnableControl",
"controltower:DisableControl",
"controltower:GetControlOperation",
"controltower:ListEnabledControls",
"organizations:AttachPolicy",
"organizations:CreatePolicy",
"organizations:DeletePolicy",
"organizations:DescribeOrganization",
"organizations:DescribeOrganizationalUnit",
"organizations:DetachPolicy",
"organizations:ListAccounts",
"organizations:ListAWSServiceAccessForOrganization",
"organizations:ListChildren",
"organizations:ListOrganizationalUnitsForParent",
"organizations:ListParents",
"organizations:ListPoliciesForTarget",
"organizations:ListRoots",
"organizations:UpdatePolicy",
"ssm:GetParameters"
],
"Resource": "*"
}
]
}
The following custom trust policy allows a specific IAM role in the deployment account to assume the IAM role in the management account. Replace the following:
<DEPLOYMENT-ACCOUNT-ID>
is the ID of the deployment account<DEPLOYMENT-ROLE-NAME>
is the name of the role in the deployment account that is allowed to assume the role in the management account
{
“Version”: “2012-10-17”,
“Statement”: [
{
“Effect”: “Allow”,
“Principal”: {
“AWS”: “arn:aws:iam::<DEPLOYMENT-ACCOUNT-ID>:role/<DEPLOYMENT-ROLE-NAME>”
},
“Action”: “sts:AssumeRole”,
“Condition”: {}
}
]
}
Pattern created by Ivan Girardi (AWS) and Iker Reina Fuente (AWS).
See CONTRIBUTING for more information.
This library is licensed under the MIT-0 License. See the LICENSE file.