1 CHECKOUT · 8 NAMES · 16 DNS QUERIES · 4 IN NO LOG YOU OWN

AWS Route 53:
how one checkout resolves eight names

DNS turns a name like shop.example into the address a connection needs. Route 53 is AWS’s DNS service: it holds your records, picks which answer each asker gets, and runs the DNS server inside every private network you build.

WHAT THIS TUTORIAL COUNTS

A customer pays at an online shop. For that one checkout, a phone, an app server and a warehouse system look up eight names. Each DNS question one machine sends another is one query.

queries one checkout causes16
  • the VPC resolver6 queries
    the DNS server AWS builds into every private network; the shop’s own servers ask it
  • Route 53 name servers4 queries
    four public servers that hold the shop’s records and answer the rest of the internet
  • the customer’s resolver3 queries
    the DNS server a phone asks first, run by the customer’s network provider
  • the data centre’s DNS servers2 queries
    hold the names of systems the shop still runs outside AWS
  • the .example registry1 query
    says which four name servers hold shop.example
AND WHEN AN ANSWER IS WRONG
  • queries in no log you own4 of 16
    answered by servers the shop doesn’t run, so nothing the shop keeps records them
shop.example · us-east-1 and us-west-2 · November 2026

This tutorial follows one checkout at an online shop, and an outage four minutes later. To pay, the customer’s phone has to find the shop’s website and its API. To take the payment, the shop’s server has to find its database, a secrets store, a storage bucket, a payment provider and a warehouse system in the shop’s own data centre, which then has to find its way back. That is eight names. Every DNS question one machine sends another counts as one , and there are 16. Each chapter says who answers, how that answer was chosen, and which log, if any, would show a wrong one. The shop is the one from the AWS VPC tutorial, one release later.

You need to know what an IP address and a cache are; no DNS or AWS networking experience is assumed. The scenes play themselves, so watch or just scroll. are tappable. Names ending in .example are reserved for documentation and don’t exist on the real internet. Every number is November 2026. Each chapter’s deep dive ends with the scenario cues used by the AWS DevOps Engineer Professional (DOP-C02), Solutions Architect Professional (SAP-C03) and Security Specialty (SCS-C03) exams.

Four name servers the whole internet is told to ask

The shop owns a domain name, shop.example, and a customer’s phone has never heard of it. Before the phone can connect to anything, some server has to hold the shop’s DNS records, and the rest of the internet has to be told which server that is. Route 53 holds the records in a hosted zone, served by four name servers. This chapter follows the phone’s first lookup, at 14:01:30. The query count goes from 0 to 3.

STEP 01 / 06

A ZONE IS BORN WITH TWO RECORDS

shop.example · public zone
zone ID Z0SHOP1EXAMPLE · 2 records, both written by Route 53
recordvalue
shop.exampleNS · 172,800 sns-2048.awsdns-64.comns-2049.awsdns-65.netns-2050.awsdns-66.orgns-2051.awsdns-67.co.uk
shop.exampleSOA · 900 sns-2048.awsdns-64.comtimers: refresh 7,200 s · retry 900 s · expire 1,209,600 s · minimum 86,400 s
your records go herenone yet
the 4 name servers sit under 4 top-level domains: .com, .net, .org and .co.uk
Fig 0.1The two accent rows are the records Route 53 wrote itself: NS names the four servers, SOA holds the zone’s timers.

A is Route 53’s container for one domain’s records. Each record has a name, a value, and a type that says what the value is: an A record holds an IPv4 address, an NS record holds server names. Creating a zone for shop.example writes two records you never asked for.

The NS record lists four , the servers that hold the zone’s records and answer from them. The SOA record holds the zone’s timers. The four servers sit under four different top-level domains, .com, .net, .org and .co.uk, so trouble in one top-level domain leaves the other three names reachable.

A zone costs $0.50 a month. An account holds 500 zones and a zone holds 10,000 records before quotas or extra fees apply.

ONE CALL RETURNS THE ZONE AND ITS FOUR NAME SERVERS
# One call creates the zone and assigns its four name servers.
aws route53 create-hosted-zone \
  --name shop.example \
  --caller-reference 2026-11-13-shop

# From the response:
#   "Id": "/hostedzone/Z0SHOP1EXAMPLE",
#   "DelegationSet": { "NameServers": [
#       "ns-2048.awsdns-64.com",
#       "ns-2049.awsdns-65.net",
#       "ns-2050.awsdns-66.org",
#       "ns-2051.awsdns-67.co.uk" ] }
# The zone already holds 2 records: NS and SOA.
STEP 02 / 06

THE REGISTRY HOLDS THE ONLY POINTER

  1. customer’s phone203.0.113.50
  2. query #1 ↓
  3. customer’s resolver192.0.2.53
  4. query #2 ↓ · referral ↑
  5. .example registrylists who holds each domain
query #1 · the phone asks its resolver
the registry holds no address for shop.example, only the names of the 4 servers that do
QUESTIONquery #2
shop.exampletype A
asked by the customer’s resolver · asked of the .example registry
ANSWER
a referral: no address, ask one of these
  • NSns-2048.awsdns-64.com
  • NSns-2049.awsdns-65.net
  • NSns-2050.awsdns-66.org
  • NSns-2051.awsdns-67.co.uk
Fig 0.2Follow query #2: the registry answers with four server names, not an address. The accent names must match the zone’s NS record.

At 14:01:30 the customer’s phone asks its at 192.0.2.53 for shop.example. That is query #1. A resolver is a server whose job is to find answers by asking other servers. This one has nothing cached for the shop, so it asks the .example registry, which is query #2. The registry returns a referral: no address, only the names of the four name servers to ask next.

Those four names are in the registry because the shop gave them to its registrar, the company a domain is bought through. That hand-off is . Resolvers follow the registry’s copy, not the NS record inside the zone. Delete the hosted zone and recreate it, and Route 53 assigns four new servers while the registry still lists the old four.

How a resolver gets from the root of DNS down to a registry is a walk of its own, covered in what happens when you press Enter. This resolver starts with the registry’s servers already cached, as real resolvers nearly always do.

THE REGISTRY’S LIST OF NAME SERVERS AGAINST THE ZONE’S OWN
# What the registry tells every resolver:
dig +short NS shop.example
#   ns-2048.awsdns-64.com.
#   ns-2049.awsdns-65.net.
#   ns-2050.awsdns-66.org.
#   ns-2051.awsdns-67.co.uk.

# What the hosted zone was actually given:
aws route53 get-hosted-zone --id Z0SHOP1EXAMPLE \
  --query 'DelegationSet.NameServers'

# If the two lists of 4 differ, resolvers are being sent to
# name servers that do not hold the zone.
STEP 03 / 06

2,048 SERVERS, FOUR PER CUSTOMER

  • shop.exampleits 4 name servers, of 2,048
  • another customershares 2 of its 4 with shop.example
  • a third customershares 1 of its 4 with shop.example
32 cells drawn · 2,048 servers exist · a ringed cell is a server shared with shop.example730,862,190,080 ways to choose 4 of 2,048
Fig 0.3Each row is one customer’s four servers. Compare the accent row with the next: they overlap in two cells at most.

Route 53 arranges its capacity as 2,048 virtual name servers and gives each hosted zone four of them. AWS calls the method shuffle sharding: every customer gets a different combination of four. A flood of queries aimed at one domain lands on that domain’s four servers, and every other domain keeps at least two servers the flood does not reach.

There are 730,862,190,080 ways to choose four servers from 2,048, and no two customer domains share more than two. Each virtual name server answers from more than 200 locations by anycast: one IP address announced from many places, with each query reaching the nearest.

The service-level agreement counts a zone as unavailable only when all four name servers fail to answer for a full minute. It pays credits for any month under 100%.

STEP 04 / 06

THE APEX CANNOT BE A CNAME

a CNAME at www.shop.example2 questions
QUESTION
www.shop.exampletype A
asked of Route 53
ANSWER
  • CNAMEd111111abcdef8.cloudfront.net
    another name, not an address
↓ so the resolver asks a second question
QUESTION
d111111abcdef8.cloudfront.nettype A
asked of CloudFront’s name servers
ANSWER
  • A198.51.100.201TTL 60 s
  • A198.51.100.202TTL 60 s
an alias at shop.example1 question
QUESTIONquery #3
shop.exampletype A
asked of Route 53
ANSWER
  • A198.51.100.201TTL 60 s
  • A198.51.100.202TTL 60 s
plain A records: Route 53 looked the distribution up itself, and the alias is not in the answer
Fig 0.4Compare the two answers. The CNAME one makes the resolver ask a second question; the accent alias answer already holds addresses.

The resolver picks one of the four name servers, ns-2051.awsdns-67.co.uk, and asks it for shop.example: query #3. The shop’s site is a CloudFront distribution, which is reached by a name and has no fixed addresses. The usual record for that is a CNAME, which says “this name is another name”. A CNAME may not share its name with any other record, and the bare domain, called the zone apex, already holds NS and SOA.

An is Route 53’s way around that. Route 53 looks up the target itself and answers with plain A records, in one query where a CNAME takes two. Queries for an alias to an AWS resource are free. An alias answers one record type, so IPv6 needs a second alias of type AAAA. Its TTL comes from the target and can’t be set.

AN ALIAS A RECORD AT THE BARE DOMAIN. THERE IS NO TTL FIELD TO SET
{
  "Changes": [
    {
      "Action": "UPSERT",
      "ResourceRecordSet": {
        "Name": "shop.example",
        "Type": "A",
        "AliasTarget": {
          "HostedZoneId": "Z2FDTNDATAQYW2",
          "DNSName": "d111111abcdef8.cloudfront.net",
          "EvaluateTargetHealth": false
        }
      }
    }
  ]
}
STEP 05 / 06

SIXTY SECONDS FOR A CHANGE, FIFTEEN MINUTES FOR A NO

  • every name server has the change60 s
    Route 53 reports PENDING, then INSYNC
  • a resolver keeps an alias answer60 s
    the TTL of an alias to a load balancer or CloudFront
  • a resolver keeps “no such name”900 s
    the lesser of the SOA record’s TTL (900 s) and its minimum field (86,400 s)
Fig 0.5Three bars on one scale, in seconds. The longest, in accent, is how long a resolver keeps “no such name”.

Two timers follow every change to a record. The first belongs to Route 53: the change is reported as PENDING, then as INSYNC once every name server has it, generally within 60 seconds. The second belongs to resolvers. Each keeps the answer it already cached for the record’s : 60 seconds for an alias to a load balancer or CloudFront, and whatever you set on other records.

An answer of “no such name”, which DNS calls NXDOMAIN, is cached too. A resolver keeps it for the lesser of the SOA record’s TTL and the SOA’s minimum field. In a new Route 53 zone those are 900 and 86,400 seconds, so the answer is kept for 900 seconds, which is 15 minutes.

STEP 06 / 06

THREE QUERIES, AND ROUTE 53 SAW ONE

  1. #1customer’s phone → customer’s resolvershop.example · nothing cached, so the resolver asks on
  2. #2customer’s resolver → .example registryshop.example · a referral: four name-server names
  3. #3customer’s resolver → Route 53shop.example · public zone: alias to CloudFront
queries so far3
Fig 0.6Three rows, three different answerers. The accent row is the only query that reached Route 53.

The phone’s first lookup took three questions, and each one is a : the phone to its resolver, the resolver to the registry, and the resolver to Route 53. Route 53 answered one of the three, so only that one can appear on a bill. Standard queries cost $0.40 per million, and a query for an alias to an AWS resource costs nothing.

For the next 60 seconds everyone behind that resolver gets the cached answer, and Route 53 receives nothing. AWS’s documentation says the query log of a busy record may show one query for every several thousand that users made. The query count is 3.

