Note: Updated in August 2020 with new prechecks to the account enrollment script.

Since the launch of AWS Control Tower, customers have been asking for the ability to deploy AWS Control Tower in their existing AWS Organizations and to extend governance to those accounts in their organization.

We are happy to announce that you can now deploy AWS Control Tower in your existing AWS Organizations. The accounts that you launched before deploying AWS Control Tower, what we refer to as unenrolled accounts, remain outside AWS Control Towers’ governance by default. These accounts must be enrolled in the AWS Control Tower explicitly.

When you enroll an account into AWS Control Tower, it deploys baselines and additional guardrails to enable continuous governance on your existing AWS accounts. However, you must perform proper due diligence before enrolling in an account. Refer to the Things to Consider section below for additional information.

In this blog, I show you how to enroll your existing AWS accounts and accounts within the unregistered OUs in your AWS organization under AWS Control Tower programmatically.

Background

Here’s a quick review of some terms used in this post:

The Python script provided in this post. This script interacts with multiple AWS services, to identify, validate, and enroll the existing unmanaged accounts into AWS Control Tower.

An unregistered organizational unit (OU) is created through AWS Organizations. AWS Control Tower does not manage this OU.

An unenrolled account is an existing AWS account that was created outside of AWS Control Tower. It is not managed by AWS Control Tower.

A registered organizational unit (OU) is an OU that was created in the AWS Control Tower service. It is managed by AWS Control Tower.

When an OU is registered with AWS Control Tower, it means that specific baselines and guardrails are applied to that OU and all of its accounts.

An AWS Account Factory account is an AWS account provisioned using account factory in AWS Control Tower.

Amazon Elastic Compute Cloud (Amazon EC2) is a web service that provides secure, resizable compute capacity in the cloud.

AWS Service Catalog allows you to centrally manage commonly deployed IT services. In the context of this blog, account factory uses AWS Service Catalog to provision new AWS accounts.

AWS Organizations helps you centrally govern your environment as you grow and scale your workloads on AWS.

AWS Single Sign-On (SSO) makes it easy to centrally manage access to multiple AWS accounts. It also provides users with single sign-on access to all their assigned accounts from one place.

Things to Consider

Enrolling an existing AWS account into AWS Control Tower involves moving an unenrolled account into a registered OU. The Python script provided in this blog allows you to enroll your existing AWS accounts into AWS Control Tower. However, it doesn’t have much context around what resources are running on these accounts. It assumes that you validated the account services before running this script to enroll the account.

Some guidelines to check before you decide to enroll the accounts into AWS Control Tower.

An AWSControlTowerExecution role must be created in each account. If you are using the script provided in this solution, it creates the role automatically for you. If AWS Config was ever enabled on the account you enroll, a default config recorder and delivery channel were created. Delete the configuration-recorder and delivery channel for the account enrollment to work. The script provided in the solution helps you in identifying these conflicting resources. Start with enrolling the dev/staging accounts to get a better understanding of any dependencies or impact of enrolling the accounts in your environment. Create a new Organizational Unit in AWS Control Tower and do not enable any additional guardrails until you enroll in the accounts. You can then enable guardrails one by one to check the impact of the guardrails in your environment. As an additional option, you can apply AWS Control Tower’s detective guardrails to an existing AWS account before moving them under AWS Control Tower governance. Instructions to apply the guardrails are discussed in detail in AWS Control Tower Detective Guardrails as an AWS Config Conformance Pack blog.

Prerequisites

Before you enroll your existing AWS account in to AWS Control Tower, check the prerequisites from AWS Control Tower documentation.

This Python script provided part of this blog, supports enrolling all accounts with in an unregistered OU in to AWS Control Tower. The script also supports enrolling a single account using both email address or account-id of an unenrolled account. Following are a few additional points to be aware of about this solution.

Enable trust access with AWS Organizations for AWS CloudFormation StackSets .

. The email address associated with the AWS account is used as AWS SSO user name with default First Name Admin and Last Name User .

and Last Name . Accounts that are in the root of the AWS Organizations can be enrolled one at a time only.

While enrolling an entire OU using this script, the AWSControlTowerExecution role is automatically created on all the accounts on this OU.

role is automatically created on all the accounts on this OU. You can enroll a single account with in an unregistered OU using the script. It checks for AWSControlTowerExecution role on the account. If the role doesn’t exist, the role is created on all accounts within the OU.

