Deploy and manage AWS Control Tower controls by using AWS CDK and AWS CloudFormation - AWS Prescriptive Guidance

Deploy and manage AWS Control Tower controls by using AWS CDK and AWS CloudFormation

Created by Iker Reina Fuente (AWS) and Ivan Girardi (AWS)

Code repository: aws-control-tower-controls-cdk

Environment: Production

Technologies: Security, identity, compliance; CloudNative; Infrastructure; Management & governance

AWS services: AWS CloudFormation; AWS Control Tower; AWS Organizations; AWS CDK

Summary

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.

Target audience

This pattern is recommended for users who have experience with AWS Control Tower, CloudFormation, AWS CDK, and AWS Organizations.

Prerequisites and limitations

Prerequisites

Limitations

  • 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.

Product versions

  • Python version 3.9 or later

  • npm version 8.9.0 or later

Architecture

Target architecture

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.

Architecture diagram of controls deployed across all AWS accounts in the organizational unit

AWS Control Tower controls are categorized according to their behavior and their guidance.

There are three primary types of control behaviors:

  1. 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.

  2. 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.

  3. 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.

Tools

AWS services

  • 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.

Other tools

  • 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.

Code repository

The code for this pattern is available in the GitHub Deploy AWS Control Tower controls using AWS CDK repository. You use the cdk.json file to interact with the AWS CDK app, and you use the package.json file to install the npm packages.

Best practices

Epics

TaskDescriptionSkills required

Create the IAM role in the management account.

  1. 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>
  2. 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>
DevOps engineer, General AWS

Bootstrap AWS CDK.

  1. In the management account, assume a role that has permissions to bootstrap AWS CDK.

  2. 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>
DevOps engineer, General AWS, Python

Clone the repository.

In a bash shell, enter the following command. This clones the Deploy AWS Control Tower controls using AWS CDK repository from GitHub.

git clone https://github.com/aws-samples/aws-control-tower-controls-cdk.git
DevOps engineer, General AWS

Edit the AWS CDK configuration file.

  1. In the cloned repository, open the constants.py file.

  2. In the ACCOUNT_ID parameter, enter the ID of your management account.

  3. In the <AWS-CONTROL-TOWER-REGION> parameter, enter AWS Region where AWS Control Tower is deployed.

  4. In the ROLE_ARN parameter, enter the ARN of the role you created in the management account.

  5. In the GUARDRAILS_CONFIGURATION section, in the Enable-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:

    1. In Tables of control metadata, locate the control you want to enable.

    2. 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.

    3. Extract the control identifier from the Regional identifier, such as AWS-GR_ENCRYPTED_VOLUMES.

  6. In the GUARDRAILS_CONFIGURATION section, in the OrganizationalUnitIds parameter, enter the ID of the organizational unit where you want to enable the control, such as ou-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.

  7. Save and close the constants.py file. For an example of an updated constants.py file, see the Additional information section of this pattern.

TaskDescriptionSkills required

Assume the IAM role in the deployment account.

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.

DevOps engineer, General AWS

Activate the environment.

If you are using Linux or MacOS:

  1. Enter the following command to create a virtual environment.

    $ python3 -m venv .venv
  2. After the virtual environment is created, enter the following command to activate it.

    $ source .venv/bin/activate

If you are using Windows:

  1. Enter the following command to activate a virtual environment.

    % .venv\Scripts\activate.bat
DevOps engineer, General AWS

Install the dependencies.

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
DevOps engineer, General AWS, Python

Deploy the stack.

Enter the following commands to synthesize and deploy the CloudFormation stack.

$ npx cdk synth $ npx cdk deploy
DevOps engineer, General AWS, Python

Related resources

AWS documentation

Other resources

Additional information

Example constants.py file

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"...], }, ]

IAM policy

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": "*" } ] }

Trust policy

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”: {} } ] }