WHAT YOU NOW KNOW

  • A hosted zone starts with NS and SOA records and four name servers; resolvers find them through the registry’s copy of those names.
  • An alias record answers at the bare domain in one query, free for AWS targets; a CNAME can’t exist there.
  • Changes reach every name server in about 60 seconds, but resolvers keep old answers for the TTL: 3 queries so far.
deep dive: record types the exams expect, registrars, and moving a domain without downtime

Records the exams expect. The types to know are A, AAAA, CNAME, MX, TXT, NS, SOA and CAA, and since October 2024 also HTTPS, SVCB, TLSA and SSHFP. An alias can target API Gateway, an interface VPC endpoint, CloudFront, App Runner, Elastic Beanstalk, a load balancer, Global Accelerator, OpenSearch, an S3 website bucket, AppSync, or another record in the same zone. EC2 public names and RDS endpoints are not on that list, so those take a CNAME. A CAA record names the certificate authorities allowed to issue certificates for the domain. ACM’s DNS validation is a CNAME you leave in the zone: 60 days before expiry ACM checks it and renews the certificate with no manual step.

Registrars and losing a domain. Route 53 registers domains through Amazon Registrar and Gandi. Transfer lock, the status clientTransferProhibited, blocks a transfer out. An expired .com registered at Route 53 can be renewed for 44 days, is removed from Route 53 on day 45, and can be restored until day 75. A reusable delegation set, created through the API or CLI only, gives several zones the same four name servers. It is also how a recreated zone keeps its old ones.

Moving DNS to Route 53 without downtime. Lower the TTLs at the old provider and wait out the old values. Recreate every record in the new zone, then change the name servers at the registrar. Keep the old zone answering for at least 48 hours, the usual 172,800-second TTL of an NS record. Shield Standard covers Route 53 automatically. The service-level agreement excludes the API and the console, which chapter 02 returns to.

On the exam

  • “point the root domain at a load balancer or CloudFront”alias A (and AAAA) record
  • “site unreachable after the hosted zone was deleted and recreated”update the registrar’s name servers, or use a reusable delegation set
  • “migrate DNS providers with no downtime”lower TTL first, copy records, switch name servers, keep the old zone 48 hours
  • “certificate must renew with no manual step”ACM DNS validation CNAME left in place
  • “only one CA may issue for this domain”CAA record
  • “record exists now but clients still get NXDOMAIN”negative caching, 900 seconds

One name, several answers, and a rule for choosing

The shop runs its API in two AWS Regions, us-east-1 and us-west-2, behind one name. Which Region a customer’s request reaches is settled by a DNS answer, before the request exists. At 14:02:07 the customer taps Pay, and the phone looks up api.shop.example. The query count goes from 3 to 5.

STEP 01 / 06

EIGHT WAYS TO PICK AN ANSWER

  • simplechooses by nothingone resource
  • weightedchooses by a number 0–255canary
  • latencychooses by the asker’s networknearest Region
  • failoverchooses by healthstandby
  • geolocationchooses by continent or countrylegal boundaries
  • geoproximitychooses by distance and a biasshifting load
  • multivaluechooses by healthup to 8 answers
  • IP-basedchooses by your own address listknown networks
Fig 1.1Each row is one policy and the single input it reads. The accent row is the policy api.shop.example uses.

A is a setting on a record. Several records share one name and type, each with its own identifier, and Route 53 picks among them when a query arrives. There are eight policies: simple, weighted, latency, failover, geolocation, geoproximity, multivalue answer and IP-based.

Each policy reads one input: nothing at all, a weight you set, the asker’s network, the health of a target, or the asker’s location. Every policy except IP-based also works in a private hosted zone, the kind that answers only inside your own networks (chapter 03). Most policies allow 100 records for one name and type.

STEP 02 / 06

LATENCY IS A TABLE, NOT A PING

QUESTIONquery #5
api.shop.exampletype A
asked by the customer’s resolver · asked of Route 53
ANSWER
  • A198.51.100.20TTL 60 s
↑ chosen from the 2 latency records that share this name
  • record use1latency · Region us-east-1
    alias tothe us-east-1 load balancer
    its address198.51.100.20
    lower latency for this network · returned
  • record usw2latency · Region us-west-2
    alias tothe us-west-2 load balancer
    its address198.51.100.140
    higher latency for this network · not returned
Fig 1.2The query names a network, not a person. The accent record is the Region the stored measurements favour for that network.

At 14:02:07 the customer taps Pay. The phone asks its resolver for api.shop.example, which is query #4, and the resolver asks Route 53, which is query #5. The name has two latency records, one for each Region. Each is an alias to that Region’s load balancer.

Route 53 answers with the record whose Region has the lowest latency for the asker’s network. It reads that from measurements AWS has collected “over a period of time” between networks and Regions. Nothing is probed when the query arrives. The answer here is us-east-1: 198.51.100.20, with a TTL of 60 seconds. Latency queries cost $0.60 per million, though a query for an alias to a load balancer stays free.

THE US-EAST-1 RECORD. ITS US-WEST-2 TWIN CHANGES THE IDENTIFIER, THE REGION, THE HEALTH CHECK AND THE ALIAS TARGET
{
  "Changes": [
    {
      "Action": "UPSERT",
      "ResourceRecordSet": {
        "Name": "api.shop.example",
        "Type": "A",
        "SetIdentifier": "use1",
        "Region": "us-east-1",
        "HealthCheckId": "abcdef11-2222-3333-4444-555555fedcba",
        "AliasTarget": {
          "HostedZoneId": "Z35SXDOTRQ7X7K",
          "DNSName": "dualstack.shop-api-1234567890.us-east-1.elb.amazonaws.com",
          "EvaluateTargetHealth": true
        }
      }
    }
  ]
}
STEP 03 / 06

ROUTE 53 SEES THE RESOLVER, NOT THE CUSTOMER

QUESTIONquery #5
api.shop.exampletype A
asked by the customer’s resolver · asked of Route 53
ANSWER
  • A198.51.100.20TTL 60 s
↓ 2 fields in this query can locate the asker
  • sent from192.0.2.53the resolverused only when no client subnet is present
  • client subnet203.0.113.0/24the customer’s network: the first 24 bits of 203.0.113.50used whenever the resolver includes it
Fig 1.3Two fields in the query could locate the customer. The accent one, the client subnet, is used whenever the resolver includes it.

Query #5 arrives at Route 53 from 192.0.2.53, the resolver, and a resolver can be far from the customers who use it. Many resolvers therefore add a field called to the query: the first 24 bits of the customer’s address, here 203.0.113.0/24.

Route 53 uses that subnet for latency, geolocation, geoproximity and IP-based routing. Without it, Route 53 falls back to the resolver’s own address. The resolver AWS runs inside a VPC never sends the field, so a query that starts inside a VPC is located by the address of AWS’s resolver fleet.

STEP 04 / 06

A DIAL FROM 0 TO 255

  • current stackweight 90 · 90% of answers
  • new stackweight 10 · 10% of answers
share of answers = weight ÷ the sum of the weights (100 here)weight 0 · no answers for that recordone cached answer serves everyone behind that resolver for the TTL
Fig 1.4The bars are drawn to their weights, 90 and 10. The accent bar is the new stack’s share of answers, not users.

Weighted routing gives each record an integer from 0 to 255. A record’s share of answers is its weight divided by the sum of the weights for that name. Weights of 90 and 10 send one answer in ten to a new stack, and a weight of 0 stops answers for that record. Blue/green and canary releases done in DNS work this way.

The share is of answers, not of users. One cached answer serves everyone behind that resolver until its TTL runs out, so a weight of 10 can deliver much more or much less than a tenth of the requests. When the split has to be exact, AWS’s own DevOps Professional sample question prefers weighted target groups on one load balancer.

STEP 05 / 06

WHERE THEY ARE, OR HOW FAR

  • geolocationasker located in Brazil↓ compared with these records
    • country · Germanyno match
    • continent · Europeno match
    • defaultanswers
    most specific location first; without the default row this asker gets no answer
  • geoproximityasker midway between two Regions↓ compared with these records
    • us-east-1 · bias +25distance counts 75% · answers
    • us-west-2 · bias 0distance counts 100%
    nearest resource wins after each distance is scaled by its bias, −99 to +99
  • IP-basedasker at 203.0.113.50↓ compared with these records
    • range 203.0.113.0/24answers
    • defaultnot reached
    matched against address ranges you upload, as specific as /24 for IPv4
Fig 1.5Three customers meet three kinds of rule. The accent customer matches no geolocation record, and only the default row answers them.

Geolocation routing picks a record by the asker’s continent, country or US state, most specific first. It needs a default record. Without one, an asker who matches none of your locations gets no answer at all.

Geoproximity routing picks the nearest resource, and a bias from −99 to +99 grows or shrinks each resource’s reach. For a positive bias Route 53 compares distance × (1 − bias ÷ 100). Since 2024-01-10 geoproximity is an ordinary record setting. IP-based routing matches the asker’s address against ranges you upload, as specific as a /24 for IPv4.

STEP 06 / 06

THE CHOICE LASTS SIXTY SECONDS

  1. #1customer’s phone → customer’s resolvershop.example · nothing cached, so the resolver asks on
  2. #2customer’s resolver → .example registryshop.example · a referral: four name-server names
  3. #3customer’s resolver → Route 53shop.example · public zone: alias to CloudFront
  4. #4customer’s phone → customer’s resolverapi.shop.example · nothing cached for this name
  5. #5customer’s resolver → Route 53api.shop.example · latency record use1: 198.51.100.20
queries so far5
  • Route 53the answer changescached for the TTL
  • Global Acceleratorthe answer never changeschosen per connection
Fig 1.6Rows #4 and #5 join the ledger. The accent row’s answer is now cached for 60 seconds by everyone behind that resolver.

Queries #4 and #5 bring the query count to 5. The resolver now holds 198.51.100.20 for 60 seconds, and every customer behind it is sent to us-east-1 without Route 53 being asked again. A client that ignores TTLs keeps the address even longer.

AWS Global Accelerator makes the same choice somewhere else. It gives you two fixed anycast addresses that never change, and AWS’s edge network picks the Region for each new connection, so no DNS answer has to expire first. That is why exam scenarios with clients that cache DNS, or with partners that need fixed addresses, point to Global Accelerator.

WHAT YOU NOW KNOW

  • A routing policy picks one of several same-named records from the query alone: the asker’s network, a weight, a location or health.
  • Latency routing reads stored measurements for the asker’s network, located by the client subnet when the resolver sends it.
  • Weighted records split answers, not users, and every answer is cached for its TTL: 5 queries so far.
deep dive: multivalue and nested records, and when the answer is not Route 53

Multivalue, simple and nested records. A simple record with several values returns all of them in random order and can’t use health checks. Multivalue answer returns up to eight healthy records and is not a load balancer. An alias record can point at another record in the same zone, which builds trees: latency at the top, weighted under each Region, failover under those. Traffic Flow is a visual editor and version store for such trees, at $50 per policy record per month.

When the answer is not Route 53. Choose Global Accelerator for fixed addresses and for failover that DNS caches can’t delay. Choose a CloudFront origin group to fail over between origins behind one name, which is the answer to AWS’s own DOP-C02 sample question. Choose weighted target groups on one load balancer, or CodeDeploy, when a canary must be an exact share of requests.

Private zones. Every policy except IP-based works in a private hosted zone. EDNS Client Subnet does not apply there, and latency records are judged by the Region of the VPC that asks.

On the exam

  • “serve each user from the Region that responds fastest”latency routing
  • “EU users’ requests must stay in EU Regions”geolocation with a default record
  • “send 10% to the new version and roll back quickly”weighted records with a low TTL, or weighted target groups when the split must be exact
  • “move more traffic to one Region by geography”geoproximity bias
  • “clients cache DNS, or partners need fixed IP addresses”Global Accelerator
  • “return several healthy addresses without a load balancer”multivalue answer
  • “route one ISP’s ranges differently”IP-based routing with a CIDR collection

