AWS Control Tower Account Factory for Terraform provides a Terraform module that makes it easy to create and customize new accounts that comply with an organization’s security guidelines. AFT defines a pipeline for automated and consistent creation of AWS Control Tower accounts, giving you the benefits of Terraform’s workflow and Control Tower’s governance features. AWS maintains this module.
This article covers deployment, configuration, customization options, workflow components, state management, and teardown as described in the official tutorial and reference material.
Introduction
AWS Control Tower Account Factory for Terraform, commonly referenced as AFT, is a Terraform module designed to automate multi-account vending in an AWS Control Tower landing zone. Initially the multi-account vending system for AWS was called Landing Zones. Eventually Landing Zones got rebranded and restructured as AWS Control Tower. It is an opinionated way for provisioning AWS accounts with management tools like dashboards.
There are no public API endpoints for AWS Control Tower, so the only ways to automate provisioning are:
Manual provisioning - ClickOps
Customizations for AWS Control Tower - which uses CloudFormation
Target underlying AWS services that do have a Terraform provider or use a provider like idealo/controltower that does that for you
AWS Control Tower Account Factory for Terraform - AFT
Using AFT brings a GitOps driven workflow, HCLv2 usage, and is fully into both AWS and Terraform ecosystems with support. Security is built-in and aligned with Well-Architected Framework practices.
Prerequisites and Initial Setup
This tutorial assumes that you are familiar with the standard Terraform workflow. If you are new to Terraform, complete the Get Started tutorials first.
For this tutorial, you will need:
- Terraform v0.15+ installed locally configured with credentials for the non-root user with AdministratorAccess
- an AWS account, with credentials for a non-root user with the AdministratorAccess policy attached. Some steps can take up to 30 minutes, so make sure your credentials have a long enough duration
The tutorial guides you through the one-time steps required to deploy AFT to create the pipeline for account creation. Then, you will to use AFT to create and customize your Control Tower accounts. In this tutorial, you will deploy the AFT module, review the support account customization options, and learn about the components of AFT and its workflow.
Module Structure and File Layout
The reference configuration layout includes helper scripts and Terraform files for initial bootstrapping.
├── pre-api-helpers.sh
│ └── python
│ └── requirements.txt
└── terraform
├── aft-providers.jinja
└── backend.jinja
This configuration does not define any global customizations for your account.
AFT applies Account customizations to a specific account or set of accounts. It uses the customizations defined in the repository you pass to the accountcustomizationsrepo_name input variable.
Core AFT Module Declaration
A typical module block for AFT is declared in learn-terraform-aws-control-tower-aft/main.tf:
hcl
module "aft" {
source = "github.com/aws-ia/terraform-aws-control_tower_account_factory"
##...
vcs_provider = "github"
account_request_repo_name = "${var.github_username}/learn-terraform-aft-account-request"
account_provisioning_customizations_repo_name = "${var.github_username}/learn-terraform-aft-account-provisioning-customizations"
global_customizations_repo_name = "${var.github_username}/learn-terraform-aft-global-customizations"
account_customizations_repo_name = "${var.github_username}/learn-terraform-aft-account-customizations"
}
The value of that input variable must match a subdirectory of your account customizations repository.
Key Input Variables and Feature Flags
AFT exposes a set of input variables to control VPC creation, feature toggles, framework sourcing, and metrics.
VPC and Networking Variables
| Name | Description | Default |
|---|---|---|
| aftvpccidr | CIDR Block to allocate to the AFT VPC | 192.168.0.0/22 |
| aftvpcendpoints | Flag turning VPC endpoints on/off for AFT VPC | true |
| aftvpcprivatesubnet01_cidr | CIDR Block to allocate to the Private Subnet 01 | 192.168.0.0/24 |
| aftvpcprivatesubnet02_cidr | CIDR Block to allocate to the Private Subnet 02 | 192.168.1.0/24 |
| aftvpcpublicsubnet01_cidr | CIDR Block to allocate to the Public Subnet 01 | 192.168.2.0/25 |
| aftvpcpublicsubnet02_cidr | CIDR Block to allocate to the Public Subnet 02 | 192.168.3.0/25 |
Feature Flags
| Name | Description | Default |
|---|---|---|
| aftenablevpc | Flag turning use of VPC on/off for AFT | true |
| aftfeaturecloudtraildataevents | Feature flag toggling CloudTrail data events on/off | false |
| aftfeaturedeletedefaultvpcs_enabled | Feature flag toggling deletion of default VPCs on/off | false |
| aftfeatureenterprise_support | Feature flag toggling Enterprise Support enrollment on/off | false |
| aftmetricsreporting | Flag toggling reporting of operational metrics | true |
Framework Sourcing Variables
| Name | Description | Default |
|---|---|---|
| aftframeworkrepogitref | Git branch from which the AFT framework should be sourced from | null |
| aftframeworkrepo_url | Git repo URL where the AFT framework should be sourced from | https://github.com/aws-ia/terraform-aws-controltoweraccount_factory.git |
| aftmanagementaccount_id | AFT Management Account ID | n/a, required |
Dependency and Version Requirements
AFT has defined provider and module dependencies.
Provider Requirements
| Name | Version |
|---|---|
| terraform | >= 1.6.1, < 2.0.0 |
| aws | >= 6.0.0, < 7.0.0 |
Module Dependencies
| Name | Source | Version |
|---|---|---|
| aftaccountprovisioning_framework | ./modules/aft-account-provisioning-framework | n/a |
| aftaccountrequest_framework | ./modules/aft-account-request-framework | n/a |
| aft_backend | ./modules/aft-backend | n/a |
| aftcoderepositories | ./modules/aft-code-repositories | n/a |
| aft_customizations | ./modules/aft-customizations | n/a |
| aftfeatureoptions | ./modules/aft-feature-options | n/a |
| aftiamroles | ./modules/aft-iam-roles | n/a |
| aftlambdalayer | ./modules/aft-lambda-layer | n/a |
| aftssmparameters | ./modules/aft-ssm-parameters | n/a |
| packaging | ./modules/aft-archives | n/a |
Data Sources
| Name | Description | Type |
|---|---|---|
| aws_partition.current | data source | |
| awsservice.homeregion_validation | data source | |
| localfile.pythonversion | data source | |
| local_file.version | data source |
Account Customization Inputs
Account customizations are maintained outside AFT and re-applied after AFT updates.
| Name | Description | Type | Default | Required |
|---|---|---|---|---|
| accountcustomizationsrepo_branch | Branch to source account customizations repo from | string | main | no |
| accountcustomizationsrepo_name | Repository name for the account customizations files | string |
Note that this customization must be maintained outside of AFT and re-applied after AFT updates.
State Management and Security Considerations
This artifact describes the state of the resources that Terraform created. If you plan to update the AFT version, make sure to preseve the Terraform state file, or set up a Terraform backend using Amazon S3 and DynamoDB. The AFT module doesn't manage a backend Terraform state.
Note
You're responsible for protecting the Terraform state file. Some input variables might contain sensitive values, such as a private ssh key or Terraform token. Depending on your deployment method, these values can be viewable as plain text in the Terraform state file. For more information, see Sensitive data in State
Workflow and Customization Options
AFT applies Account customizations to a specific account or set of accounts. It uses the customizations defined in the repository you pass to the accountcustomizationsrepo_name input variable.
The tutorial covers deploying the AFT module, reviewing the support account customization options, and learning about the components of AFT and its workflow.
Support account customization options can be toggled via feature flags such as aftfeaturecloudtraildataevents, aftfeaturedeletedefaultvpcsenabled, and aftfeatureenterprisesupport.
Teardown and Cleanup
Cleanup involves removing pipelines, emptying buckets, decommissioning accounts, and destroying Terraform resources.
Select the pipeline, then click Delete pipeline and confirm the deletion.
Next, navigate to your learn-terraform-aws-control-tower-aft repository, which contains a remove_buckets.sh script to empty and delete buckets created in your log archive and AFT management accounts.
Run the script.
$ ./remove_buckets.sh
Next, decommission your sandbox-aft account from your Control Tower landing zone. This disassociates your account, but does not close it.
Log in to the AWS Console as your Control Tower management user, then navigate to your Provisioned Products in ServiceCatalog.
Select the Account Access Filter, then select your sandbox-aft account.
Under Actions, click Terminate. Then click Terminate provisioned product to confirm the termination. This will remove the account from Control Tower, and move it under the Root organization for your account.
Then, run terraform destroy to delete the AFT resources from your account.
Respond yes to the prompt to confirm the operation.
$ terraform destroy
Plan: 0 to add, 0 to change, 297 to destroy.
Changes to Outputs:
- aftmanagementaccountid = "365371481900" -> null
- auditaccountid = "187724155000" -> null
- ctmanagementaccountid = "447475458655" -> null
- logarchiveaccount_id = "866255933133" -> null
- region = "us-east-1" -> null
Do you really want to destroy all resources?
Terraform will destroy all your managed infrastructure, as shown above.
There is no undo
Conclusion
AWS Control Tower Account Factory for Terraform delivers a fully automated, GitOps driven account vending pipeline that integrates with AWS Control Tower governance. The module is maintained by AWS and provides a standard Terraform workflow for creating and customizing accounts while preserving compliance.
Deployment requires a non-root AWS user with AdministratorAccess and Terraform v0.15+ locally. Configuration is driven through input variables for VPC sizing, feature flags, framework sourcing, and account customization repositories. The module internally composes multiple sub-modules for account provisioning, account request, backend, code repositories, customizations, feature options, IAM roles, Lambda layer, SSM parameters, and packaging.
Operational best practices include preserving Terraform state, optionally moving state to S3 and DynamoDB backend, and protecting sensitive values stored in state. Cleanup follows a deliberate sequence of pipeline deletion, bucket removal via remove_buckets.sh, account decommissioning in Control Tower Service Catalog, and final terraform destroy.
When used as designed, AFT reduces manual ClickOps, enforces consistent security baselines, and aligns multi-account provisioning with the Well-Architected Framework.