How to govern your Multi-Region and Multi-account AWS Organization with Terraform
AWS Control Tower Account Factory for Terraform
Multi Account AWS Organization is easy
Having tens or hundreds of AWS Accounts in your AWS Organization is nothing unexpected. AWS tools are ready for that. For example, AWS GuardDuty gives you a hint to enable GuardDuty for your Organization in current region, see image below.
but what if you use more than 1 region?
Multi Region AWS Organization is hard
Having tens or thousands AWS accounts that uses 10 or 20 AWS Regions sounds like a nightmare for every security / cloud governance person. If you would like to enable AWS GuardDuty in every AWS Account in every region, then you would have to do this:
log in to AWS Account who has permission to manage GuardDuty in your Organization
for every region enable GuardDuty manually…
Yes, you could use CloudFormation which has quite good support of multi-region configuration via CloudFormation Stack Set. But what if you are not familiar with CloudFormation and you work with Terraform only?
AWS Control Tower Account Factory for Terraform
Two years ago AWS introduced solution called AWS Control Tower Account Factory for Terraform which is often called AFT.
Firstly, with AFT you can create a new AWS account from Terraform. But that’s not the most important part…AFT gives you ability to define Terraform that is executed against your newly created AWS Account. It has two types of TF sections
Global Terraform customization
applied to all newly created account without exception
Account Terraform customization
a TF template for your account…
you can define different TF code for different AWS Accounts types…
imagine having accounts for your engineering, local IT, sandboxes, customer deployments…all of them requires a different set of rules and controls obviously…
AFT is one of the best solution for managing AWS accounts I’ve seen in recent years!
AFT is amazing, but…
The multi-region support in AFT is not my cup of tea….It provides you multi-region support via terraform providers.
I decided to make my life easier and replace Terraform by Terragrunt. Terragrunt is a wrapper on top of Terraform.
Thanks to this, my terraform code is more clean. My TF structure is following:
modules contains TF code for specific AWS services, like a AWS Security Hub, VPC, etc.
then I define folders for each region where I can say which modules will be used in that region
Each region-folder consist of file region.hcl with variable aws_region saying which region this TF code should be applied to (see code below)
# file region.hcl content
#
locals {
aws_region = "ap-southeast-2"
}
Also, each region-folder includes a folder in which I define link to the TF source code from modules folder
# content of file /regions/ap-southeast-2/security-hub/terragrunt.hcl
#
terraform {
source = "../../../modules/security-hub"
}
The whole folder structure looks following:
.
├── modules
│ ├── security-hub
│ │ ├── cis.tf
│ │ ├── main.tf
│ │ └── variables.tf
├── regions
│ ├── ap-southeast-2
│ │ ├── region.hcl
│ │ ├── security-hub
│ │ │ └── terragrunt.hcl
│ ├── ca-central-1
│ │ ├── region.hcl
│ │ ├── security-hub
│ │ │ └── terragrunt.hcl
└── terragrunt.hcl
My solution is not the best one, but it help me to separate TF code definition from definition of regions.
Unfortunately, AFT does not support Terragrunt by default….So I had to touch the AFT code itself…I changed definition of AWS CodePipeline for Account Customization aft-account-customization-terraform.yml.
https://github.com/aws-ia/terraform-aws-control_tower_account_factory/blob/main/modules/aft-customizations/buildspecs/aft-account-customizations-terraform.yml#L104
# I changed file aft-account-customizations-terraform.yml at line 104 and put there following code to install Terragrunt
echo "installing Terragrunt"
LATEST_URL=$(curl -sL https://api.github.com/repos/gruntwork-io/terragrunt/releases | jq -r '.[0].assets[].browser_download_url' | egrep 'linux.*amd64' | tail -1)
curl -L ${LATEST_URL} > /usr/bin/terragrunt
chmod +x /usr/bin/terragrunt
terragrunt -v
And last step is to replace terraform apply by terragrunt apply in the same file…
and that’s it!
Hi Martin,
Where do you change this aft-account-customizations-terraform.yml? I see that's a repo in the aws-ia org, how do you apply those changes in your environment?