Ninety seconds from a failed deploy to another Region

At 14:06:00 a deploy in us-east-1 goes wrong, and every request to /health there returns 500. Nothing in DNS has changed: resolvers around the world still hold us-east-1’s address. This chapter follows what has to happen before the customer’s next lookup, at 14:07:40, gets us-west-2. The query count goes from 5 to 7.

STEP 01 / 06

A REQUEST EVERY TWO SECONDS, FROM EIGHT REGIONS

  • us-east-1
  • us-west-1
  • us-west-2
  • eu-west-1
  • ap-southeast-1
  • ap-southeast-2
  • ap-northeast-1
  • sa-east-1
↓ a checker in each of the 8 Regions requests this URLhttps://use1.api.shop.example/health
one request, as one checker times it
request sent6 s at most
  • open a TCP connectionwithin 4 s
  • receive a 2xx or 3xx statuswithin 2 s more
Fig 2.1Eight checker Regions surround one endpoint. The accent timer is the 4 seconds each has to open a connection.

A is Route 53 servers in eight Regions, called health checkers, each requesting a URL you name. A checker must open a TCP connection within 4 seconds, then receive a 2xx or 3xx status within 2 more. An optional string match reads the first 5,120 bytes of the response body. An HTTPS check never validates the certificate.

Every checker runs on its own clock. At the standard 30-second interval the endpoint receives a request about every two seconds. At the fast 10-second interval it receives more than one a second. The shop’s check on us-east-1, hc-use1, costs $2.50 a month: $0.50 for a check on an AWS endpoint, $1 for HTTPS and $1 for the fast interval.

HC-USE1: AN HTTPS CHECK EVERY 10 SECONDS, UNHEALTHY AFTER 3 FAILURES
# hc-use1: an HTTPS probe of the us-east-1 load balancer.
aws route53 create-health-check \
  --caller-reference hc-use1-2026-11-13 \
  --health-check-config '{
    "Type": "HTTPS",
    "FullyQualifiedDomainName": "use1.api.shop.example",
    "Port": 443,
    "ResourcePath": "/health",
    "RequestInterval": 10,
    "FailureThreshold": 3
  }'

# 3 failed checks x 10 s = 30 s before Route 53 marks it unhealthy.
# $0.50 + $1 for HTTPS + $1 for the 10 s interval = $2.50 a month.
STEP 02 / 06

EIGHTEEN PERCENT IS A PASS

  • unhealthy
  • unhealthy
  • healthy
  • unhealthy
  • unhealthy
  • unhealthy
  • unhealthy
  • healthy
  • unhealthy
  • unhealthy
  • unhealthy
  • unhealthy
  • unhealthy
  • healthy
  • unhealthy
  • unhealthy
3 of 16 healthy18.75%above 18%HEALTHY
16 checkers drawn; AWS doesn’t publish the real count
Fig 2.2Each cell is one checker’s verdict. Count the accent cells: 3 of 16, under a fifth, and the endpoint is still healthy.

Each checker judges alone. It flips its verdict only after FailureThreshold consecutive results that disagree with it: 3 by default, and 1 to 10 are allowed. Route 53 then counts the verdicts. The endpoint is healthy when more than 18% of the checkers say so, which means a network fault on one continent can’t mark it down.

The reverse also holds. An endpoint that only a fifth of the checkers can reach still counts as healthy, even while most of the internet can’t reach it. A firewall that admits too few checkers marks a working endpoint unhealthy, so allow the address ranges AWS publishes under ROUTE53_HEALTHCHECKS in ip-ranges.json.

STEP 03 / 06

THIRTY SECONDS TO NOTICE, SIXTY TO FORGET

ANSWERapi.shop.example · type A
198.51.100.20 · us-east-1
cached by resolvers that asked before 14:06:30
14:06:00 · /health starts failing14:07:40
  • 3 failed checks30 shc-use1 is unhealthy at 14:06:30
  • resolvers’ cached answers expireup to 60 sthe last one by 14:07:30
until every customer has switched30 s + 60 s = 90 s
Fig 2.3Read the bar left to right: 30 seconds of failed checks, then 60 seconds of cached answers. Query #7 lands after both.

At 14:06:00 the health URL starts failing. Three failed 10-second checks later, at about 14:06:30, hc-use1 is unhealthy and Route 53 stops returning the us-east-1 record. Latency routing now answers every query with us-west-2. A resolver that cached the old answer at 14:06:29 keeps it for 60 more seconds, so the last customers switch by about 14:07:30.

That is 90 seconds: 3 × 10 to notice, plus 60 of TTL. With standard 30-second checks it is 150. At 14:07:40 the phone asks again, which makes queries #6 and #7, and gets 198.51.100.140. The query count is 7. A failover policy, with one PRIMARY record and one SECONDARY, runs on the same clock.

STEP 04 / 06

THE ALIAS THAT INHERITS A VERDICT

api.shop.example · alias · use1Evaluate Target Health on · healthy, so it stays in the answer
↑ takes its health from
us-east-1 load balancerhealthy while every target group that has targets has at least 1 healthy target
↑ which reads its target groups
  • target group 1healthyunhealthyunhealthy1 of 3 targets healthy: enough
  • target group 2healthyunhealthy1 of 2 targets healthy: enough
Fig 2.4Follow the arrows up from the targets: one healthy target per group keeps the accent alias record in the answer.

An alias record can take its health from its target. The setting is called Evaluate Target Health. With it on, an alias to a load balancer is healthy only while every target group that has targets also has at least one healthy target. It needs no separate health check and adds no charge. It can’t be turned on for an alias to CloudFront.

A record with neither a health check nor this setting always counts as healthy, which is the usual reason a failover never happens. One more rule runs the other way: when every record for a name is unhealthy, Route 53 treats them all as healthy and answers from all of them.

STEP 05 / 06

A PRIVATE DATABASE NO CHECKER CAN REACH

requesting a private address directly
  1. health checkerson the public internet
  2. ✕ no path in
  3. Postgres 10.0.20.14a private address inside the VPC
watching a CloudWatch alarm’s metric
  1. probe in the VPCpublishes a custom metric
  2. CloudWatch metricthe data an alarm watches
  3. health checkreads the metric’s data stream
  4. recordleft out of answers when unhealthy
Fig 2.5No checker arrow crosses into the VPC. The accent path runs through a CloudWatch metric, and the health check reads that.

Health checkers sit on the public internet, so they can’t reach a private address such as the shop’s database at 10.0.20.14. For anything private, a health check can watch a CloudWatch alarm instead. The alarm’s metric can be the database’s connection count, or a custom metric that a probe inside the VPC publishes.

The health check reads the metric’s data, not the alarm’s state. A setting says what missing data means: healthy, unhealthy, or the last known status. A calculated health check, one whose inputs are other health checks, combines up to 255 of them under a rule such as “healthy if at least 2 of 3 are”.

STEP 06 / 06

THE EDIT THAT NEEDS THE REGION YOU ARE LEAVING

data planeruns everywhere
  • answer querieskeeps working
  • run health checkskeeps working
  • change answers when a check failskeeps working
  • flip an ARC routing controlkeeps working
control planeus-east-1
  • create or edit a recordmay fail
  • create a zonemay fail
  • create a health checkmay fail
the right-hand words say what each action does while us-east-1 is impaired
Fig 2.6Two lists: what keeps working when us-east-1 is impaired, and what doesn’t. The accent row, editing a record, is in the second.

Changing a record is an API call, and Route 53’s API runs in us-east-1. That API is the . Answering queries and running health checks is the data plane, and it runs everywhere. A failover plan that edits a record therefore depends on the Region it is trying to leave.

On 2025-10-19 at 23:48 PDT a race condition in DynamoDB’s own DNS automation left dynamodb.us-east-1.amazonaws.com with no addresses, and the effects lasted about 14.5 hours. So fail over without API calls. Health checks do that. So do routing controls in Amazon Application Recovery Controller (ARC): on/off switches served by five Regional endpoints, usable while any three answer, for $2.50 an hour, $1,825 a month.

A FAILOVER THAT CALLS ONE OF FIVE REGIONAL ENDPOINTS AND EDITS NO RECORD
# Turn the us-east-1 routing control off. The call goes to one of
# the 5 Regional endpoints of the ARC cluster, here the one in us-west-2.
aws route53-recovery-cluster update-routing-control-state \
  --routing-control-arn arn:aws:route53-recovery-control::777788889999:controlpanel/0123456789abcdef0123456789abcdef/routingcontrol/abcdef1234567890 \
  --routing-control-state Off \
  --region us-west-2 \
  --endpoint-url https://host-dddddd.us-west-2.example.com/v1

# Any 3 of the 5 endpoints keep the cluster answering.
# No record is edited: the health check tied to this control
# turns unhealthy, and Route 53 stops returning us-east-1.

WHAT YOU NOW KNOW

  • Checkers in eight Regions request the health URL; more than 18% healthy means healthy, and three failed 10-second checks mark it down in 30 seconds.
  • Failover time is detection plus TTL: 30 + 60 = 90 seconds here. Queries #6 and #7 get us-west-2, for 7 so far.
  • Record edits need the us-east-1 control plane; health checks and ARC routing controls change answers without it.
deep dive: disaster recovery patterns, Application Recovery Controller, and the day AWS’s own DNS broke

Active-active and active-passive. The shop’s latency records with health checks are active-active: both Regions serve, and one drops out when it is unhealthy. The failover policy is active-passive: a PRIMARY record answers while it is healthy, and a SECONDARY answers only when the primary isn’t. The secondary can be a static “we’ll be back” page in S3. If both are unhealthy, Route 53 returns the primary. Match the pattern to the recovery strategy the question names: backup and restore, pilot light, warm standby, or multi-site.

Application Recovery Controller. Routing controls come with safety rules: an assertion rule keeps at least one Region on, and a gating rule makes one control a master switch for others. Zonal shift moves load-balancer traffic out of one Availability Zone for up to three days. Zonal autoshift lets AWS do the same, with weekly practice runs, and both are free. Region switch, launched 2025-08-01, runs a recovery plan across Regions for $70 a plan per month. Readiness check has been closed to new customers since 2026-04-30.

The day AWS’s own DNS broke. In the October 2025 event two components managed DynamoDB’s records: a DNS Planner that wrote plans, and three DNS Enactors, one per Availability Zone, that applied them. A delayed Enactor applied an old plan over a newer one. Another Enactor’s clean-up then deleted that plan, and with it every address. AWS disabled the automation worldwide until the race was fixed. Since 2025-11-26, accelerated recovery lets record changes resume from us-west-2 with a 60-minute recovery time objective, if you enabled it beforehand.

Testing and measuring. Invert a health check to rehearse a failure, or inject one with AWS Fault Injection Service. Measured recovery time is detection plus TTL plus whatever the client caches. A JVM with a security manager caches lookups forever unless networkaddress.cache.ttl is set. An RDS Multi-AZ failover is also a DNS change, which is why applications must connect by endpoint name and never by a cached address.

On the exam

  • “active-passive DR across two Regions”failover routing, health check on the primary
  • “failover must not depend on a control plane”health checks or ARC routing controls, never record edits
  • “health-check an RDS instance or anything with a private address”health check on a CloudWatch alarm
  • “healthy only if two of three components are up”calculated health check
  • “alias to a load balancer never fails over”turn on Evaluate Target Health
  • “move traffic out of one impaired Availability Zone”ARC zonal shift or autoshift
  • “stop an operator turning both Regions off”ARC safety rule
  • “measure recovery time in a failover test”detection + TTL + client cache, tested with Fault Injection Service

The resolver every VPC already has

