Skip to content

Prerequisites

  1. Clone the source demo repository
  2. Work from the demo repository root for all commands in this walkthrough
  1. Three AWS accountsnetwork, dev, and sandbox
  2. Both regions enabled on each account: ap-southeast-2 and ap-southeast-6

Why these two regions?

This walkthrough uses ap-southeast-2 and ap-southeast-6 as concrete examples — one established region plus a second for cross-region association
VPCs in ap-southeast-6 associate with a PHZ in ap-southeast-2 — Route 53 resolves shared records across regions from one zone.
. Any two regions work if you rename stacks, update CIDRs, and set vpc_region correctly in authorizations. Before you commit, check that Terraform and the AWS provider support your chosen regions and that services you rely on (VPC, Route 53, SSM endpoints, and so on) are available there — see Regional service gaps below for one example.

Configure one profile per account:

[profile r53demo-network]
sso_session = my-sso
sso_account_id = 111111111111
sso_role_name = AdministratorAccess
region = ap-southeast-2
[profile r53demo-dev]
sso_session = my-sso
sso_account_id = 222222222222
sso_role_name = AdministratorAccess
region = ap-southeast-2
[profile r53demo-sandbox]
sso_session = my-sso
sso_account_id = 333333333333
sso_role_name = AdministratorAccess
region = ap-southeast-2

Verify before each phase:

Terminal window
export AWS_PROFILE=r53demo-network # or dev / sandbox
aws sts get-caller-identity
RequirementValue
Terraform>= 1.5.0
AWS provider6.53.0 per stack (versions.tf) — required for ap-southeast-6

After cloning or pulling demo updates:

Terminal window
terraform -chdir=terraform/accounts/<stack> init -upgrade
VariableWhereWhen needed
dev_apse2_vpc_id, dev_apse6_vpc_id, sandbox_apse2_vpc_id, sandbox_apse6_vpc_idnetworkPhase 2a — from workload Phase 1 outputs
zone_idnetwork-apse6, all workload stacksPhase 2b / Phase 3 — from network Phase 2a output

Copy terraform.tfvars.exampleterraform.tfvars per stack after Phase 1 outputs are captured.

Default provider tags: Project=r53demo, Account=<network|dev|sandbox>, ManagedBy=terraform.

Route 53 hosted zones appear global in the console. VPC and EC2 are regional. Switching services may reset the region picker — if lists look empty, switch back to ap-southeast-2 or ap-southeast-6 before assuming deploy failed.

Test_EC2
One minimal EC2 per stack (seven total) for in-VPC DNS checks via SSM Session Manager and `dig`.
instances sit in private subnets with no public IP. Session Manager needs either:

PathRequirementsUsed in demo
VPC interface endpoints
Interface endpoints for `ssm`, `ssmmessages`, and `ec2messages` — required for Session Manager in private subnets.
All three SSM services in the same region as the instanceap-southeast-2 stacks (default)
Internet egressNAT gateway
Optional internet egress for private subnets on `*-apse6` stacks when full SSM shell access is needed.
(enable_nat_gateway=true)
Optional on *-apse6 stacks

Required SSM endpoint services when using VPC endpoints:

Service suffixRequired
ssmYes
ssmmessagesYes
ec2messagesYes

In ap-southeast-6, AWS has launched ssm and ssmmessages interface endpoints, but not ec2messages yet. *-apse6 stacks default to the two available services so terraform apply succeeds.

VariableDefault (*-apse2)Default (*-apse6)
enable_ssm_vpc_endpointstruetrue
ssm_vpc_endpoint_servicesall threessm, ssmmessages only

Confirm after apply:

Terminal window
terraform -chdir=terraform/accounts/dev-apse6 output ssm_vpc_endpoints_enabled
terraform -chdir=terraform/accounts/dev-apse6 output ssm_vpc_endpoint_services
# Expected today: true, ["ssm", "ssmmessages"]

Check whether ec2messages exists before adding it:

Terminal window
aws ec2 describe-vpc-endpoint-services \
--service-names com.amazonaws.ap-southeast-6.ec2messages \
--region ap-southeast-6 \
--query 'ServiceDetails[0].ServiceName' \
--output text

Until ec2messages exists as a VPC interface endpoint, interactive Session Manager from private subnets may need internet egress. Set enable_nat_gateway = true on network-apse6, dev-apse6, and sandbox-apse6 to enable a NAT gateway
Optional internet egress for private subnets on `*-apse6` stacks when full SSM shell access is needed.
.

Cost

Approximate NAT cost: ~USD 0.06/hour per gateway (~USD 1.40/day per stack). Disable NAT or destroy stacks during teardown to stop charges.

Never partial re-apply

Never re-apply with only -var="enable_nat_gateway=true" — that omits zone_id and Terraform may destroy the Route 53 VPC association. Always use -var-file=terraform.tfvars with full phase flags.

These are operational realities of the classic pattern in this demo — not bugs in Route 53 itself.

Regional service gaps
A region lacks a service for full verification — e.g. `ec2messages` may be unavailable in ap-southeast-6.
affect SSM, not DNS: VPC_Association
AssociateVPCWithHostedZone — workload account links its VPC to an authorized private hosted zone so the VPC resolver can query shared records.
and Route 53 resolution work regardless of SSM. SSM agents on *-apse6 instances may register with only ssm + ssmmessages endpoints. If start-session fails, use send-command, enable NAT, or verify with Step A in Verification.

Network_Account creates authorizations; Dev_Account and Sandbox_Account create associations — separate profiles, separate applies, fixed order.

Manual handoff of four workload vpc_id values into network, then zone_id into five downstream stacks. Stale IDs are the most common demo failure mode.

Route 53 blocks PHZ deletion while cross-account associations exist. Set feature flags to false on workload stacks before destroying network.

Pre-flight checks before your first apply.