role on the account. If the role doesn’t exist, the role is created on all accounts within the OU. By default, you are not allowed to enroll an account that is in the root of the organization. You must pass an additional flag to launch a role creation stack set across the organization.

While enrolling a single account that is in the root of the organization, it prompts for additional flag to launch role creation stack set across the organization.

The script uses CloudFormation Stack Set Service-Managed Permissions to create the AWSControlTowerExecution role in the unenrolled accounts.

How it works

The following diagram shows the overview of the solution.

In your AWS Control Tower environment, access an Amazon EC2 instance running in the master account of the AWS Control Tower home Region. Get temporary credentials for AWSAdministratorAccess from AWS SSO login screen Download and execute the enroll_script.py script The script creates the AWSControlTowerExecution role on the target account using Automatic Deployments for a Stack Set feature. On successful validation of role and organizational units that are given as input, the script launches a new product in Account Factory. The enrollment process creates an AWS SSO user using the same email address as the AWS account.

Setting up the environment

It takes up to 30 minutes to enroll each AWS account in to AWS Control Tower. The accounts can be enrolled only one at a time. Depending on number of accounts that you are migrating, you must keep the session open long enough. In this section, you see one way of keeping these long running jobs uninterrupted using Amazon EC2 using the screen tool.

Optionally you may use your own compute environment where the session timeouts can be handled. If you go with your own environment, make sure you have python3 , screen and a latest version of boto3 installed.

1. Prepare your compute environment:

Log in to your AWS Control Tower with AWSAdministratorAccess role.

Switch to the Region where you deployed your AWS Control Tower if needed.

If necessary, launch a VPC using the stack here and wait for the stack to COMPLETE.

If necessary, launch an Amazon EC2 instance using the stack here. Wait for the stack to COMPLETE.

While you are on master account, increase the session time duration for AWS SSO as needed. Default is 1 hour and maximum is 12 hours.

2. Connect to the compute environment (one-way):

Go to the EC2 Dashboard, and choose Running Instances .

. Select the EC2 instance that you just created and choose Connect .

. In Connect to your instance screen, under Connection method , choose EC2InstanceConnect (browser-based SSH connection) and Connect to open a session.

screen, under , choose and to open a session. Go to AWS Single Sign-On page in your browser. Click on your master account.

Choose command line or programmatic access next to AWSAdministratorAccess .

next to . From Option 1 copy the environment variables and paste them in to your EC2 terminal screen in step 5 below.

3. Install required packages and variables. You may skip this step, if you used the stack provided in step-1 to launch a new EC2 instance:

Install python3 and boto3 on your EC2 instance. You may have to update boto3, if you use your own environment.

$ sudo yum install python3 -y $ sudo pip3 install boto3 $ pip3 show boto3 Name: boto3 Version: 1.12.39

Change to home directory and download the enroll_account.py script.

$ cd ~ $ wget https://raw.githubusercontent.com/aws-samples/aws-control-tower-reference-architectures/master/customizations/AccountFactory/EnrollAccount/enroll_account.py

Set up your home Region on your EC2 terminal.

export AWS_DEFAULT_REGION=<AWSControlTower-Home-Region>

4. Start a screen session in daemon mode. If your session gets timed out, you can open a new session and attach back to the screen.

$ screen -dmS SAM $ screen -ls There is a screen on: 585.SAM (Detached) 1 Socket in /var/run/screen/S-ssm-user. $ screen -dr 585.SAM

5. On the screen terminal, paste the environmental variable that you noted down in step 2.

6. Identify the accounts or the unregistered OUs to migrate and run the Python script provide with below mentioned options.

Python script usage:

usage: enroll_account.py -o -u|-e|-i [-c|-V] Enroll existing accounts to AWS Control Tower. optional arguments: -h, --help show this help message and exit -o OU, --ou OU Target Registered OU -u UNOU, --unou UNOU Origin UnRegistered OU -e EMAIL, --email EMAIL AWS account email address to enroll in to AWS Control Tower -i AID, --aid AID AWS account ID to enroll in to AWS Control Tower -c, --create_role Create Roles on Root Level -V, --verify_only Pre-checks only. No account enrollment initiated