Go back two minutes, to 14:00:05. The app server has just booted in a private subnet, with no public address, and before it can serve a single request it has to find its database and its secrets store by name. Every lookup it makes goes to one address, 10.0.0.2. This chapter covers 3 of them, and the query count goes from 7 to 10.

STEP 01 / 05

AN ADDRESS THAT ANSWERS IN EVERY VPC

internet gatewaynot neededNAT gatewaynot needed
shop-prod VPC · 10.0.0.0/16
  1. app server10.0.10.27
  2. every DNS query
  3. VPC resolver10.0.0.2 · also 169.254.169.253
security groupscan’t filter this hop
network ACLscan’t filter this hop
each network interface1,024 packets a second
Fig 3.1The accent arrow reaches the resolver without crossing a route table or a filter: the resolver sits outside both.

Every VPC has a DNS server at its base address plus two. In 10.0.0.0/16 that is 10.0.0.2, and the same server also answers at 169.254.169.253. It is the , formally the Route 53 VPC Resolver (called Route 53 Resolver until 2026, and still in most exam material). Instances learn its address when they boot.

No security group or network ACL can filter traffic to it, and a query needs no internet gateway or NAT gateway to reach it. One limit does apply: each network interface may send it 1,024 packets a second, an allowance shared with the instance metadata and time services. The AWS VPC tutorial follows this app server’s packets through the filters that do apply.

STEP 02 / 05

A ZONE THE INTERNET CAN’T SEE

aws.shop.internal · private zone
readable from · shop-prod VPC · shop-hub VPC
nametypevalue
dbCNAMEshop-db.cluster-c1a2b3c4d5e6.us-east-1.rds.amazonaws.com
ordersaliasinternal load balancer
query #8 asked for db: the resolver followed the CNAME and returned 10.0.20.14, all in one query
Fig 3.2The zone’s header lists the VPCs allowed to read it. The accent row is the record query #8 matched.

A answers only queries from VPCs associated with it. The shop’s zone, aws.shop.internal, holds a record named db: a CNAME to the RDS endpoint. When the connection pool looks up db.aws.shop.internal, the VPC resolver follows the CNAME itself and returns 10.0.20.14 in one query, number 8.

Two VPC attributes must both be on for this to work, enableDnsSupport and enableDnsHostnames, and the second is off by default in every VPC except the default one. Every private zone also lists the same four reserved name servers in its NS record. They never answer for the zone on the internet.

The ending of the name is deliberate. ICANN set .internal aside for private names on 2024-07-29, so no registry will ever hand out a public name under it.

STEP 03 / 05

ONE NAME, TWO TRUTHS

ASKED FROM THE INTERNET
QUESTION
api.shop.exampletype A
asked by the customer’s resolver · asked of the public zone
ANSWER
  • 198.51.100.20TTL 60 s
    the public zone holds this record
ASKED FROM INSIDE THE VPC
QUESTION
api.shop.exampletype A
asked by the app server · asked of the VPC resolver
ANSWER
NXDOMAIN · no such name
shop.example · private zone
an example: created later and associated with this VPC
nametypevalue
adminA10.0.10.77
the zone matches the domain and has no api record, so public DNS is never tried
Fig 3.3One question, asked from two places. Inside the VPC the accent answer is NXDOMAIN: the private zone matched and lacks that record.

A public hosted zone and a private one can have the same name. That arrangement is : one question gets one answer from the internet and another from inside the VPC. Inside an associated VPC the private zone answers, and the public zone is never consulted.

The trap is a private zone that matches the domain and lacks the record. The VPC resolver then returns NXDOMAIN, the DNS status for “no such name”, and does not try public DNS. Create a private shop.example holding only admin, and api.shop.example stops resolving inside the VPC. When several private zones overlap, the one with the most specific name answers.

STEP 04 / 05

SECRETS MANAGER MOVES INTO YOUR SUBNET

QUESTIONquery #9
secretsmanager.us-east-1.amazonaws.comtype A
asked by the app server · asked of the VPC resolver
ANSWER
  • 10.0.10.41
    from a private zone AWS manages, readable in this VPC only
QUESTION
vpce-0a1b2c3d4e5f67890-ab12cd34.secretsmanager.us-east-1.vpce.amazonaws.comtype A
asked by anyone · asked of public DNS
ANSWER
  • 10.0.10.41
    a public record that holds a private address
interface endpointone network interface · 10.0.10.41 · app subnet
Fig 3.4Two names lead to one network interface. The accent name is the service’s ordinary hostname, answered by a zone AWS manages.

At boot the AWS SDK looks up secretsmanager.us-east-1.amazonaws.com, query 9, and gets 10.0.10.41, an address in the app subnet. That address belongs to an interface endpoint: a network interface in your subnet that leads to the service. With its private DNS setting on, the endpoint comes with a hidden private hosted zone for the service’s name. AWS manages that zone, and only the endpoint’s own VPC can read it.

The application’s code doesn’t change, because the name it looks up is the public one. The endpoint also has names of its own, which begin vpce-. Those are ordinary public DNS records, and they return the same private address to anyone who asks.

STEP 05 / 05

THE BUCKET’S ANSWER NEVER CHANGED

  • query #8 · answeredfrom a private hosted zone
  • query #9 · answeredfrom an endpoint’s managed zone
  • query #10 · answeredfrom public DNS
  1. #8app server → VPC resolverdb.aws.shop.internal · private hosted zone: 10.0.20.14
  2. #9app server → VPC resolversecretsmanager.us-east-1.amazonaws.com · endpoint’s managed zone: 10.0.10.41
  3. #10app server → VPC resolvershop-receipts.s3.us-east-1.amazonaws.com · public DNS: a public S3 address
queries so far10
Fig 3.5Compare rows #9 and #10: the Secrets Manager name got a private address, the accent S3 name still gets a public one.

At 14:02:07, during the checkout, the app looks up the receipts bucket, shop-receipts.s3.us-east-1.amazonaws.com: query 10. The answer is a public S3 address, although the VPC has a gateway endpoint for S3. A gateway endpoint adds routes to the subnet’s route table and never changes DNS. The name resolves as it would anywhere, and the route table then keeps the packets inside AWS.

The VPC resolver fetched that answer from public DNS itself, asking from AWS’s own public addresses. Those questions are not counted here. The resolver is a fleet shared between customers, with a shared cache, and no log you own shows whether it asked anyone. It may even serve an answer past its TTL while the servers it would ask are failing.

Queries 8, 9 and 10 all went to 10.0.0.2, and each was answered from a different place. The query count is 10.

WHAT YOU NOW KNOW

  • Every VPC has a resolver at its base address plus two; no security group, network ACL or route table stands in front of it.
  • A private hosted zone answers only for associated VPCs, and a matching zone with no record returns NXDOMAIN without trying public DNS.
  • Interface endpoints change the DNS answer and gateway endpoints don’t: queries #8 to #10 make 10.
deep dive: DHCP option sets, EC2’s own names, the 1,024-packet limit and service discovery

DHCP option sets and other resolvers. A VPC’s DHCP option set tells instances which DNS servers to use: AmazonProvidedDNS, which is the VPC resolver, or addresses you choose, such as Active Directory’s. Point instances elsewhere and three things stop seeing their queries: DNS Firewall, Resolver query logs and GuardDuty’s DNS findings. The usual design keeps instances on the VPC resolver and reaches other DNS servers through forwarding rules, which chapter 04 covers.

Names EC2 gives you. Every instance gets a private DNS name built from its address: ip-10-0-10-27.ec2.internal in us-east-1, and ip-10-0-10-27.us-west-2.compute.internal in other Regions. A subnet can hand out resource names instead, such as i-0123456789abcdef.ec2.internal. The VPC resolver also answers reverse lookups for the VPC’s address ranges automatically.

The 1,024-packet limit and caching. The limit applies to each network interface and can’t be raised, and there is no per-VPC limit. A host that looks up a name for every request, with no local cache, reaches it under load. The counter linklocal_allowance_exceeded in ethtool output shows the dropped packets. glibc, the C library most Linux software resolves names through, waits 5 seconds for an answer, tries twice and keeps no cache of its own. Kubernetes pods search with ndots:5, which multiplies the queries behind each lookup; the Kubernetes tutorial’s Services chapter covers cluster DNS.

Service discovery. AWS Cloud Map creates private hosted zones for services that are discovered through DNS. ECS Service Connect resolves service names in a proxy inside each task, so it doesn’t depend on VPC DNS at all.

On the exam

  • “instances can’t resolve a private hosted zone”both VPC DNS attributes on, and the zone associated with the VPC
  • “same domain must answer differently inside and outside”split-horizon: a public and a private zone with the same name
  • “internal clients get NXDOMAIN for public records after a private zone was added”copy those records into the private zone
  • “reach an AWS service privately with no code change”interface endpoint with private DNS
  • “intermittent DNS failures on one busy host”1,024 packets per second per interface; add a local cache
  • “GuardDuty reports no DNS findings”instances aren’t using the VPC resolver

Two networks that each own half the names

The warehouse stock system still runs in the shop’s data centre, and its name, stock.shop.internal, exists on two DNS servers there and nowhere else. The VPC resolver has never heard of that zone, and those two servers have never heard of aws.shop.internal. During this checkout 4 queries pass between the two networks, two in each direction, and the query count goes from 10 to 14.

STEP 01 / 05

THE RESOLVER HAS A RULEBOOK

query namestock.shop.internal
Resolver rules seen by shop-prod
the most specific matching domain decides
domainwhat the rule does
.matches
automatic · Internet Resolverlook the name up in public DNS
shop.internalmatches · wins
FORWARDsend to 10.50.0.10, 10.50.0.11
aws.shop.internalno match
automatic · private hosted zoneanswer from the zone’s records
ec2.internalno match
automaticanswer EC2’s own instance names
db.aws.shop.internal would match three of these rows, and the aws.shop.internal rule would win
Fig 4.1The query name is tested against every row. Two match, and the accent row wins because its domain is the longer one.

The VPC resolver tests every query name against a list of and uses the most specific match. Some rules are automatic. Each associated private hosted zone gets one, EC2’s own names get some, and one covers ., the root of every name. That last rule is called Internet Resolver, and it is why a name nothing else matches is looked up in public DNS.

A forwarding rule names a domain and up to six DNS server addresses, and the VPC resolver sends every query under that domain to those servers instead of answering it. It works like a mail redirection order: anything addressed to that domain goes to the other address, unopened.

The shop’s forwarding rule, rslvr-rr-onprem, sends shop.internal to 10.50.0.10 and 10.50.0.11. Names under aws.shop.internal still go to the private hosted zone, because that zone’s automatic rule names the longer domain.

ONE FORWARDING RULE, AND THE ASSOCIATION THAT SWITCHES IT ON
# In shop-network: send one domain to the 2 data centre DNS servers.
aws route53resolver create-resolver-rule \
  --creator-request-id onprem-2026-11-13 \
  --name onprem \
  --rule-type FORWARD \
  --domain-name shop.internal \
  --resolver-endpoint-id rslvr-out-hub \
  --target-ips "Ip=10.50.0.10" "Ip=10.50.0.11"

# A rule does nothing until a VPC is associated with it.
aws route53resolver associate-resolver-rule \
  --resolver-rule-id rslvr-rr-onprem \
  --vpc-id vpc-0shopprod
STEP 02 / 05

A QUERY LEAVES THROUGH A BORROWED ADDRESS

questionstock.shop.internal
#11#12
  1. app server10.0.10.27 · shop-prod VPC
  2. VPC resolver10.0.0.2
  3. outbound endpoint10.1.10.20 · hub VPC
  4. data centre DNS10.50.0.10
query #11: the app server asks 10.0.0.2 for the stock system’s address
query #11 · source address10.0.10.27seen by the VPC resolver
query #12 · source address10.1.10.20seen by the data centre
Fig 4.2Watch the query change hands: it leaves the app as #11 and reaches the data centre as #12, from the accent endpoint.

