This content originally appeared on DEV Community and was authored by DevOps Fundamental
Terraform Control Tower: A Production-Grade Deep Dive
The relentless pressure to deliver cloud infrastructure faster, more reliably, and with stronger governance is a constant challenge. Many organizations find themselves wrestling with inconsistent configurations, security vulnerabilities, and a lack of centralized control as Terraform adoption scales. While Terraform excels at defining infrastructure, managing the platform on which that infrastructure runs – networking, security baselines, account structure – often requires significant custom effort. This is where Terraform Control Tower steps in, offering a standardized, automated approach to multi-account AWS environments. It’s not merely a Terraform provider; it’s a framework for building and enforcing a secure, compliant, and scalable cloud landing zone, integrated directly into your IaC pipelines.
What is “Control Tower” in Terraform context?
Terraform Control Tower isn’t a single Terraform provider in the traditional sense. Instead, it’s implemented through the hashicorp/aws
provider, leveraging AWS-native services orchestrated by Control Tower itself. You interact with Control Tower through Terraform resources that trigger Control Tower actions – creating organizations, enabling services, and deploying pre-configured infrastructure.
There isn’t a dedicated “controltower” provider. Instead, you’re primarily using resources like aws_organizations_organization
, aws_organizations_account
, aws_controltower_control
, and aws_controltower_enforcement_mode
. These resources interact with the Control Tower API to provision and manage the landing zone.
A key caveat is that Terraform doesn’t manage the Control Tower landing zone itself after initial setup. It provisions it. Subsequent changes to the landing zone’s core configuration are best managed through Control Tower’s console or CLI, while Terraform continues to manage resources within the accounts created by Control Tower. This separation of concerns is crucial.
Use Cases and When to Use
Control Tower with Terraform is invaluable in several scenarios:
- Multi-Account Strategy: Organizations adopting a well-defined multi-account strategy for isolation, security, and cost management. Terraform automates the creation and configuration of these accounts, ensuring consistency. This is a core need for SRE teams responsible for platform reliability.
- Centralized Governance: Enforcing organization-wide security policies, compliance standards (PCI DSS, HIPAA), and tagging conventions. Control Tower’s controls, deployed via Terraform, provide a baseline for all accounts. DevOps teams benefit from reduced friction in onboarding new projects.
- Automated Onboarding: Streamlining the onboarding process for new teams or projects. Terraform can automatically create accounts, configure networking, and deploy initial infrastructure based on pre-defined blueprints.
- Landing Zone as Code: Treating the entire landing zone as infrastructure code, enabling version control, auditability, and repeatable deployments. This is critical for infrastructure architects focused on long-term maintainability.
- Disaster Recovery & Account Replication: Quickly replicating the landing zone structure in a new AWS region for disaster recovery or expansion. Terraform’s declarative nature makes this process straightforward.
Key Terraform Resources
Here are eight essential Terraform resources for working with Control Tower:
-
aws_organizations_organization
: Creates and manages the AWS Organizations root.
resource "aws_organizations_organization" "example" {
aws_account_id = data.aws_caller_identity.current.account_id
email = "admin@example.com"
feature_set = "STANDARD"
}
-
aws_organizations_account
: Creates and manages AWS accounts within the organization.
resource "aws_organizations_account" "example" {
name = "Development"
email = "dev@example.com"
iam_role_arn = aws_iam_role.organization_account_access_role.arn
parent_account_id = aws_organizations_organization.example.aws_account_id
}
-
aws_controltower_control
: Enables Control Tower controls (e.g., core infrastructure, logging).
resource "aws_controltower_control" "core_infrastructure" {
control_arn = "arn:aws:controltower:us-east-1:012345678901:control/CoreInfrastructure"
}
-
aws_controltower_enforcement_mode
: Sets the enforcement mode for a Control Tower control (PERMISSIVE or ENFORCING).
resource "aws_controltower_enforcement_mode" "core_infrastructure" {
control_arn = aws_controltower_control.core_infrastructure.control_arn
enforcement_mode = "ENFORCING"
}
-
aws_iam_role
: Essential for creating roles with permissions for Control Tower to manage accounts.
resource "aws_iam_role" "organization_account_access_role" {
name = "OrganizationAccountAccessRole"
assume_role_policy = jsonencode({
Version = "2012-10-17",
Statement = [
{
Action = "sts:AssumeRole",
Principal = {
Service = "controltower.amazonaws.com"
},
Effect = "Allow",
Sid = ""
}
]
})
}
-
aws_iam_policy
: Defines IAM policies for roles used by Control Tower. -
aws_organizations_organizational_unit
: Creates organizational units (OUs) for hierarchical account management. -
data.aws_caller_identity
: Retrieves information about the current AWS account.
Dependencies are critical. aws_organizations_organization
must be created before aws_organizations_account
. Controls should be enabled after accounts are provisioned. Lifecycle rules should be used to prevent accidental deletion of the organization root.
Common Patterns & Modules
- Remote Backend: Always use a remote backend (S3, Terraform Cloud) for state locking and collaboration.
-
Dynamic Blocks: Utilize
dynamic
blocks to iterate over lists of accounts or controls, reducing code duplication. -
for_each
: Employfor_each
to create multiple accounts or OUs based on a map of configurations. - Monorepo: A monorepo structure is ideal for managing the landing zone and associated infrastructure.
- Layered Approach: Separate the landing zone configuration from the resources deployed within the accounts.
- Environment-Based Modules: Create modules for different environments (dev, staging, prod) with environment-specific configurations.
Public modules are emerging, but often require customization. Consider starting with the AWS Terraform examples and adapting them to your specific needs.
Hands-On Tutorial
This example creates a basic Control Tower landing zone with a single development account.
Provider Setup:
terraform {
required_providers {
aws = {
source = "hashicorp/aws"
version = "~> 5.0"
}
}
}
provider "aws" {
region = "us-east-1"
}
Resource Configuration:
resource "aws_organizations_organization" "example" {
aws_account_id = data.aws_caller_identity.current.account_id
email = "admin@example.com"
feature_set = "STANDARD"
}
resource "aws_organizations_account" "dev" {
name = "Development"
email = "dev@example.com"
iam_role_arn = aws_iam_role.organization_account_access_role.arn
parent_account_id = aws_organizations_organization.example.aws_account_id
}
resource "aws_iam_role" "organization_account_access_role" {
name = "OrganizationAccountAccessRole"
assume_role_policy = jsonencode({
Version = "2012-10-17",
Statement = [
{
Action = "sts:AssumeRole",
Principal = {
Service = "controltower.amazonaws.com"
},
Effect = "Allow",
Sid = ""
}
]
})
}
resource "aws_controltower_control" "core_infrastructure" {
control_arn = "arn:aws:controltower:us-east-1:012345678901:control/CoreInfrastructure" # Replace with your region's ARN
}
Apply & Destroy:
terraform init
, terraform plan
, terraform apply
. The terraform plan
output will show the resources being created. terraform destroy
will remove the landing zone (use with extreme caution!).
This example is a simplified starting point. A real-world implementation would include more accounts, OUs, and controls.
Enterprise Considerations
Large organizations leverage Terraform Cloud/Enterprise for state management, remote runs, and collaboration. Sentinel or Open Policy Agent (OPA) are used for policy-as-code, enforcing compliance rules before infrastructure is deployed. IAM design is paramount, utilizing least privilege principles and robust role-based access control (RBAC). State locking is essential to prevent concurrent modifications.
Costs are driven by Control Tower’s underlying services (CloudTrail, Config, etc.) and the resources deployed within the accounts. Scaling requires careful planning of account limits and networking capacity. Multi-region deployments necessitate replicating the landing zone structure in each region.
Security and Compliance
Enforce least privilege using aws_iam_policy
and aws_iam_role
. Implement RBAC to control access to resources. Utilize aws_controltower_enforcement_mode
to enforce policies.
resource "aws_iam_policy" "controltower_admin_policy" {
name = "ControlTowerAdminPolicy"
description = "Policy for Control Tower administrators"
policy = jsonencode({
Version = "2012-10-17",
Statement = [
{
Action = [
"controltower:*",
"organizations:*",
"iam:*"
],
Effect = "Allow",
Resources = "*"
}
]
})
}
Drift detection can be implemented using Terraform Cloud’s drift detection feature or by comparing the Terraform state with the actual infrastructure. Tagging policies should be enforced using Control Tower’s tagging controls. Auditability is provided by CloudTrail logs.
Integration with Other Services
Here’s how Control Tower integrates with other services:
- AWS Config: Enforces configuration rules.
- AWS CloudTrail: Logs API calls for auditing.
- AWS Security Hub: Aggregates security findings.
- AWS Organizations: Provides the foundation for multi-account management.
- AWS IAM: Manages access control.
graph LR
A[Terraform] --> B(Control Tower);
B --> C[AWS Config];
B --> D[AWS CloudTrail];
B --> E[AWS Security Hub];
B --> F[AWS Organizations];
B --> G[AWS IAM];
Module Design Best Practices
Abstract Control Tower functionality into reusable modules. Use input variables for customization (e.g., account names, email addresses, control ARNs). Define output variables for important attributes (e.g., account IDs). Utilize locals for internal calculations. Document the module thoroughly. Use a remote backend for state management.
CI/CD Automation
# .github/workflows/control-tower.yml
name: Control Tower Deployment
on:
push:
branches:
- main
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: hashicorp/setup-terraform@v2
- run: terraform fmt
- run: terraform validate
- run: terraform plan -out=tfplan
- run: terraform apply tfplan
Pitfalls & Troubleshooting
- Incorrect Control ARNs: Ensure the Control ARNs are correct for your region.
- IAM Permissions: Control Tower requires specific IAM permissions. Verify the roles have the necessary policies.
- Account Limits: AWS Organizations has account limits. Monitor these limits and request increases if necessary.
- State Corruption: Protect the Terraform state file. Use a remote backend and enable state locking.
- Control Tower Updates: Control Tower is constantly evolving. Stay up-to-date with the latest changes and update your Terraform code accordingly.
- Dependency Issues: Ensure resources are created in the correct order.
Pros and Cons
Pros:
- Automated landing zone provisioning.
- Centralized governance and security.
- Scalability and repeatability.
- Integration with AWS native services.
- Infrastructure as Code.
Cons:
- Limited customization options.
- Terraform doesn’t fully manage the landing zone after initial setup.
- Requires understanding of AWS Organizations and Control Tower.
- Potential for vendor lock-in.
Conclusion
Terraform Control Tower is a powerful tool for building and managing secure, compliant, and scalable AWS environments. It’s not a replacement for Terraform, but rather an extension that streamlines the provisioning of a well-governed cloud landing zone. Engineers should prioritize evaluating Control Tower modules, setting up a CI/CD pipeline for automated deployments, and integrating it into their existing IaC workflows. The strategic value lies in reducing operational overhead, improving security posture, and accelerating cloud adoption.
This content originally appeared on DEV Community and was authored by DevOps Fundamental