1. Account model
Accounts are the strongest isolation boundary in AWS. Typical structure:
Root
├── Security OU ── Log Archive, Audit (created by Control Tower)
├── Infrastructure OU ── Network (Transit Gateway, egress), Shared Services
├── Workloads OU
│ ├── Prod OU ── payments-prod, crm-prod
│ └── NonProd OU ── payments-dev, payments-test
├── Sandbox OU
└── Suspended OU
One account per workload per environment keeps blast radius, quotas and bills separate.
2. Set up Control Tower
In the management account: choose the home region, governed regions (for example ap-south-1 and ap-south-2 for DR), and let Control Tower create the Log Archive and Audit accounts, the organisation CloudTrail and AWS Config.
Keep the management account for billing and organisation administration only. No workloads there.
3. Controls (guardrails)
| Kind | Example | Mechanism |
|---|---|---|
| Preventive | Deny leaving the organisation; deny disabling CloudTrail; region deny | SCPs |
| Detective | S3 buckets with public read; unencrypted EBS volumes; root user MFA | AWS Config rules |
| Proactive | Block CloudFormation stacks that create non-compliant resources | CloudFormation hooks |
Region deny SCP example (exclude global services):
{
"Effect": "Deny",
"NotAction": ["iam:*", "organizations:*", "sts:*", "support:*", "route53:*", "cloudfront:*", "budgets:*", "ce:*", "health:*"],
"Resource": "*",
"Condition": { "StringNotEquals": { "aws:RequestedRegion": ["ap-south-1", "ap-south-2"] } }
}
Warning
Test SCPs in a sandbox OU first. A wrong region SCP can break cross-region DR replication or global services you depend on.
4. Account vending
Use Account Factory (console/Service Catalog) or Account Factory for Terraform (AFT). A new account should arrive with: baseline VPC (or none, if networks are shared via RAM), IAM Identity Center permission sets, budget, security services enrolled, and tags.
5. Check drift
aws controltower list-enabled-controls --target-identifier arn:aws:organizations::111122223333:ou/o-abc/ou-xyz
aws organizations list-accounts-for-parent --parent-id ou-xyz --query "Accounts[].{Name:Name,Id:Id,Status:Status}" --output table
Control Tower shows drift when someone changes managed resources (for example, moves an account between OUs outside Control Tower). Repair through the console.
Foundation checklist
- Root user of every account: MFA, no access keys, contact details correct
- IAM Identity Center for human access (see the identity post)
- Organisation CloudTrail + Config in all governed regions
- GuardDuty, Security Hub delegated to the Audit account
- Network account with Transit Gateway
- Budgets and cost allocation tags activated