During the checkout the app server asks 10.0.0.2 for stock.shop.internal: query 11. The forwarding rule matches, so the VPC resolver passes the query to an outbound . The shop’s is rslvr-out-hub: two network interfaces in the hub VPC, 10.1.10.20 and 10.1.11.20, in two Availability Zones.

One of those interfaces sends the question to the data centre’s DNS server at 10.50.0.10, over the private connection that joins the two networks. That is query 12, and it comes back with 10.50.4.20. The app’s VPC needs no route to the hub VPC for any of this. The resolver service carries the query to the endpoint itself.

STEP 03 / 05

THE DATA CENTRE ASKS BACK

questionorders.aws.shop.internal
  1. warehouse system10.50.4.20
  2. #13
  3. data centre DNS10.50.0.10 · forwarder for aws.shop.internal
  4. #14
  5. inbound endpoint10.1.10.10 · 10.1.11.10hub VPC
  6. reads
  7. private zoneaws.shop.internalorders is 10.0.10.90
data centre DNS → 10.1.0.2a VPC’s .2 resolver address can’t be queried from outside AWS
Fig 4.3The reverse path has its own endpoint. The two accent addresses are the ones the data centre’s forwarder points at.

One second later, at 14:02:08, the warehouse system has to confirm the reservation with the orders service in AWS, so it must find orders.aws.shop.internal. It asks the data centre’s DNS server: query 13. That server has a conditional forwarder, its own equivalent of a forwarding rule, for aws.shop.internal. The forwarder points at 10.1.10.10 and 10.1.11.10.

Those two fixed addresses are an inbound endpoint, rslvr-in-hub, in the hub VPC. The data centre’s server sends the question to one of them: query 14. A query that arrives at an inbound endpoint is answered as if it had been asked from inside the hub VPC, so the private hosted zone must be associated with that VPC. The answer is 10.0.10.90, the internal load balancer.

The endpoint is not optional. Servers outside AWS can’t query a VPC’s resolver at its .2 address, even over a private connection: AWS doesn’t support it.

STEP 04 / 05

WHEN A RULE AND A ZONE CLAIM THE SAME NAME

  • SAME NAME
    forwarding rule forshop.internal
    private zone namedshop.internal
    the rule takes every query, and the zone’s records are ignored
  • CARVE-OUT
    forwarding rule forshop.internal
    system rule fordev.shop.internal
    the subdomain is answered inside AWS, and the rest is forwarded
  • LOOP
    forwarding rule associated withthe hub VPC
    inbound endpoint hosted inthe hub VPC
    a query the data centre sends back in can be forwarded out again
Fig 4.4Three pairs of rule and zone. In the accent pair the names are identical, and the rule takes the query.

Three mistakes follow from how rules are matched. The first is a forwarding rule and a private hosted zone with the same domain name. If both are called shop.internal, the forwarding rule takes every query and the zone’s records are ignored. Nothing warns you.

The second is a subdomain you want answered inside AWS while its parent domain is forwarded. That takes a system rule: a Resolver rule that tells the VPC resolver to answer a domain itself. A system rule for dev.shop.internal is more specific than the forwarding rule for shop.internal, so it wins for those names.

The third is a loop. Suppose a forwarding rule sends a domain to the data centre, and the data centre forwards that same domain back to an inbound endpoint. Associate the rule with the VPC that hosts that inbound endpoint, and a query can circle between the two networks.

STEP 05 / 05

FOUR NETWORK INTERFACES, $365 A MONTH

shop-hub Resolver endpoints · us-east-1 · per month
endpoint interfaces$365.00/month
4 interfaces × 730 h × $0.125/h
queries through an endpoint$0.40 per million
inbound or outbound, on top of the hours
  1. #11app server → VPC resolverstock.shop.internal · forwarding rule shop.internal matches
  2. #12outbound endpoint → data centre DNSstock.shop.internal · the data centre’s own zone: 10.50.4.20
  3. #13warehouse system → data centre DNSorders.aws.shop.internal · conditional forwarder for aws.shop.internal
  4. #14data centre DNS → inbound endpointorders.aws.shop.internal · private hosted zone: 10.0.10.90
queries so far14
Fig 4.5Every receipt line carries its unit. The accent line is the hourly charge, paid per interface whether or not a query passes.

Each endpoint address is a network interface that handles about 10,000 UDP queries a second. If the endpoint’s security group tracks connections, that can fall to as few as 1,500. AWS’s guidance is to add an address when one reaches 50% of its capacity, up to six per endpoint.

Each interface costs $0.125 an hour. The hub has two endpoints with two addresses each, so its 4 interfaces cost $365 a month at 730 hours, plus $0.40 for every million queries that pass through them. Putting each endpoint’s addresses in two Availability Zones is also what earns the 99.99% availability SLA.

Queries 11 and 12 took one name out to the data centre, and queries 13 and 14 brought another back in. That is 4 more, and the query count is 14.

WHAT YOU NOW KNOW

  • Resolver rules send each query to the most specific matching domain; the shop’s forwarding rule sends shop.internal to two data centre servers.
  • Outbound endpoints carry queries out and inbound endpoints accept them in; both are network interfaces at $0.125 an hour each.
  • A forwarding rule beats a private zone of the same name. Queries #11 to #14 make 14.
deep dive: delegation rules, encrypted DNS, Active Directory and sizing endpoints

Delegation instead of forwarding. Since 2025-06-24 there is a third rule type beside forward and system: DELEGATE. With it the data centre’s DNS can delegate a subdomain to a private hosted zone through an inbound endpoint, and a private hosted zone can delegate one to the data centre through an outbound endpoint, as ordinary DNS delegation does. Inbound endpoints used for delegation speak plain DNS only.

Encrypted DNS. Resolver endpoints have spoken DNS over HTTPS since 2023-12-20, with a FIPS variant on inbound endpoints only. Use it when queries between the two networks must be encrypted in transit.

Active Directory. With AWS Managed Microsoft AD, a forwarding rule sends the directory’s domain to the directory’s DNS addresses. In the other direction, the domain controllers get a conditional forwarder for AWS names that points at an inbound endpoint.

Sizing and failure. An endpoint’s security group needs TCP and UDP port 53: an inbound rule on an inbound endpoint, an outbound rule on an outbound one. Write those rules so connections go untracked, or capacity falls as step 5 described. The data centre’s firewall must admit the outbound endpoint’s addresses. The resolver sends redundant outbound queries, so the data centre’s servers see more queries than clients asked. The metrics to watch are InboundQueryVolume, OutboundQueryAggregateVolume and ResolverEndpointCapacityStatus. The default quota is four endpoints per Region.

IPv6 and Outposts. Endpoints have been dual-stack since 2023-03-10, and inbound endpoints have offered DNS64 since 2026-05-07. Outposts racks can run a local resolver of their own.

On the exam

  • “on-premises servers must resolve private hosted zone or endpoint names”inbound endpoint plus a conditional forwarder on-premises
  • “VPC workloads must resolve on-premises names”outbound endpoint plus a forwarding rule associated with the VPCs
  • “highly available hybrid DNS”both endpoints, at least two addresses in two Availability Zones
  • “private zone records ignored after a forwarding rule was added”rule precedence; rename, or add a system rule
  • “exempt one subdomain from forwarding”system rule
  • “queries loop between AWS and on-premises”rule associated with the inbound endpoint’s VPC
  • “DNS between sites must be encrypted”DNS over HTTPS on the endpoints

Forty accounts, one set of DNS rules

Everything in the last two chapters worked because the app’s VPC could read a private zone and use a forwarding rule that it doesn’t own. Both belong to a different AWS account, shop-network, and the shop has 40 accounts whose networks all need the same setup. A is the standard multi-account layout that holds them, and this chapter covers how one DNS setup is shared across it. Sharing configuration sends no DNS question, so the query count holds at 14.

STEP 01 / 05

CONTROL TOWER BUILDS NO DNS

management account · Control Tower builds the accounts and no DNS
Security · unit
shop-logscentral logging
Infrastructure · unit
shop-networkthe network account
shop-hub VPC · 10.1.0.0/16inbound endpointoutbound endpointrule · shop.internalzone · aws.shop.internal
Workloads · unit
shop-prodthe checkout
VPC · resolver 10.0.0.2
shop-devdevelopment
VPC · its own .2 resolver
+ 37 moreaccounts
each VPC · its own .2 resolver
one hub pair of endpoints$365.00/month
a pair in each of 40 VPCs$14,600.00/month
4 interfaces × 730 h × $0.125/h per pair
Fig 5.1One account holds the endpoints and the rules. The accent box is its hub VPC; every other VPC keeps its own resolver.

AWS Control Tower builds a landing zone: accounts grouped into organizational units, shared logging and security accounts, guardrails that apply to every account, and a factory for new accounts. It creates no Resolver endpoint, rule or hosted zone.

AWS’s reference design adds a network account, here shop-network, with a hub VPC that holds the endpoints, the rules and the shared zones. Every other VPC keeps sending its queries to its own .2 resolver address. Chapter 04 priced the hub’s pair of endpoints at $365 a month, so 40 VPCs with pairs of their own would cost $14,600.

Landing Zone Accelerator, an AWS solution that deploys on top of Control Tower, takes this design as configuration. The sample declares the outbound endpoint, its forwarding rule and the organizational unit the rule is shared with.

THE HUB ENDPOINT AND ITS SHARED RULE IN LANDING ZONE ACCELERATOR
# network-config.yaml (Landing Zone Accelerator on AWS)
centralNetworkServices:
  delegatedAdminAccount: Network
  route53Resolver:
    endpoints:
      - name: outbound-hub
        type: OUTBOUND
        vpc: shop-hub
        subnets:
          - hub-endpoints-a
          - hub-endpoints-b
        rules:
          - name: onprem
            domainName: shop.internal
            targetIps:
              - ip: 10.50.0.10
              - ip: 10.50.0.11
            shareTargets:
              organizationalUnits:
                - Workloads
STEP 02 / 05

A RULE SHARED IS AN ENDPOINT SHARED

Infrastructure · unit
shop-networkowns the rule
rule rslvr-rr-onprem · shop.internaloutbound endpoint · shared indirectly
AWS RAM shareone Region
Workloads · unit
shop-prodcan use the rule, can’t edit it
VPC✓ rule associated
shop-devthe same
VPC✓ rule associated
+ 37 moreaccounts
each VPC✓ rule associated
an account moved out of Workloads loses these associations, unless the rule is shared with its new unit too
Fig 5.2The share runs down the accent line from the network account to the Workloads unit. The association is still made per VPC.

AWS Resource Access Manager (RAM) is the service that lets one account share a resource it owns with others. shop-network uses it to share the forwarding rule rslvr-rr-onprem with the Workloads unit. A share can name single accounts, an organizational unit or the whole organization, and it stays within one Region.

Each receiving account then associates the rule with its own VPCs. It can use the rule and can’t edit it. The outbound endpoint behind the rule is shared indirectly: forwarded queries from every one of those VPCs leave through rslvr-out-hub, which the workload accounts never see.

Sharing with a unit has one catch. Move an account to a different unit, and its rule associations are deleted unless the rule is shared with the new unit too.

STEP 03 / 05

TWO COMMANDS AND NO CONSOLE

  1. 1
    shop-network · owns the zoneaws route53 create-vpc-association-authorizationnames the zone and the one VPC allowed to join it
  2. 2
    shop-prod · owns the VPCaws route53 associate-vpc-with-hosted-zonefails until the authorization from command 1 exists
  3. 3
    shop-network · owns the zoneaws route53 delete-vpc-association-authorizationtidies up; the association stays
