The bfstore production application needs to send telemetry to its self-hosted observability platform.
The observability service currently has this private address:
10.96.12.45
I could place that address directly in the application configuration:
telemetry:
endpoint: 10.96.12.45:4317
That works until the service moves, a load balancer replaces it, recovery activates another destination or somebody must remember what 10.96.12.45 represents.
An address identifies a current network location.
The application needs a stable service identity:
otel.prod.aws.internal.bfstore.example
The name can point to:
- an internal load balancer;
- a PrivateLink interface endpoint;
- one or more intentional private addresses;
- another Route 53 record;
- a failover destination.
The application keeps the service name.
DNS absorbs the change in location.
BFSTORE APPLICATION
│
│ query:
│ otel.prod.aws.internal.bfstore.example
▼
ROUTE 53 VPC RESOLVER
│
▼
PRIVATE DNS VIEW
│
▼
PRIVATE SERVICE DESTINATION
A Route 53 private hosted zone contains records that Route 53 VPC Resolver can use to answer queries for a domain and its subdomains. The private answer is available through the resolver contexts to which the zone is distributed, traditionally by direct VPC association and now also through Route 53 Profiles. AWS describes the basic private hosted-zone model here.
A private hosted zone gives selected resolver views a private interpretation of a DNS namespace.
This article covers VPC DNS through direct associations, Profiles and Resolver rules and endpoints. Route 53 Global Resolver is outside scope. AWS documents it separately.
Private DNS is one part of private service access
Suppose bfstore creates:
prod.aws.internal.bfstore.example
with these records:
orders.prod.aws.internal.bfstore.example
payments.prod.aws.internal.bfstore.example
otel.prod.aws.internal.bfstore.example
The zone tells Route 53 how to answer those names.
It does not establish a route to the returned address.
If:
otel.prod.aws.internal.bfstore.example
resolves to:
10.96.12.45
the client still needs a network path to 10.96.12.45.
That path may use:
- local VPC routing;
- Transit Gateway;
- VPC peering;
- AWS PrivateLink;
- another private network connection.
Security groups, network ACLs, firewalls and application authentication must also permit the connection.
| Control | Question |
|---|---|
| Private DNS | Where should this name lead? |
| Route table | Can the destination address be reached? |
| Network policy | May this source establish the connection? |
| Application identity | May this caller perform the operation? |
DNS is not private access control. A strong design provides both a stable name and an intentional access path.
How the private namespace reaches a VPC
A private hosted zone must be associated with a VPC when it is created. More VPCs can be associated afterwards. The associated VPCs require enableDnsSupport and enableDnsHostnames to be enabled for private hosted-zone resolution. AWS documents those VPC requirements and the matching behaviour.
There are now two principal ways to distribute the namespace.
Direct hosted-zone association
The zone is associated directly with each consuming VPC.
PRIVATE HOSTED ZONE
prod.aws.internal.bfstore.example
│
├── bfstore-prod VPC
├── bfstore-observability VPC
└── bfstore-backup VPC
This model is explicit and works well when the VPC inventory is modest or when each association needs individual approval.
Route 53 Profile
A Route 53 Profile can collect DNS configuration and apply it to many VPCs, including VPCs in other accounts through AWS Resource Access Manager.
Profiles can distribute:
- private hosted-zone associations;
- Resolver rules;
- DNS Firewall rule groups;
- Resolver query-logging configurations.
A VPC can have one Profile association. When local VPC DNS configuration conflicts with Profile-delivered configuration, the local configuration takes precedence; the most-specific matching domain still determines the winner where names differ in specificity. AWS documents Profile resources and precedence here.
ROUTE 53 PROFILE
production-dns
│
├── private hosted zones
├── Resolver rules
├── DNS Firewall policies
└── query logging
│
├── prod VPC
├── observability VPC
└── backup VPC
A useful choice is:
| Model | Best fit |
|---|---|
| Direct association | Smaller estate, explicit per-VPC control, exceptional namespace |
| Route 53 Profile | Repeated DNS configuration across many VPCs and accounts |
The association mechanism defines resolution scope: which resolver views receive the namespace. It does not authorise workloads to use the services behind the records.
Transit Gateway does not distribute DNS
Suppose the production and observability VPCs are attached to the same Transit Gateway.
The routes work:
BFSTORE PROD VPC
│
▼
TRANSIT GATEWAY
│
▼
OBSERVABILITY VPC
That does not automatically make a private hosted zone available to production.
Transit Gateway provides Layer 3 connectivity.
A direct zone association, Route 53 Profile or deliberate forwarding design determines whether the source resolver view receives the private answer.
TRANSIT GATEWAY
Can the returned address
be reached?
DNS CONFIGURATION
Can this resolver view
obtain the private answer?
Routing joins address spaces. DNS configuration joins naming views.
They must often be designed together, but they are not the same control plane.
Workloads query Route 53 VPC Resolver
Workloads do not normally query the private zone’s displayed name servers directly.
They send queries to Route 53 VPC Resolver, the recursive DNS service available in each VPC. VPC Resolver answers local VPC names, associated private hosted zones and public recursive queries, and applies matching Resolver rules. AWS describes the resolver path here.
WORKLOAD
│
▼
ROUTE 53 VPC RESOLVER
│
├── local VPC names
├── private hosted zones
├── Resolver rules
└── public recursive resolution
The ordinary DHCP option set normally directs resources towards AmazonProvidedDNS. Custom first-hop DNS servers need conditional forwarding, commonly through Resolver inbound endpoints, for names AWS should answer.
How VPC Resolver chooses the winning answer
Most private DNS mistakes become easier to understand when resolution is treated as a selection process.
The resolver considers:
- local and Profile-delivered DNS configuration;
- matching Resolver rules;
- matching private hosted zones;
- namespace specificity;
- record presence;
- public recursion only when no private namespace or rule claims the query.
Split-view DNS
Route 53 can use public and private hosted zones with the same name.
PUBLIC ZONE
bfstore.example
PRIVATE ZONE
bfstore.example
An internet client receives the public view.
A client using VPC Resolver in a resolver view containing the private zone receives the private view.
INTERNET CLIENT
│
▼
PUBLIC ZONE
│
▼
PUBLIC ENDPOINT
VPC CLIENT
│
▼
PRIVATE ZONE
│
▼
PRIVATE ENDPOINT
The zones do not share or inherit records.
A matching private zone prevents public fallback
Suppose the public zone contains:
docs.bfstore.example
The production resolver view also contains a private zone:
bfstore.example
but that private zone does not contain the docs record.
VPC Resolver finds a matching private namespace, searches it and returns NXDOMAIN.
It does not retry against the public zone. AWS documents this behaviour explicitly.
QUERY
docs.bfstore.example
│
▼
MATCHING PRIVATE ZONE
bfstore.example
│
▼
RECORD ABSENT
│
▼
NXDOMAIN
A broad same-name private zone claims authority over the complete branch for that resolver view.
If internal clients still need public records, bfstore must:
- reproduce the required records privately;
- use a narrower private namespace;
- redesign forwarding;
- avoid creating the overlapping private zone.
The most-specific namespace wins
A resolver view may contain:
internal.bfstore.example
prod.internal.bfstore.example
payments.prod.internal.bfstore.example
For:
authorise.payments.prod.internal.bfstore.example
the most-specific matching zone is:
payments.prod.internal.bfstore.example
VPC Resolver searches that zone.
If the record is absent, it does not continue upwards and search the less-specific zones for the same record. AWS documents most-specific matching for overlapping private zones.
This allows independent authority for narrower namespaces, but can also create accidental shadowing. Review a new, more-specific zone like a routing change.
The word “delegation” should be reserved for designs that actually use DNS delegation semantics. A separately associated child private hosted zone can become the winning authority without the parent zone containing an NS delegation.
A Resolver rule can override the hosted zone
Suppose a VPC has:
Private hosted zone:
corp.example
Forwarding rule:
corp.example
→ enterprise DNS
The forwarding rule takes precedence over the private hosted zone.
Resolver also chooses the most-specific matching rule when several rules apply. AWS documents rule selection and private-zone interactions here.
QUERY
service.corp.example
│
▼
MATCHING FORWARD RULE
corp.example
│
▼
ENTERPRISE DNS
A correct private record can remain unused because a rule intercepted the namespace. Troubleshooting must inspect both zones and rules.
Choose zone boundaries around ownership and audience
One possible design is a broad zone:
internal.bfstore.example
It could contain production, non-production and platform records.
That minimises the number of zones.
It also centralises every change beneath one authority.
A more separated design might use:
prod.aws.internal.bfstore.example
nonprod.aws.internal.bfstore.example
platform.aws.internal.bfstore.example
Separate a zone when the namespace needs a different owner, audience, IAM policy, change lifecycle or incident boundary. Production records should not normally share the everyday development DNS role.
The displayed hierarchy does not imply that the zones are automatically delegated to one another. Each zone becomes authoritative in resolver views where it is directly or indirectly associated, subject to the resolver’s selection rules.
Names should express durable service identity rather than incidental infrastructure.
Prefer:
orders.prod.aws.internal.bfstore.example
over:
orders-eks-cluster-3-subnet-a.prod...
The service may move between clusters without requiring every client to learn a new name.
Records should point to durable service boundaries
Private hosted zones support ordinary Route 53 record types and alias records.
Common bfstore patterns include:
Internal load balancer
orders.prod.aws.internal.bfstore.example
→ internal ALB or NLB alias
PrivateLink endpoint
otel.prod.aws.internal.bfstore.example
→ interface endpoint alias
Database endpoint
mysql.orders.prod.aws.internal.bfstore.example
→ RDS endpoint through CNAME where appropriate
Intentional private address
legacy.prod.aws.internal.bfstore.example
→ 10.80.40.25
Alias records can target supported AWS resources and can be used at a zone apex. A CNAME cannot be used at the apex and cannot coexist with other data at the same owner name. AWS compares aliases and CNAME records here.
Use direct IP records only for intentionally stable, owned addresses, not as an inventory of ephemeral Kubernetes Pods.
KUBERNETES-INTERNAL DISCOVERY
use Kubernetes Service and cluster DNS
VPC OR CROSS-VPC BOUNDARY
consider Route 53 private DNS
Private hosted zones are strongest at durable service boundaries. Publishing a record does not grant permission to use the service.
DNS
discover the destination
NETWORK POLICY
permit the connection
SERVICE IDENTITY
authorise the operation
A useful internal name is a stable label, not an invitation.
TTL and alias records need different treatment
DNS resolvers cache ordinary record answers according to the record’s time to live.
RECORD CHANGED
│
▼
ROUTE 53 HAS NEW ANSWER
│
▼
CACHE MAY HOLD OLD ANSWER
│
▼
TTL EXPIRES
│
▼
CLIENT QUERIES AGAIN
Shorter TTLs make changes visible sooner; longer TTLs reduce query frequency. Alias records do not always expose a configurable TTL.
- When an alias points to an AWS resource, Route 53 uses the target resource’s default TTL.
- When an alias points to another record in the same hosted zone, Route 53 uses the target record’s TTL.
- Ordinary non-alias records such as A, AAAA and CNAME records have an explicitly configured TTL.
AWS documents these alias TTL rules here.
A team cannot assume it can lower an ALB alias TTL before migration; the target controls it.
The change process should distinguish:
ROUTE 53 CHANGE STATUS
Has Route 53 applied the new record?
CACHE LIFETIME
How long may resolvers and clients
retain the previous answer?
INSYNC confirms the Route 53 change has propagated through Route 53.
It does not flush answers already cached by clients or recursive resolvers.
Health and failover depend on the target
Private hosted zones support failover and other routing policies.
The health source should match the target and the capability being protected.
| Destination | Possible health source | Important limitation |
|---|---|---|
| ALB or NLB alias | EvaluateTargetHealth |
Inherits supported load-balancer and target-group health |
| Private application endpoint | CloudWatch alarm-backed Route 53 health check | Alarm must represent the application capability |
| Publicly reachable endpoint | Direct Route 53 endpoint health check | Health checker must be able to reach it |
| Interface endpoint | Application or synthetic metric | Alias target health may not prove the provider service works |
When EvaluateTargetHealth is enabled for a supported alias target, the alias inherits the health of the referenced AWS resource or record. For load balancers, Route 53 can use load-balancer and target-group health. AWS documents alias target health here.
This differs from a standalone Route 53 health check. Health checkers cannot directly monitor private, non-routable addresses, so private services can use a CloudWatch alarm-backed health check. AWS documents both points here. health-check-addresses
PRIVATE SERVICE
│
▼
APPLICATION OR SYNTHETIC METRIC
│
▼
CLOUDWATCH ALARM
│
▼
ROUTE 53 HEALTH CHECK
│
▼
FAILOVER DECISION
The signal should represent the capability the DNS decision is meant to protect.
An instance status check may prove that an instance is running.
It may not prove that:
- the service can process an order;
- its database is available;
- the recovery endpoint is ready;
- required credentials remain valid.
DNS failover affects future lookups.
It does not move established connections, and cached answers may remain in use until their TTL expires.
Private routing policies use AWS resolver context
Private hosted zones support several routing policies, including failover, weighted, latency and geolocation.
For private geolocation records, Route 53 uses the AWS Region of the originating VPC, not necessarily the human user’s location. Resolver endpoints can therefore shape the location Route 53 observes. AWS documents the private-zone behaviour here.
Before using private latency or geolocation routing, state explicitly:
Which resolver location does Route 53 see?
Does that location represent
the client population we intend to steer?
For many internal services, explicit regional names or application-level routing may be easier to reason about.
Multi-account ownership
bfstore may place the private hosted zone in bfstore-network while workload VPCs live in separate accounts.
For a direct cross-account association:
- the zone-owning account authorises one VPC association;
- the VPC-owning account completes the association;
- the unused authorisation should be removed.
The cross-account workflow requires the API, CLI, SDK or infrastructure code rather than the Route 53 console alone. AWS documents the handshake here.
ZONE ACCOUNT
│
▼
AUTHORISE VPC
│
▼
VPC ACCOUNT
│
▼
ASSOCIATE ZONE
For repeated organisation-wide configuration, a shared Route 53 Profile may remove much of that per-zone, per-VPC association work.
Profiles are shared through AWS RAM, and updates to the Profile propagate to its associated VPCs. AWS documents Profile sharing here.
The choice should be intentional:
DIRECT ASSOCIATION
explicit exceptional relationship
ROUTE 53 PROFILE
repeatable resolver view
for a class of VPCs
DNS write access is data-path authority
Changing:
payments.prod.aws.internal.bfstore.example
can redirect payment traffic towards:
- the wrong environment;
- an obsolete endpoint;
- a compromised destination;
- a recovery service that is not ready.
DNS write permission is production data-path authority.
The change model should distinguish:
| Role | Capabilities |
|---|---|
| Zone administrator | Create zones, associate resolver views, change ownership boundaries |
| Record administrator | Change approved records, TTLs, routing and health associations |
| Read-only investigator | Inspect zones, rules, Profiles, associations and change status |
Route 53 IAM conditions can restrict changes by normalised record name, record type and change action, and can restrict zone associations to particular VPCs. AWS documents these fine-grained conditions here.
That supports a model such as:
APPLICATION TEAM
declares a service-name requirement
PLATFORM PIPELINE
validates the namespace and destination
ROUTE 53 ROLE
updates only approved names and types
The key question is who may redirect the name and where that decision is reviewed.
Logging and inventory must cover the resolver view
VPC Resolver query logging can record queries from associated VPCs and deliver them to CloudWatch Logs, S3 or Firehose.
Useful fields include:
- VPC and source information;
- queried name and record type;
- response code;
- returned answer;
- DNS Firewall action.
The logs can identify clients using retired names, explain NXDOMAIN, show failover lookups and reveal unexpected domains.
VPC Resolver caches answers.
Query logging records unique queries that reach the resolver, not repeated queries answered from the resolver cache. AWS documents that limitation here.
ONE QUERY-LOG ENTRY
does not equal
ONE APPLICATION REQUEST
The inventory must also cover every way DNS configuration reaches the VPC:
resolver_view:
vpc_id: vpc-example
region: eu-west-2
private_zones:
direct:
- zone_id: Z123
name: prod.aws.internal.bfstore.example
profiles:
- profile_id: rp-example
private_zones:
- platform.aws.internal.bfstore.example
resolver_rules:
- domain: corp.example
type: FORWARD
query_logging:
destination: central-dns-logs
dns_firewall:
policy: production-egress
endpoints:
inbound: []
outbound:
- rslvr-out-example
This distinction matters because ListHostedZonesByVPC and GetHostedZone do not report private hosted-zone associations delivered through Route 53 Profiles. Profile resource-association APIs must also be queried. AWS documents the inventory limitation here.
The architecture must know which rule, association or Profile actually supplies the resolver view.
Quotas should inform, not dictate, the design
Route 53 applies quotas to hosted zones, records, associations, Profiles and other resources.
AWS currently documents:
- 10,000 records per hosted zone by default;
- 300 direct VPC associations per private hosted zone;
- Route 53 Profiles as the recommended model when more associations are required.
Because quotas can change or be increased, runbooks should link to the current page. Current quotas are documented here.
The design tension remains:
TOO BROAD
one zone
many unrelated owners
large blast radius
TOO FRAGMENTED
one zone per record
large inventory
complex authority tree
USEFUL
one zone per meaningful
owner and audience boundary
The objective is not the fewest zones.
It is the clearest authority model.
A bfstore private DNS design
I would place private DNS governance in the bfstore-network account and use a combination of Route 53 Profiles and exceptional direct associations.
aws.internal.bfstore.example
│
├── prod.aws.internal.bfstore.example
├── nonprod.aws.internal.bfstore.example
└── platform.aws.internal.bfstore.example
These are separate authority zones, not automatically delegated children.
Production Profile
A bfstore-production-dns Profile could contain:
prod.aws.internal.bfstore.example;- approved platform-zone access;
- central query logging;
- standard DNS Firewall policy;
- common enterprise forwarding rules.
It would be shared with production-class VPCs through AWS RAM.
Non-production Profile
A separate Profile could provide:
nonprod.aws.internal.bfstore.example;- development forwarding rules;
- non-production logging and firewall policy.
Development and staging can split when their ownership diverges.
Exceptional direct associations
A narrow zone or rule can be associated directly when one VPC needs an exceptional resolver view.
Because local configuration overrides conflicting Profile configuration, the exception must be visible in inventory.
A conceptual record could look like:
private_hosted_zone:
name: prod.aws.internal.bfstore.example
owner_account: bfstore-network
owner_team: network-platform
distribution:
profile:
name: bfstore-production-dns
shared_with:
- bfstore-prod
- bfstore-observability
- bfstore-backup
records:
- name: otel.prod.aws.internal.bfstore.example
type: A_ALIAS
target: observability-ingest-nlb
owner: observability-platform
health:
evaluate_target_health: true
ttl:
managed_by: alias-target
- name: orders.prod.aws.internal.bfstore.example
type: A_ALIAS
target: internal-orders-alb
owner: order-service
health:
evaluate_target_health: true
ttl:
managed_by: alias-target
controls:
query_logging: central-dns-logs
public_dnssec_validation: evaluated-separately
record_changes: infrastructure-pipeline
resolver_view_inventory: required
public_dnssec_validation is deliberately scoped.
VPC Resolver DNSSEC validation applies to recursively resolved signed public domains. It is not a mechanism that signs or authenticates records inside this private hosted zone. AWS documents VPC DNSSEC validation here.
Test from the consuming VPC
A hosted zone showing the correct record in the console does not prove that a client receives it.
Test from the resolver view that consumes the namespace.
dig otel.prod.aws.internal.bfstore.example A
dig missing.prod.aws.internal.bfstore.example A
getent hosts otel.prod.aws.internal.bfstore.example
Record the source VPC and Region, resolver configuration, VPC DNS attributes, direct and Profile associations, matching rules, winning namespace, effective TTL, route and application result.
NAME RESOLVES
│
▼
ADDRESS RETURNED
│
▼
ROUTE EXISTS
│
▼
NETWORK POLICY PERMITS
│
▼
SERVICE AUTHORISES
A successful answer proves only the first two steps; a failed connection does not automatically mean DNS is broken.
Common failure patterns
Public name works, VPC receives NXDOMAIN
Likely cause:
- a matching private zone claims the namespace;
- the record is absent privately;
- Resolver does not fall back to public DNS.
Name resolves in production but not development
Likely cause:
- the production resolver view includes the zone;
- the development resolver view does not.
This may be intentional.
Correct record exists but is ignored
Likely causes:
- a forwarding rule takes precedence;
- local VPC configuration overrides a Profile;
- a more-specific zone owns the branch;
- the client uses a custom resolver without the required forwarding path.
Name resolves to the wrong environment
Likely causes:
- overly broad association or Profile;
- copied record points to staging;
- local override conflicts with the shared Profile;
- stale client or resolver cache.
Name resolves, connection times out
Likely causes:
- missing route;
- incorrect Transit Gateway propagation;
- security-group or firewall denial;
- return-path failure;
- service not listening.
DNS may have succeeded.
Failover does not switch as expected
Likely causes:
- the health source does not represent the application;
EvaluateTargetHealthis unsupported or ineffective for the target;- a CloudWatch-alarm health check is misconfigured;
- the old answer remains cached;
- existing connections do not repeat DNS resolution.
Inventory says the VPC has no zone, but it resolves
Likely cause:
- the zone arrived through a Route 53 Profile;
- the inventory queried only direct VPC associations.
Diagnose namespace selection, cache state, routing and service acceptance separately.
The decision model
The recurring questions are:
Which namespace are we claiming?
Which resolver views receive it?
Does a local setting, Profile or rule win?
Which zone is the most-specific authority?
What durable service boundary
does the record represent?
Who may redirect the name?
How is health evaluated?
What does the client cache?
Can the returned address be reached
and used by the caller?
The model is:
PRIVATE NAMESPACE
│
▼
PRIVATE HOSTED ZONE
│
┌─────────────┴─────────────┐
│ │
▼ ▼
RECORDS RESOLUTION SCOPE
│
┌─────────────┴─────────────┐
│ │
▼ ▼
DIRECT ASSOCIATION PROFILE
│ │
└─────────────┬─────────────┘
▼
VPC RESOLVER VIEW
│
┌───────────────┼───────────────┐
│ │ │
▼ ▼ ▼
LOCAL OVERRIDE RESOLVER RULE PRIVATE ZONE
│ │ │
└───────────────┼───────────────┘
▼
MOST-SPECIFIC WINNER
│
▼
DNS RESPONSE
│
▼
CACHE AND TTL
│
▼
NETWORK ROUTE
│
▼
NETWORK AUTHORISATION
│
▼
APPLICATION AUTHORISATION
A private hosted zone creates private meaning, not private infrastructure.
The zone defines authority. Direct associations and Profiles define the resolver views. Rules can redirect the question, and the most-specific namespace decides which authority wins. Alias targets may control caching, while health determines which future answers remain eligible.
The network carries the resulting packet. Network and application controls decide whether the request should succeed.
DNS lets the architecture move without requiring every application to memorise its current address.
References and further reading
Reviewed against official AWS documentation on 31 July 2026.
- Working with private hosted zones
- Private hosted-zone considerations
- What is Route 53 VPC Resolver?
- What are Route 53 Profiles?
- Working with shared Route 53 Profiles
- Route 53 Global Resolver
- Resolver rule behaviour
- Choosing between alias and non-alias records
- Alias target health
- Failover in private hosted zones
- Health-check address restrictions
- Geolocation routing in private hosted zones
- Cross-account private hosted-zone associations
- Route 53 IAM conditions
- VPC Resolver query logging
- ListHostedZonesByVPC and Profile inventory
- Route 53 quotas
- VPC Resolver DNSSEC validation