Control Tower Landing Zone
This is a Terraform module that deploys the AWS Control Tower Landing Zone in the management account.
Usage
module "control_tower_landing_zone" {
source = "git::git@github.com:gruntwork-io/terraform-aws-control-tower//modules/landingzone/control-tower-landing-zone?ref=v0.7.6"
email_address_account_log_archiver = "log-archiver-email@example.com"
email_address_account_audit = "audit-email@example.com"
}
How to upgrade the landing zone
AWS releases updates to the Control Tower Landing Zone on a regular basis.
To upgrade Landing Zone to the latest version, you can simply update the landing_zone_version
input variable to the desired version.
Check the Configuration update management in AWS Control Tower documentation for more information.
How to enable Region deny control
The Region deny control
can't be enabled via the API/IaC. To enable it you need to follow the steps below:
- Open the AWS Control Tower console at https://console.aws.amazon.com/controltower/
- In the navigation pane, choose Settings.
- In the Region deny control section, choose Edit.
- Select the Enable region deny control check box.
- Choose Save.
How to import existing Landing Zones
If you are setting up the Landing Zone on a new installation no module is required. This section is for importing existing Landing Zones into infrastructure as code.
The goal of this section is to import the existing Landing Zone into Terraform so that it can be managed as code with no changes to the existing Landing Zone.
To achieve this you can use one of the following import methods:
- [RECOMANDED] Using the
import
blocks available in OpenTofu and Terraformimport {
to = module.<resource_type>.<resource_name>
id = "<resource_id>"
} - Import resources using the CLI
import
command available in OpenTofu and Terraformtofu import "module.<resource_type>.<resource_name>" "<resource_id>"
Regardless of the method you choose, you will need find the resources that need to be imported using the AWS Console or the AWS CLI.
In the following table you can find examples for all the resources that need to be imported:
Resource Target | How to find the Resource ID |
---|---|
module.<module_name>.aws_organizations_account.log_archive | aws organizations list-accounts --query "Accounts[?Name=='Logs'].Id" |
module.<module_name>.aws_organizations_account.audit | aws organizations list-accounts --query "Accounts[?Name=='Security'].Id" |
module.<module_name>.aws_iam_role.controltower_admin | In this case the ID is static AWSControlTowerAdmin |
module.<module_name>.aws_iam_role.controltower_execution | In this case the ID is static AWSControlTowerExecution (depending on the version this one may not exist) |
module.<module_name>.aws_iam_policy.controltower_admin_policy | aws iam list-policies --no-paginate --query "Policies[?PolicyName=='AWSControlTowerAdminPolicy'].Arn" |
module.<module_name>.aws_iam_role.cloudtrail | In this case the ID is static AWSControlTowerCloudTrailRole |
module.<module_name>.aws_iam_policy.cloudtrail_policy | aws iam list-policies --no-paginate --query "Policies[?PolicyName=='AWSControlTowerCloudTrailRolePolicy'].Arn" |
module.<module_name>.aws_iam_role.stackset | In this case the ID is static AWSControlTowerStackSetRole |
module.<module_name>.aws_iam_policy.stackset_policy | aws iam list-policies --no-paginate --query "Policies[?PolicyName=='AWSControlTowerStackSetRolePolicy'].Arn" |
module.<module_name>.aws_iam_role.config_aggregator | In this case the ID is static AWSControlTowerConfigAggregatorRoleForOrganizations |
module.<module_name>.aws_kms_key.controltower | aws kms list-aliases --no-paginate --query "Aliases[?AliasName=='alias/control_tower_key'].TargetKeyId" |
module.<module_name>.aws_kms_alias.controltower | In this case the ID is static alias/control_tower_key |
module.<module_name>.aws_controltower_landing_zone.zone | aws controltower list-landing-zones --no-paginate |
After you have found the resource IDs you can import the resources. The CLI commands assume a default configuration, if you have a different configuration you will need to adjust the commands accordingly.
The resources aws_iam_role_policy_attachment
are safe to be re-created.
We also recommend using the variable existing_key_arn
to use the KSM key. Especially if you have a dedicated policy attached to the key.
The goal of the import is to have a plan with no operations to be performed. If you see any operations to be performed, you should stop and investigate the issue before applying the plan.
Sample Usage
- Terraform
- Terragrunt
# ------------------------------------------------------------------------------------------------------
# DEPLOY GRUNTWORK'S CONTROL-TOWER-LANDING-ZONE MODULE
# ------------------------------------------------------------------------------------------------------
module "control_tower_landing_zone" {
source = "git::git@github.com:gruntwork-io/terraform-aws-control-tower.git//modules/landingzone/control-tower-landing-zone?ref=v0.8.1"
# ----------------------------------------------------------------------------------------------------
# REQUIRED VARIABLES
# ----------------------------------------------------------------------------------------------------
# The email address to use for the account to use for audit.
email_address_account_audit = <string>
# The email address to use for the account to use for centralized logging.
email_address_account_log_archiver = <string>
# ----------------------------------------------------------------------------------------------------
# OPTIONAL VARIABLES
# ----------------------------------------------------------------------------------------------------
# The number of days to retain log objects in the centralized access logging
# bucket.
access_logging_bucket_retention_days = 3650
# The name of the account to use for audit.
account_name_audit = "Security"
# The name of the account to use for centralized logging.
account_name_log_archiver = "Logs"
# The name of an additional organizational unit to create in AWS Control
# Tower.
additional_organizational_unit_name = "Pre-prod"
# The amount of time allowed for the create operation to take before being
# considered to have failed.
# https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/servicecatalog_provisioned_product#timeouts
create_operation_timeout = "60m"
# The amount of time allowed for the delete operation to take before being
# considered to have failed.
# https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/servicecatalog_provisioned_product#timeouts
delete_operation_timeout = "60m"
# Whether to enable access management in AWS Control Tower.
enable_access_management = true
# The ARN of an existing KMS key to use for AWS Control Tower.
existing_key_arn = ""
# The name of the foundational organizational unit to create in AWS Control
# Tower.
foundational_organizational_unit_name = "Security"
# A list of AWS regions to govern with AWS Control Tower. The region where you
# deploy the landing zone MUST always be included in this list.
governed_regions = ["us-east-1","us-west-2"]
# A list of IAM users or roles that should be granted administrative access to
# the KMS key.
kms_key_admins = []
# The alias to use for the KMS key used by AWS Control Tower.
kms_key_alias_name = "control_tower_key"
# A list of IAM users or roles that should be granted user access to the KMS
# key.
kms_key_users = []
# The version of the AWS Control Tower landing zone to deploy.
landing_zone_version = "3.3"
# The number of days to retain log objects in the centralized logging bucket.
logging_bucket_retention_days = 365
# Whether to provision the production organizational unit.
provision_prod_ou = false
# If you want to overwrite the auto discovery of the root OU, you can provide
# the ID here.
root_ou_id = ""
# A map of tags to apply to the AWS Control Tower landing zone.
tags = {}
# The amount of time allowed for the update operation to take before being
# considered to have failed.
# https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/servicecatalog_provisioned_product#timeouts
update_operation_timeout = "60m"
}
# ------------------------------------------------------------------------------------------------------
# DEPLOY GRUNTWORK'S CONTROL-TOWER-LANDING-ZONE MODULE
# ------------------------------------------------------------------------------------------------------
terraform {
source = "git::git@github.com:gruntwork-io/terraform-aws-control-tower.git//modules/landingzone/control-tower-landing-zone?ref=v0.8.1"
}
inputs = {
# ----------------------------------------------------------------------------------------------------
# REQUIRED VARIABLES
# ----------------------------------------------------------------------------------------------------
# The email address to use for the account to use for audit.
email_address_account_audit = <string>
# The email address to use for the account to use for centralized logging.
email_address_account_log_archiver = <string>
# ----------------------------------------------------------------------------------------------------
# OPTIONAL VARIABLES
# ----------------------------------------------------------------------------------------------------
# The number of days to retain log objects in the centralized access logging
# bucket.
access_logging_bucket_retention_days = 3650
# The name of the account to use for audit.
account_name_audit = "Security"
# The name of the account to use for centralized logging.
account_name_log_archiver = "Logs"
# The name of an additional organizational unit to create in AWS Control
# Tower.
additional_organizational_unit_name = "Pre-prod"
# The amount of time allowed for the create operation to take before being
# considered to have failed.
# https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/servicecatalog_provisioned_product#timeouts
create_operation_timeout = "60m"
# The amount of time allowed for the delete operation to take before being
# considered to have failed.
# https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/servicecatalog_provisioned_product#timeouts
delete_operation_timeout = "60m"
# Whether to enable access management in AWS Control Tower.
enable_access_management = true
# The ARN of an existing KMS key to use for AWS Control Tower.
existing_key_arn = ""
# The name of the foundational organizational unit to create in AWS Control
# Tower.
foundational_organizational_unit_name = "Security"
# A list of AWS regions to govern with AWS Control Tower. The region where you
# deploy the landing zone MUST always be included in this list.
governed_regions = ["us-east-1","us-west-2"]
# A list of IAM users or roles that should be granted administrative access to
# the KMS key.
kms_key_admins = []
# The alias to use for the KMS key used by AWS Control Tower.
kms_key_alias_name = "control_tower_key"
# A list of IAM users or roles that should be granted user access to the KMS
# key.
kms_key_users = []
# The version of the AWS Control Tower landing zone to deploy.
landing_zone_version = "3.3"
# The number of days to retain log objects in the centralized logging bucket.
logging_bucket_retention_days = 365
# Whether to provision the production organizational unit.
provision_prod_ou = false
# If you want to overwrite the auto discovery of the root OU, you can provide
# the ID here.
root_ou_id = ""
# A map of tags to apply to the AWS Control Tower landing zone.
tags = {}
# The amount of time allowed for the update operation to take before being
# considered to have failed.
# https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/servicecatalog_provisioned_product#timeouts
update_operation_timeout = "60m"
}
Reference
- Inputs
- Outputs
Required
The email address to use for the account to use for audit.
The email address to use for the account to use for centralized logging.
Optional
The number of days to retain log objects in the centralized access logging bucket.
3650
account_name_audit
stringThe name of the account to use for audit.
"Security"
The name of the account to use for centralized logging.
"Logs"
The name of an additional organizational unit to create in AWS Control Tower.
"Pre-prod"
create_operation_timeout
stringThe amount of time allowed for the create operation to take before being considered to have failed. https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/servicecatalog_provisioned_product#timeouts
"60m"
delete_operation_timeout
stringThe amount of time allowed for the delete operation to take before being considered to have failed. https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/servicecatalog_provisioned_product#timeouts
"60m"
Whether to enable access management in AWS Control Tower.
true
existing_key_arn
stringThe ARN of an existing KMS key to use for AWS Control Tower.
""
The name of the foundational organizational unit to create in AWS Control Tower.
"Security"
governed_regions
list(string)A list of AWS regions to govern with AWS Control Tower. The region where you deploy the landing zone MUST always be included in this list.
[
"us-east-1",
"us-west-2"
]
kms_key_admins
list(string)A list of IAM users or roles that should be granted administrative access to the KMS key.
[]
kms_key_alias_name
stringThe alias to use for the KMS key used by AWS Control Tower.
"control_tower_key"
kms_key_users
list(string)A list of IAM users or roles that should be granted user access to the KMS key.
[]
landing_zone_version
stringThe version of the AWS Control Tower landing zone to deploy.
"3.3"
The number of days to retain log objects in the centralized logging bucket.
365
Whether to provision the production organizational unit.
false
root_ou_id
stringIf you want to overwrite the auto discovery of the root OU, you can provide the ID here.
""
tags
map(string)A map of tags to apply to the AWS Control Tower landing zone.
{}
update_operation_timeout
stringThe amount of time allowed for the update operation to take before being considered to have failed. https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/servicecatalog_provisioned_product#timeouts
"60m"