commands 1 and 2 × 40 VPCs80 calls per zone
Route 53 consoleoffers neither
Fig 5.3Two accounts each run one command. The accent command is the VPC owner’s, and it fails until the authorization exists.

A private hosted zone is not a resource RAM can share. To let a VPC in another account read aws.shop.internal, the zone’s owner, shop-network, first runs create-vpc-association-authorization naming that VPC. The VPC’s owner, shop-prod, then runs associate-vpc-with-hosted-zone. Afterwards the zone’s owner deletes the authorization, and the association stays.

The Route 53 console offers neither step, so both are done with the CLI, an SDK or an infrastructure template. A zone accepts up to 300 VPCs. For the shop’s 40 VPCs the two required calls come to 80, and every new private zone repeats them.

AUTHORIZE IN ONE ACCOUNT, ASSOCIATE FROM THE OTHER, THEN CLEAN UP
# 1. In shop-network, which owns the zone:
aws route53 create-vpc-association-authorization \
  --hosted-zone-id Z0AWS1INTERNAL \
  --vpc VPCRegion=us-east-1,VPCId=vpc-0shopprod

# 2. In shop-prod, which owns the VPC:
aws route53 associate-vpc-with-hosted-zone \
  --hosted-zone-id Z0AWS1INTERNAL \
  --vpc VPCRegion=us-east-1,VPCId=vpc-0shopprod

# 3. Back in shop-network, remove the authorization:
aws route53 delete-vpc-association-authorization \
  --hosted-zone-id Z0AWS1INTERNAL \
  --vpc VPCRegion=us-east-1,VPCId=vpc-0shopprod

# Calls 1 and 2 for each of 40 VPCs = 80 calls for every zone.
STEP 04 / 05

ONE PROFILE INSTEAD OF 160 ASSOCIATIONS

BEFORE · 4 ASSOCIATIONS PER VPC
shop-prod VPC
  • private zone aws.shop.internal
  • rule rslvr-rr-onprem
  • firewall rule group rslvr-frg-egress
  • query log configuration
WITH A PROFILE · 1 ASSOCIATION PER VPC
shop-prod VPC
  • rp-shop-dnsRoute 53 Profile
    • private zone aws.shop.internal
    • rule rslvr-rr-onprem
    • firewall rule group rslvr-frg-egress
    • query log configuration
before: 40 VPCs × 4 kinds160 associations
with the Profile: 40 VPCs × 140 associations
one Profile, up to 100 VPCs$547.50/month
Fig 5.4Four kinds of association collapse into the accent Profile. Count the lines to each VPC: one, where there were four.

A , available since 2024-04-22, is one shareable object that holds DNS settings: private hosted zone associations, Resolver rules, DNS Firewall rule groups, interface endpoints and query-logging settings. shop-network builds one, rp-shop-dns, and shares it with RAM. Each account then associates it once with each VPC.

Before the Profile, each of the shop’s 40 VPCs needed 4 kinds of association: zone, rule, firewall rule group and query log. That is 160 associations, and the Profile replaces them with 40.

Since 2026-11-09 a VPC can take two Profiles, ordered by priority. A Profile costs $0.75 an hour for up to 100 VPCs, which is $547.50 a month.

STEP 05 / 05

WHO MAY CHANGE api.shop.example

  • the pipeline role asks toUPSERT api.shop.exampleallowedevery name in the batch is on the list
  • the pipeline role asks toUPSERT shop.examplerefusedone name off the list refuses the whole batch
EffectAllow
Actionroute53:ChangeResourceRecordSets
Resourcehostedzone/Z0SHOP1EXAMPLE
Conditionroute53:ChangeResourceRecordSetsNormalizedRecordNamesmay only be api.shop.example
Fig 5.5The accent Condition names one record. A change that touches any other name in the zone is refused whole.

The public zone shop.example lives in shop-network, but the production deploy pipeline has to update one record in it, api.shop.example. An IAM condition key, route53:ChangeResourceRecordSetsNormalizedRecordNames, limits a role to the record names you list. A change batch that touches any other name is refused whole, including the changes that would have been allowed.

A team that needs more than one record gets a zone of its own. dev.shop.example is a separate hosted zone in shop-dev, and one NS record in the parent zone delegates it. Service control policies, the organization-wide rules that cap what any account’s roles may do, stop workload accounts removing the shared associations.

None of this sent a DNS question. Shares, associations, Profiles and policies are all configuration, so the query count stays at 14.

ONE RECORD NAME, TWO RECORD TYPES, NOTHING ELSE IN THE ZONE
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": "route53:ChangeResourceRecordSets",
      "Resource": "arn:aws:route53:::hostedzone/Z0SHOP1EXAMPLE",
      "Condition": {
        "ForAllValues:StringEquals": {
          "route53:ChangeResourceRecordSetsNormalizedRecordNames": ["api.shop.example"],
          "route53:ChangeResourceRecordSetsRecordTypes": ["A", "AAAA"]
        }
      }
    }
  ]
}

WHAT YOU NOW KNOW

  • Control Tower builds accounts and guardrails but no DNS; the reference design keeps endpoints, rules and shared zones in one network account.
  • RAM shares Resolver rules, private zones need two API calls per VPC, and a Profile replaces 160 associations with 40.
  • Sharing sends no query, so the count stays at 14; IAM condition keys and service control policies decide who can change what.
deep dive: centralised endpoints, Landing Zone Accelerator, multi-Region DNS and guardrails

Centralised interface endpoints. Create the interface endpoint once, in the hub VPC, with private DNS off. Then create a private hosted zone named for the service, such as secretsmanager.us-east-1.amazonaws.com, with an alias record to the endpoint, and associate that zone with every VPC. Since 2025-04-28 a Profile can carry the endpoint instead. The trade-off is that one endpoint policy, at most 20,480 characters, now serves every account. The data centre reaches the same endpoints through the inbound endpoint.

Landing Zone Accelerator. LZA’s network-config.yaml expresses this chapter as configuration: centralNetworkServices.delegatedAdminAccount, route53Resolver.endpoints[] with their forwarding rules[] and shareTargets.organizationalUnits, queryLogs, firewallRuleGroups[], and per VPC useCentralEndpoints. Without LZA, the same associations are made when an account is created, by Account Factory customisations or CloudFormation StackSets.

Who owns the zones. In the central model every private zone lives in the network account and is associated outward. In the decentralised model each account owns its zone and associates it with the hub VPC, so the data centre can resolve it. Public subdomains are delegated the same way in both: an NS record in the parent zone.

More than one Region. Endpoints, rules and Profiles are Regional, and a RAM share stays within one Region, so each Region needs its own hub set. Private hosted zones are global and can be associated with VPCs in any Region.

Guardrails. Service control policies can deny route53resolver:DisassociateResolverRule, route53resolver:DisassociateFirewallRuleGroup, route53resolver:DeleteResolverQueryLogConfig and route53:DisassociateVPCFromHostedZone to every role but the network team’s. Security Hub control Route53.2 flags public hosted zones without query logging. A newer condition key, route53:VPCs, limits which VPCs a zone may be associated with.

On the exam

  • “manage DNS centrally for hundreds of VPCs in many accounts”Route 53 Profiles shared with RAM (before Profiles: RAM-shared rules plus per-VPC zone associations)
  • “share forwarding rules with every account”AWS RAM
  • “associate a private hosted zone with a VPC in another account”authorization, then association, by CLI or API
  • “cut the cost of the same interface endpoints in many VPCs”centralised endpoints with a private zone per service
  • “a team must manage its own subdomain”delegate it with NS records
  • “stop workload accounts removing DNS controls”service control policy
  • “a pipeline may update only one record”IAM condition keys on ChangeResourceRecordSets

A query you can refuse, and an answer you can verify

DNS has two weaknesses the last six chapters stepped around. A query leaves every VPC without passing a security group, so it can carry data out. And an answer arrives with no proof of who wrote it, so it can be forged. DNS Firewall, a filter built into the VPC resolver, closes the first. DNSSEC, a way of signing a zone’s records, closes the second. The checkout’s last two queries meet one each, and the query count goes from 14 to 16.

STEP 01 / 06

THE ONE EXIT EVERY SUBNET HAS

QUESTIONan example, not counted
aGVsbG8encoded data: “hello” in base64
.x.attacker.examplethe attacker’s domain
type A
asked by a compromised server · asked of the VPC resolver
longest name DNS allows253 characters
longest single label63 characters
  1. compromised serverin a subnet with no route to the internet
  2. the question
  3. VPC resolver10.0.0.2 · fetches the answer as for any name
  4. the whole name
  5. attacker’s name serverholds attacker.example · receives the whole name
Fig 6.1The accent label is the stolen data, encoded. The resolver passes the whole name to the name server the attacker runs.

A compromised server can encode stolen data as one label of a name and then look that name up: aGVsbG8.x.attacker.example. The label aGVsbG8 is the word “hello” in base64. The server sends the question to the VPC resolver at 10.0.0.2, as it does for every name, and neither security groups nor network ACLs filter traffic to that address.

The VPC resolver fetches the answer from the internet as it would for any public name. That means asking the name server for attacker.example, which the attacker runs, and handing it the whole name. This is DNS tunnelling: data carried out inside the question itself. It works from a subnet with no route to the internet, because the resolver makes the outside connection.

The channel is narrow, and by default it is open in every subnet. A name can be 253 characters long, with each label up to 63, so one lookup carries a couple of hundred characters of payload. The checkout sends no such query, so the query count is still 14.

STEP 02 / 06

AN ALLOW LIST FOR NAMES

query #15 · from the app serverapi.payments.example→ matches rule 100: ALLOW
the encoded name from step 1aGVsbG8.x.attacker.example→ falls through to rule 200: BLOCK
rslvr-frg-egress · DNS Firewall rule group
associated with the shop-prod VPC · lowest priority number is checked first
priorityactiondomain list
100ALLOWshop-allowedthe names the checkout needs
200BLOCKanswers NXDOMAIN*every other name
the first rule that matches decides; later rules are not read
Fig 6.2Two queries meet the rule group. The checkout’s stops at the accent ALLOW row; the encoded one falls through to BLOCK.

checks every query the VPC resolver receives against the rule groups associated with the VPC. Rules run in priority order, lowest number first, and the first rule whose domain list matches the name decides. There are three actions: ALLOW, ALERT (which lets the query through and logs it) and BLOCK. A block answers with NODATA, NXDOMAIN or a substitute name you choose.

The shop’s group, rslvr-frg-egress, has two rules. Priority 100 allows the domain list shop-allowed, and priority 200 blocks *, every other name, with NXDOMAIN. At 14:02:07 the app server looks up api.payments.example. Rule 100 matches, the resolver fetches the answer from public DNS, and the server gets 203.0.113.80. That is query #15. The encoded name from step 1 reaches rule 200 and gets NXDOMAIN.

DNS Firewall costs $0.60 per million queries it inspects. AWS also maintains managed domain lists of known malware and botnet domains, which any rule can reference at no extra charge. Their contents stay private: you can use a list, but no API call returns the domains in it.

AN ALLOW RULE AT PRIORITY 100, THEN A BLOCK FOR EVERY OTHER NAME
# The lowest priority number is evaluated first.
aws route53resolver create-firewall-rule \
  --firewall-rule-group-id rslvr-frg-egress \
  --firewall-domain-list-id rslvr-fdl-shopallowed \
  --name allow-shop-domains \
  --priority 100 \
  --action ALLOW

# The list rslvr-fdl-everything holds one entry: *
aws route53resolver create-firewall-rule \
  --firewall-rule-group-id rslvr-frg-egress \
  --firewall-domain-list-id rslvr-fdl-everything \
  --name block-the-rest \
  --priority 200 \
  --action BLOCK \
  --block-response NXDOMAIN
STEP 03 / 06

THE QUERY THAT NEVER REACHES THE FIREWALL

