Skip to content

Cross-account private hosted zones

A private hosted zone resolves only inside the VPCs associated with it. To associate a VPC that lives in a different account from the hosted zone, the two accounts perform a two-step handshake: the zone owner authorises the VPC, and the VPC owner creates the association.

The zone owner cannot associate somebody else’s VPC unilaterally, and the VPC owner cannot associate with somebody else’s zone unilaterally. Both steps are required.

  • Administrative access to both accounts
  • The VPC ID and Region from account B
  • The hosted zone ID from account A
  • The AWS CLI configured with a profile for each account
  • enableDnsSupport and enableDnsHostnames on the VPC in account B
Terminal window
aws route53 list-hosted-zones --profile account-a
aws route53 create-vpc-association-authorization \
--hosted-zone-id <HOSTED_ZONE_ID> \
--vpc VPCRegion=eu-west-2,VPCId=<VPC_ID> \
--profile account-a
Terminal window
aws route53 associate-vpc-with-hosted-zone \
--hosted-zone-id <HOSTED_ZONE_ID> \
--vpc VPCRegion=eu-west-2,VPCId=<VPC_ID> \
--profile account-b
Terminal window
aws route53 delete-vpc-association-authorization \
--hosted-zone-id <HOSTED_ZONE_ID> \
--vpc VPCRegion=eu-west-2,VPCId=<VPC_ID> \
--profile account-a

Deleting the authorization does not remove the association; it removes the standing permission to create one. Leaving authorizations in place is standing access to associate a VPC with your private zone, so clean them up.

There is no CloudFormation resource for the cross-account case. AWS::Route53::HostedZone accepts a VPCs property, but only for VPCs in the same account as the stack, and there is no CloudFormation resource type for the authorization at all.

Cross-account association is therefore CLI, SDK or CDK custom-resource territory. A CloudFormation-first estate usually wraps the two API calls in a Lambda-backed custom resource, or runs them from the pipeline that creates the VPC.

In account A, the principal that authorises:

{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"route53:CreateVPCAssociationAuthorization",
"route53:DeleteVPCAssociationAuthorization",
"route53:ListVPCAssociationAuthorizations"
],
"Resource": "arn:aws:route53:::hostedzone/*"
}
]
}

In account B, the principal that associates needs route53:AssociateVPCWithHostedZone on the hosted zone, and ec2:DescribeVpcs in its own account.

Terminal window
# From an EC2 instance in the VPC in account B
nslookup db.example.internal
dig db.example.internal
# From account A, confirm the VPC now appears on the zone
aws route53 get-hosted-zone --id <HOSTED_ZONE_ID> --profile account-a
  • 300 VPCs can be associated with a single private hosted zone. Beyond that, use Route 53 Profiles, which associate up to 1,000 VPCs with a Profile and up to 5,000 private hosted zones with that Profile — and share it across the organization with AWS Resource Access Manager.
  • 1,000 outstanding VPC association authorizations per hosted zone.
  • A VPC can be associated with any number of private hosted zones.

Route 53 Profiles is also the better answer well before the 300 limit if the same set of zones has to be attached to every new VPC — it turns a per-VPC operation into a one-time association.

SymptomLook at
Resolution fails from the VPCenableDnsSupport and enableDnsHostnames on the VPC; the DHCP options set pointing at AmazonProvidedDNS
AssociateVPCWithHostedZone is refusedThe authorization was not created, or was created for a different Region or VPC ID
Association succeeds but names do not resolveAnother private hosted zone for an overlapping name is associated with the same VPC; the most specific zone wins
Resolution works from some subnets onlyThe failing instances bypass the Amazon resolver (a custom DNS setting or /etc/resolv.conf on the instance), or those subnets belong to a VPC that is not associated with the hosted zone