Use attribute -V to identify any conflicting resources before enrolling the accounts.

$ python3 enroll_account.py -o MigrateToRegisteredOU -u FromUnregisteredOU -V Executing on AWS Account: 888888888888, USER+SCADMINT1@amazon.com 777788889999 us-west-2: Config Recorder exist. Need to be DELETED. 777788889999 us-west-2: Delivery Channel exist. Need to be DELETED. 111122223333 AWSControlTowerExecution Role does not exist. This script will create the role 111122223333 us-west-2: Config Recorder exist. Need to be DELETED. 111122223333 us-west-2: Delivery Channel exist. Need to be DELETED.

Note: You could follow the steps from Failure Error that Mentions AWS Config to delete above conflicting resources before proceeding.

Enroll all the accounts from an unregistered OU to a registered OU Update : In any pre-checks fail, script will stop execution and list out the possible issues to fix.



$ python3 enroll_account.py -o MigrateToRegisteredOU -u FromUnregisteredOU Creating cross-account role on 111122223333, wait 30 sec: RUNNING Executing on AWS Account: 888888888888, USER+SCADMINT1@amazon.com PRECHECK SUCCEEDED. Proceeding Launching Enroll-Account-vinjak-unmgd3 Status: UNDER_CHANGE. Waiting for 6.0 min to check back the Status Status: UNDER_CHANGE. Waiting for 5.0 min to check back the Status . . Status: UNDER_CHANGE. Waiting for 1.0 min to check back the Status SUCCESS: 111122223333 updated Launching Enroll-Account-vinjakSCchild Status: UNDER_CHANGE. Waiting for 6.0 min to check back the Status ERROR: 444455556666 Launching Enroll-Account-Vinjak-Unmgd2 Status: UNDER_CHANGE. Waiting for 6.0 min to check back the Status . . Status: UNDER_CHANGE. Waiting for 1.0 min to check back the Status SUCCESS: 777788889999 updated

Use AWS account ID to enroll a single account that is part of an unregistered OU.

$ python3 enroll_account.py -o MigrateToRegisteredOU -i 111122223333

Use AWS account email address to enroll a single account from an unregistered OU.

$ python3 enroll_account.py -o MigrateToRegisteredOU -e JohnDoe+outside-ct-ou@amazon.com

You are not allowed by default to enroll an AWS account that is in the root of the organization. The script checks for the AWSControlTowerExecution role in the account. If role doesn’t exist, you are prompted to use -c | --create-role . Using -c flag adds the stack instance to the parent organization root. Which means an AWSControlTowerExecution role is created in all the accounts with in the organization.

Note: Ensure installing AWSControlTowerExecution role in all your accounts in the organization, is acceptable in your organization before using -c flag.

If you are unsure about this, follow the instructions in the documentation and create the AWSControlTowerExecution role manually in each account you want to migrate. Rerun the script.

Use AWS account ID to enroll a single account that is in root OU (need -c flag).

$ python3 enroll_account.py -o MigrateToRegisteredOU -i 111122223333 -c

Use AWS account email address to enroll a single account that is in root OU (need -c flag).

$ python3 enroll_account.py -o MigrateToRegisteredOU -e JohnDoe+in-the-root@amazon.com -c

Cleanup steps

On successful completion of enrolling all the accounts into your AWS Control Tower environment, you could clean up the below resources used for this solution.

If you have used templates provided in this blog to launch VPC and EC2 instance, delete the EC2 CloudFormation stack and then VPC template.

Conclusion

Now you can deploy AWS Control Tower in an existing AWS Organization. In this post, I have shown you how to enroll your existing AWS accounts in your AWS Organization into AWS Control Tower environment. By using the procedure in this post, you can programmatically enroll a single account or all the accounts within an organizational unit into an AWS Control Tower environment.

Now that governance has been extended to these accounts, you can also provision new AWS accounts in just a few clicks and have your accounts conform to your company-wide policies.

Additionally, you can use Customizations for AWS Control Tower to apply custom templates and policies to your accounts. With custom templates, you can deploy new resources or apply additional custom policies to the existing and new accounts. This solution integrates with AWS Control Tower lifecycle events to ensure that resource deployments stay in sync with your landing zone. For example, when a new account is created using the AWS Control Tower account factory, the solution ensures that all resources attached to the account’s OUs are automatically deployed.