app server10.0.10.27a process on it picks where to ask
sent to the VPC resolver · every name is checked
  1. VPC resolver10.0.0.2
  2. DNS Firewallrslvr-frg-egress checks the name
  3. public DNSasked only if a rule allows
sent to any other resolver · DNS Firewall never sees it
  1. security group / Network Firewallthe only gate on this path: close outbound ports 53 and 853 here
  2. 8.8.8.8:53a public resolver, asked directly
same side path: DNS over TLS on port 853 · DNS over HTTPS on port 443
Fig 6.3Two paths leave the server. Only one crosses the firewall; the accent path to 8.8.8.8 needs a network rule to close it.

A DNS Firewall rule group sits on one path: from a server to the VPC resolver at 10.0.0.2. A process that addresses its question to 8.8.8.8 on port 53 is making an ordinary internet connection, and no rule in the group runs. The same holds for DNS over TLS on port 853, and for DNS over HTTPS, which travels on port 443 like any other web request.

Closing the side path takes network rules. Leave outbound ports 53 and 853 closed in security groups, or deny them in network ACLs. Lookups through the VPC resolver keep working, because neither filter applies to its address. For DNS over HTTPS, AWS Network Firewall can block the known resolver hosts by name. GuardDuty has the same blind spot: its DNS findings cover only queries the VPC resolver handled.

One setting covers the case where DNS Firewall itself can’t evaluate a query. The default is to fail closed: the query is answered with SERVFAIL, so a broken filter stops lookups and never lets them pass unchecked. A VPC can be set to fail open when availability matters more than filtering.

STEP 04 / 06

A SIGNATURE ON EVERY ANSWER

QUESTIONquery #3
shop.exampletype A
asked by customer’s resolver · asked of ns-2051.awsdns-67.co.uk
ANSWER
  • A198.51.100.201TTL 60 s
  • A198.51.100.202TTL 60 s
  • RRSIGsignature over the two A rows
    algorithm 13 · made with the zone-signing key
  1. KMS keyalias/shop-dnssec-kskyours · asymmetric ECC_NIST_P256 · us-east-1
    backs
  2. key-signing keyshop_ksk_2026signs the zone’s set of public keys
    signs
  3. zone-signing keycreated and managed by Route 53signs every record set in the zone
    signs each answer: the RRSIG row
Fig 6.4The answer now has two parts. The accent RRSIG row is a signature over the address rows, made with the zone-signing key.

With signing on, Route 53 returns a signature record, type RRSIG, with every answer from shop.example to any resolver that asks for signatures. The signature covers the address records and is made with a zone-signing key that Route 53 creates and manages. A resolver holding the matching public key can check that the answer came from the zone and wasn’t altered on the way.

The zone-signing key is signed in turn by a key-signing key, shop_ksk_2026, backed by a KMS key you own. That key must be customer managed and asymmetric, with key spec ECC_NIST_P256, and it has to be created in us-east-1 wherever the application runs. The AWS KMS tutorial covers asymmetric keys and the key policy that admits a service like Route 53.

To check the signature on answer #3, the customer’s resolver needs the zone’s public keys. At 14:01:30 it asks Route 53 for the DNSKEY records of shop.example: query #16. Signing is available for public hosted zones only, and Route 53 adds no charge for it. The KMS key is billed by AWS KMS.

THREE CALLS: A KMS KEY, A KEY-SIGNING KEY, THEN SIGNING
# 1. The KMS key: asymmetric, ECC_NIST_P256, and in us-east-1.
aws kms create-key --region us-east-1 \
  --key-spec ECC_NIST_P256 \
  --key-usage SIGN_VERIFY

# 2. Make it the key-signing key of the zone.
aws route53 create-key-signing-key \
  --hosted-zone-id Z0SHOP1EXAMPLE \
  --name shop_ksk_2026 \
  --status ACTIVE \
  --caller-reference shop-ksk-2026 \
  --key-management-service-arn arn:aws:kms:us-east-1:777788889999:key/1234abcd-12ab-34cd-56ef-1234567890ab

# 3. Start signing. Nothing validates until the DS record
#    is added at the registrar.
aws route53 enable-hosted-zone-dnssec --hosted-zone-id Z0SHOP1EXAMPLE
STEP 05 / 06

A CHAIN THAT ENDS AT ONE KEY

root zonekey tag 38696, in use since 2026-10-11its public key is built into every validating resolver
DS record for .examplea hash of the registry’s key, held in the root zone
.example registrythe registry’s own keysthey sign every DS record the registry holds
DS record for shop.examplea hash of shop_ksk_2026, held by the registry · you add it through the registrar
shop.examplekey-signing key shop_ksk_2026signs the zone-signing key, which signs each answer
Fig 6.5Read from the bottom: each key is vouched for one level up. You add the accent link at the registrar.

A signature proves nothing until someone vouches for the key that made it, because a forger can sign with a key of their own. So the .example registry holds a DS record for shop.example: a hash of the shop’s key-signing key, which the shop submits through its registrar. The registry signs that record with its own key.

The same step repeats one level up. The root zone holds a DS record for .example, and every validating resolver ships with the root’s public key. Each key is vouched for by the zone above until the chain reaches a key the resolver already holds. That is the chain of trust. The root’s key changed on 2026-10-11, from key tag 20326 to key tag 38696, only its second change ever.

Order matters at both ends. To start, turn signing on first and add the DS record afterwards. A DS record that points at a key the zone doesn’t publish yet makes every validating resolver reject the zone. To stop, remove the DS record, wait out its TTL, and only then stop signing.

STEP 06 / 06

WHEN THE KEY GOES MISSING

CloudWatch alarms on these two metrics fire at the start of the bar:
DNSSECInternalFailureDNSSECKeySigningKeysNeedingAction
KMS key disabled
  • signatures made in advance are still validthe next few days
  • validating resolvers refuse the domainuntil signing resumes
segment lengths are not to scale: AWS gives no exact number of days
  1. #15app server → VPC resolverapi.payments.example · DNS Firewall allows it; public DNS: 203.0.113.80
  2. #16customer’s resolver → Route 53shop.example (DNSKEY) · public zone: the zone’s public keys
queries so far16
Fig 6.6The bar starts when the key is disabled. The accent segment is the signatures made in advance; lookups fail where it ends.

The key-signing key works only while Route 53 can use the KMS key behind it. Disable that key, schedule it for deletion, or change its key policy so that Route 53 is no longer admitted, and Route 53 can’t sign the zone’s keys again. The zone keeps answering at first. Route 53 holds signatures it made in advance, and they stay valid for the next few days.

When the last of them expires, every validating resolver refuses answers for shop.example, while resolvers that don’t validate keep resolving it. The outage arrives days after the change that caused it, and only for some customers. Two CloudWatch metrics report the problem well before that, so put an alarm on each: DNSSECInternalFailure and DNSSECKeySigningKeysNeedingAction.

Validating is a separate choice from signing. Inside a VPC it is a per-VPC setting on the VPC resolver, and the shop has it on, so the payment answer in step 2 was validated before the app server got it. That completes the chapter’s tally. Query #15, checked by DNS Firewall, and query #16, the key lookup, take the query count from 14 to 16.

WHAT YOU NOW KNOW

  • DNS Firewall checks each query sent to the VPC resolver against prioritised domain lists; an allow list followed by a block-all rule stops tunnelling.
  • It never sees queries sent to other resolvers, so outbound port 53, port 853 and DNS over HTTPS need network rules.
  • DNSSEC signs answers with a KMS-backed key in us-east-1 and a DS record at the registry. Queries #15 and #16 make 16.
deep dive: subdomain takeover, DNS Firewall across an organization, DNSSEC operations and GuardDuty

Dangling records and subdomain takeover. A CNAME or alias left pointing at a deleted S3 website bucket, a terminated Elastic Beanstalk environment or a released Elastic IP is a dangling record. Whoever claims that resource next serves content under your name. AWS’s guidance (Security Blog, 2026-06-16) is to delete the DNS record first, wait for its TTL, then delete the resource. S3 buckets created in account regional namespaces, available since March 2026, can’t be claimed by another account. Route 53 protects one case itself: it won’t give a deleted zone’s name servers to another customer while the parent zone still lists them.

DNS Firewall across an organization. Deploy rule groups with AWS Firewall Manager or inside a Route 53 Profile. A VPC takes up to five rule groups, and a group holds 100 rules. Start each rule in ALERT, read the logs, then switch it to BLOCK. A rule can match a single query type, such as TXT, which tunnels favour, and it can inspect every name in a CNAME chain. DNS Firewall Advanced, launched 2024-11-15, detects algorithm-generated domains and tunnelling by behaviour, at $0.16 an hour per rule group per VPC. Fail open is a per-VPC setting for when availability outranks filtering.

DNSSEC operations. Route 53 signs with algorithm 13, ECDSA P-256 with SHA-256. A zone holds at most two key-signing keys, and you rotate by adding the second, publishing its DS record, then retiring the first. TTLs are capped at one week in a signed zone. Before enabling signing, lower the zone’s longest TTL to an hour and wait that long. Private hosted zones can’t be signed. The VPC resolver validates signed public names when the VPC’s setting is on, but it returns no signatures to clients and doesn’t validate forwarded queries.

GuardDuty’s DNS findings. GuardDuty reads the VPC resolver’s query stream whether or not query logging is on. Its finding types include Backdoor:EC2/C&CActivity.B!DNS, Trojan:EC2/DNSDataExfiltration, Trojan:EC2/DGADomainRequest.B, CryptoCurrency:EC2/BitcoinTool.B!DNS and Impact:EC2/MaliciousDomainRequest.Reputation. Use of outside resolvers shows up from flow logs instead: DefenseEvasion:EC2/UnusualDNSResolver, UnusualDoHActivity and UnusualDoTActivity.

Hijack and flooding. Keep transfer lock on the domain and the registrar account behind MFA, because whoever can change the name servers at the registrar controls every answer. Shield Standard protects Route 53 at no charge, and Shield Advanced adds hosted zones as protected resources.

On the exam

  • “prevent data exfiltration over DNS”DNS Firewall allow list with a block-all rule, plus network rules against other resolvers
  • “block known-malicious domains in every account”AWS managed domain lists deployed with Firewall Manager
  • “DNS filtering must never take the application down”fail open
  • “DNS filtering must never be bypassed by a failure”fail closed, the default
  • “protect a public domain against forged answers”DNSSEC signing and a DS record at the registrar
  • “which KMS key for DNSSEC”customer managed, asymmetric ECC_NIST_P256, in us-east-1
  • “validate DNSSEC for workloads in a VPC”turn on validation for that VPC
  • “a decommissioned site’s subdomain now shows someone else’s content”dangling record; delete DNS before the resource
  • “detect hosts using outside or encrypted DNS”GuardDuty UnusualDNSResolver and UnusualDoHActivity

Sixteen queries, three logs, and four that no log has

Sixteen queries were asked for this checkout, by a phone, a public resolver, an app server and a warehouse system. No single log holds all of them, and four were answered on servers the shop doesn’t run. This chapter places each query in the log that records it: the query log of the public zone, the Resolver query log inside the VPC, and the data centre’s own DNS log. The query count holds at 16, because logs record queries and ask none.

STEP 01 / 05

ONE LINE PER QUERY THAT REACHED ROUTE 53

  1. 1.0log format version
  2. 2026-11-13T14:02:07Ztime, UTC
  3. Z0SHOP1EXAMPLEhosted zone ID
  4. api.shop.examplequery name
  5. Aquery type
  6. NOERRORresponse code
  7. UDPprotocol
  8. IAD89-C1edge location
  9. 192.0.2.53resolver address
  10. 203.0.113.0/24client subnet
query #5, one line in the log group of shop.exampleedge location: an airport code near the Route 53 site that answered, and a numberclient subnet: the phone’s network, as its resolver sent it · the phone is 203.0.113.50
Fig 7.1Each field is labelled under its value. The accent field is the resolver’s address, the only asker Route 53 ever sees.

Query logging for a public hosted zone writes one line for each query Route 53 receives. The lines go to CloudWatch Logs only, and the log group must be in us-east-1. A line has ten space-separated fields: a format version, the time, the zone ID, the name, the record type, the response code, the protocol, the edge location that answered, the resolver’s address, and the client subnet if the resolver sent one.

The line for query #5 ends 192.0.2.53 203.0.113.0/24. The first value is the customer’s resolver. The second is the phone’s network, cut to a /24 by that resolver before it asked. The phone’s own address, 203.0.113.50, appears nowhere in the line. The field IAD89-C1 names the Route 53 edge location that answered.

A lookup that a resolver answers from its cache never reaches Route 53, so it never produces a line. Of the checkout’s 16 queries, 4 reached Route 53 and have a line here: #3, #5, #7 and #16.

STEP 02 / 05

THE LOG THAT NAMES THE INSTANCE

RESOLVER QUERY LOG RECORD · QUERY #15
query_nameapi.payments.example.
query_typeA
rcodeNOERROR
answers203.0.113.80 (A)
srcaddr10.0.10.27
srcids.instancei-0abc1234def567890
an allowed query: the record has no firewall fields
the blocked query from chapter 06 would add three fieldsaGVsbG8.x.attacker.example
firewall_rule_actionBLOCK
firewall_rule_group_idrslvr-frg-egress
firewall_domain_list_idrslvr-fdl-everything
Fig 7.2The accent field, srcids.instance, ties the query to one server. The three firewall fields appear only when a rule alerted or blocked.

Resolver query logging records the queries the VPC resolver handles: those from servers in the VPC, those arriving from the data centre through an inbound endpoint, and those it forwards out. Each one becomes a JSON record in CloudWatch Logs, S3 or Amazon Data Firehose. One configuration can be shared across accounts, so the shop’s 40 VPCs log to one bucket in shop-logs. Route 53 charges nothing for it.

The record for query #15 holds the question in query_name and query_type, the result in rcode and answers, and the asker twice. srcaddr is the address 10.0.10.27, and srcids.instance is the EC2 instance ID. An address can belong to a different server by tomorrow. The instance ID still identifies this one.

Three more fields, firewall_rule_action, firewall_rule_group_id and firewall_domain_list_id, exist only on records whose query matched an ALERT or BLOCK rule. Allowed queries carry no firewall fields. Query #15 matched the ALLOW rule at priority 100, so its record has none of the three. The blocked name from chapter 06 would have all of them.

QUERY #15 AS THE RESOLVER QUERY LOG RECORDS IT
{
  "version": "1.100000",
  "account_id": "111122223333",
  "region": "us-east-1",
  "vpc_id": "vpc-0shopprod",
  "query_timestamp": "2026-11-13T14:02:07Z",
  "query_name": "api.payments.example.",
  "query_type": "A",
  "query_class": "IN",
  "rcode": "NOERROR",
  "answers": [{ "Rdata": "203.0.113.80", "Type": "A", "Class": "IN" }],
  "srcaddr": "10.0.10.27",
  "srcport": "41622",
  "transport": "UDP",
  "srcids": { "instance": "i-0abc1234def567890" }
}
STEP 03 / 05

A CACHED ANSWER LEAVES NO LINE

  • Resolver query logrecords: the first query for a namenever records: repeats answered from the resolver’s cache
  • public zone query logrecords: queries that reach Route 53never records: lookups an outside resolver answered from its cache
  • VPC flow logsrecords: other traffic in the VPCnever records: DNS to the VPC resolver
  • CloudTrailrecords: changes to records and zonesnever records: queries
Fig 7.3Four sources, four blind spots. The accent row is the one people don’t expect: repeat queries answered from cache.

Every log source has a blind spot, and the Resolver query log’s is the least expected. AWS’s documentation says it holds “only unique queries”: when the VPC resolver answers from its cache, it writes no record. So the number of records for a name depends on its TTL as much as on how often servers ask. The public zone’s log has the same gap one level out: it misses whatever outside resolvers answered from cache.

The other two sources miss DNS questions altogether. VPC flow logs skip traffic to the VPC resolver entirely, as the AWS VPC tutorial shows for this same shop. CloudTrail records API calls, so it shows who changed a record and never who asked for one.

Counting log lines therefore undercounts queries, sometimes by thousands to one for a busy name. The logs tell you which names were asked, by whom, and what came back. They don’t tell you how often.

STEP 04 / 05

FOUR QUERIES IN NO LOG YOU OWN

  • Resolver query log6 queries
    queries #8 #9 #10 #11 #14 #15
  • Route 53 public zone query log4 queries
    queries #3 #5 #7 #16
  • the data centre’s DNS server log2 queries
    queries #12 #13
  • no log you own4 queries
    queries #1 #2 #4 #6
queries, each placed in one row16
Fig 7.4Each bar counts the queries one log would show. The accent bar is the four that no log of the shop’s records.

Place all 16 queries in the log that records them. The Resolver query log has 6: every question the app server sent to 10.0.0.2, plus the one that arrived through the inbound endpoint. The public zone’s query log has 4. The data centre’s DNS servers logged 2, in a log the shop owns and AWS never sees.

The other 4 were answered on servers the shop doesn’t run. Queries #1, #4 and #6 went from the phone to its resolver, and #2 went from that resolver to the .example registry. If one of them got a wrong answer, no log of the shop’s would show it.

For those the evidence is indirect. A health check or a synthetic probe run from outside shows whether the name resolves from where the probe sits. The public zone’s log shows a failure by omission: the line that should have followed, such as #3 after #2, and didn’t.

STEP 05 / 05

ASK THE NAME SERVER, SKIP THE CACHE

$ aws route53 test-dns-answer
  • --hosted-zone-id Z0SHOP1EXAMPLE
  • --record-name api.shop.example
  • --record-type A
  • --resolver-ip 192.0.2.53the customer’s resolver
  • --edns0-client-subnet-ip 203.0.113.50the customer’s phone
RESPONSE · WHILE US-EAST-1 IS UNHEALTHY
Nameserverns-2048.awsdns-64.com
RecordNameapi.shop.example
RecordTypeA
RecordData198.51.100.140 · us-west-2
ResponseCodeNOERROR
ProtocolUDP
no query was sent to any name server · public hosted zones only
Fig 7.5The command names a resolver and a client subnet. The accent line of output is the answer that pair would get.

Two tools take caches out of the question. dig @ns-2048.awsdns-64.com api.shop.example sends the question straight to one of the zone’s four name servers, so the answer is what Route 53 holds now and not what a resolver cached a minute ago. It still depends on where you run it, because a latency record is chosen by the asker’s location.

aws route53 test-dns-answer removes that dependence. You supply a resolver address and a client subnet, and Route 53 reports the answer that pair would get, without any query being sent. It works for public hosted zones only. Run it during the outage with the customer’s resolver and phone, and the response holds 198.51.100.140, the us-west-2 address.

With caches ruled out, work down the path in order. Do the registry’s name servers match the zone’s? Is the health check healthy, and if not, what is its last failure reason? Which Resolver rule or hosted zone matched the name? Or is the answer correct and only old, still inside its TTL on some resolver?

WHAT ROUTE 53 WOULD ANSWER ONE RESOLVER, WITH NO QUERY SENT
# What would Route 53 answer this resolver, for this customer?
aws route53 test-dns-answer \
  --hosted-zone-id Z0SHOP1EXAMPLE \
  --record-name api.shop.example \
  --record-type A \
  --resolver-ip 192.0.2.53 \
  --edns0-client-subnet-ip 203.0.113.50

# From the response, while us-east-1 is unhealthy:
#   "Nameserver": "ns-2048.awsdns-64.com",
#   "RecordData": ["198.51.100.140"],
#   "ResponseCode": "NOERROR",
#   "Protocol": "UDP"
# Works for public hosted zones only.

WHAT YOU NOW KNOW

  • Public zone logs go to CloudWatch Logs in us-east-1 and show the resolver’s address; Resolver query logs show the instance ID and any firewall block.
  • Cached answers leave no line in either log, and VPC flow logs skip DNS to the VPC resolver.
  • Of the 16 queries, 6 are in the Resolver log, 4 in the public zone log, 2 in the data centre’s, and 4 in none you own.
deep dive: metrics and alarms, central logging in a landing zone, and reading response codes

Metrics and alarms. Each public zone has DNSQueries. Each health check has HealthCheckStatus and HealthCheckPercentageHealthy, and the console shows its last failure reason. Each Resolver endpoint has InboundQueryVolume, OutboundQueryVolume and EndpointUnhealthyENICount. Since 2025-12-15 an endpoint can also report one-minute counts of SERVFAIL, NXDOMAIN and timeouts, if you opt in.

Central logging in a landing zone. Use one Resolver query-log configuration, owned by the network account and delivering to S3 in the logging account. Share it with AWS RAM or carry it in the Profile. An account can hold 20 configurations per Region. Query the records with Athena or CloudWatch Logs Insights. Public zone logs need a CloudWatch Logs resource policy, and an account can hold only 10 of those, which is why AWS suggests one /aws/route53/ prefix for every zone’s log group.

Reading response codes. NOERROR with an empty answer, called NODATA, means the name exists and that record type doesn’t. NXDOMAIN means the name doesn’t exist in the zone that answered, so check which zone answered. SERVFAIL means the resolver couldn’t finish. Common causes are an unreachable forwarding target and DNS Firewall failing closed, and validating resolvers in general answer SERVFAIL when a DNSSEC check fails. REFUSED means the server won’t answer that asker.

Auditing changes. CloudTrail records ChangeResourceRecordSets and every association call. Route 53 is a global service, so its events land in us-east-1.

On the exam

  • “find which instance queried a malicious domain”Resolver query logs, srcids.instance
  • “log queries for a public hosted zone”query logging to CloudWatch Logs in us-east-1
  • “collect DNS logs from every account in one place”one Resolver query-log configuration shared with RAM or a Profile, delivering to S3 in the logging account
  • “who changed this record”CloudTrail
  • “flow logs show no DNS traffic”flow logs exclude the VPC resolver
  • “confirm what users on a given network are answered”test-dns-answer with a resolver address and client subnet

Sixteen queries, and who answered each one

One checkout and one outage, counted once more. The first block sorts the 16 queries by the name being looked up, the second by the server that sent the answer back. The third is the one to keep for troubleshooting: which log records each query, and the 4 that no log of the shop’s records at all.

ONE CHECKOUT · SHOP.EXAMPLE · 14:00:05–14:07:40
BY NAME
shop.example4 queries
api.shop.example4 queries
stock.shop.internal2 queries
orders.aws.shop.internal2 queries
db.aws.shop.internal1 query
secretsmanager.us-east-1.amazonaws.com1 query
shop-receipts.s3.us-east-1.amazonaws.com1 query
api.payments.example1 query
WHO ANSWERED
the VPC resolver6 queries
from a private hosted zone2 of the 6
from an endpoint’s managed zone1 of the 6
from public DNS2 of the 6
by forwarding to the data centre1 of the 6
Route 53 public name servers4 queries
the customer’s resolver3 queries
the data centre’s DNS servers2 queries
the .example registry1 query
WHICH LOG RECORDS IT
Resolver query log6 queries
Route 53 public zone query log4 queries
the data centre’s DNS server log2 queries
no log you own4 queries
DNS queries for one checkout16
WHERE EACH EXAM LOOKS
Read next. AWS VPC: how one request crosses a private network for what happens to the packets once a name has become an address, and What happens when you press Enter for the walk down from the DNS root that query #2 skipped.
status NOERROR · answers 1 · TTL 60 s