Skip to main content
Multi-CloudNetworkingintermediate

DNS Architecture Across Clouds

Design DNS for multi-cloud: public/private zones, hybrid resolution, split-horizon, and centralized DNS strategies.

CloudToolStack Team24 min readPublished Mar 14, 2026

Prerequisites

  • Understanding of DNS fundamentals (zones, records, resolution)
  • Familiarity with at least one cloud DNS service

DNS Architecture for Multi-Cloud

DNS is the foundation of all cloud networking. Every API call, service discovery request, and user connection starts with DNS resolution. In multi-cloud environments, DNS becomes significantly more complex because you must manage public zones (internet-facing), private zones (internal resolution), and hybrid resolution (bridging on-premises and cloud).

Each cloud provider has its own managed DNS service with different features, pricing models, and integration points. This guide compares Route 53 (AWS), Azure DNS (Azure), Cloud DNS (GCP), and OCI DNS, then covers public zone management, private DNS zones, split-horizon DNS, hybrid resolution patterns, and centralized DNS strategies for multi-cloud.

DNS Service Comparison

All four cloud DNS services support standard record types (A, AAAA, CNAME, MX, TXT, SRV, NS), DNSSEC, and health-check-based routing. The key differences are in advanced routing policies, private zone integration, and pricing. Route 53 charges $0.50/zone/month and $0.40 per million queries. Azure DNS charges $0.50/zone/month and $0.40 per million. Cloud DNS charges $0.20/zone/month and $0.40 per million.

Public DNS Zone Management

Public DNS zones contain records that are resolvable from the internet. In a multi-cloud setup, you typically host your public zones in one cloud provider and point records to resources in any cloud.

Route 53 (AWS)

bash
# Create a hosted zone
aws route53 create-hosted-zone \
  --name example.com \
  --caller-reference "$(date +%s)"

# Create records pointing to resources in different clouds
# A record to AWS ALB
aws route53 change-resource-record-sets \
  --hosted-zone-id Z1234567890 \
  --change-batch '{
    "Changes": [{
      "Action": "CREATE",
      "ResourceRecordSet": {
        "Name": "app.example.com",
        "Type": "A",
        "AliasTarget": {
          "HostedZoneId": "Z35SXDOTRQ7X7K",
          "DNSName": "myalb-123.us-east-1.elb.amazonaws.com",
          "EvaluateTargetHealth": true
        }
      }
    }]
  }'

# CNAME to Azure Front Door
aws route53 change-resource-record-sets \
  --hosted-zone-id Z1234567890 \
  --change-batch '{
    "Changes": [{
      "Action": "CREATE",
      "ResourceRecordSet": {
        "Name": "portal.example.com",
        "Type": "CNAME",
        "TTL": 300,
        "ResourceRecords": [{"Value": "myapp.azurefd.net"}]
      }
    }]
  }'

# A record to GCP external IP
aws route53 change-resource-record-sets \
  --hosted-zone-id Z1234567890 \
  --change-batch '{
    "Changes": [{
      "Action": "CREATE",
      "ResourceRecordSet": {
        "Name": "api.example.com",
        "Type": "A",
        "TTL": 300,
        "ResourceRecords": [{"Value": "34.120.1.2"}]
      }
    }]
  }'

Cloud DNS (GCP)

bash
# Create a public DNS zone
gcloud dns managed-zones create example-zone \
  --dns-name="example.com." \
  --description="Production public zone" \
  --dnssec-state=on

# Add records
gcloud dns record-sets transaction start --zone=example-zone

gcloud dns record-sets transaction add "34.120.1.2" \
  --name="api.example.com." \
  --ttl=300 \
  --type=A \
  --zone=example-zone

gcloud dns record-sets transaction add "myalb-123.us-east-1.elb.amazonaws.com." \
  --name="aws-app.example.com." \
  --ttl=300 \
  --type=CNAME \
  --zone=example-zone

gcloud dns record-sets transaction execute --zone=example-zone

Private DNS Zones

Private DNS zones resolve names only within virtual networks. They are used for internal service discovery, private endpoints, and split-horizon DNS. Each cloud handles private DNS differently.

FeatureAWS Route 53Azure DNSGCP Cloud DNS
Private zonePrivate Hosted Zone (linked to VPCs)Private DNS Zone (linked to VNets)Private Zone (bound to VPCs)
Auto-registrationNo (use Cloud Map)Yes (VMs register automatically)No
Cross-account/projectYes (cross-account VPC association)Yes (cross-subscription links)Yes (cross-project binding)
Peering zoneNo (use Resolver rules)NoYes (DNS peering zones)
bash
# AWS: Create a private hosted zone
aws route53 create-hosted-zone \
  --name internal.example.com \
  --caller-reference "$(date +%s)" \
  --vpc VPCRegion=us-east-1,VPCId=vpc-abc123 \
  --hosted-zone-config PrivateZone=true

# Azure: Create a private DNS zone
az network private-dns zone create \
  --name internal.example.com \
  --resource-group network-rg

az network private-dns zone vnet-link create \
  --zone-name internal.example.com \
  --resource-group network-rg \
  --name hub-link \
  --virtual-network hub-vnet \
  --registration-enabled true

# GCP: Create a private DNS zone
gcloud dns managed-zones create internal-zone \
  --dns-name="internal.example.com." \
  --description="Internal services" \
  --visibility=private \
  --networks=projects/PROJECT/global/networks/my-vpc

Hybrid DNS Resolution

Hybrid DNS enables resources in cloud VPCs to resolve on-premises DNS names, and on-premises clients to resolve cloud private DNS names. Each cloud provides DNS forwarding mechanisms for this purpose.

bash
# AWS: Route 53 Resolver for hybrid DNS
# Inbound endpoint (on-premises can forward queries to AWS)
aws route53resolver create-resolver-endpoint \
  --name "inbound-from-onprem" \
  --creator-request-id "$(date +%s)" \
  --direction INBOUND \
  --security-group-ids sg-abc123 \
  --ip-addresses SubnetId=subnet-abc123 SubnetId=subnet-def456

# Outbound endpoint (AWS forwards queries to on-premises DNS)
aws route53resolver create-resolver-endpoint \
  --name "outbound-to-onprem" \
  --creator-request-id "$(date +%s)" \
  --direction OUTBOUND \
  --security-group-ids sg-abc123 \
  --ip-addresses SubnetId=subnet-abc123 SubnetId=subnet-def456

# Forwarding rule for on-premises domain
aws route53resolver create-resolver-rule \
  --name "forward-to-onprem" \
  --creator-request-id "$(date +%s)" \
  --rule-type FORWARD \
  --domain-name "corp.company.com" \
  --resolver-endpoint-id rslvr-out-abc123 \
  --target-ips Ip=10.200.0.53,Port=53 Ip=10.200.0.54,Port=53
hcl
# GCP: DNS forwarding for on-premises resolution
resource "google_dns_managed_zone" "onprem_forward" {
  name        = "onprem-forward"
  dns_name    = "corp.company.com."
  description = "Forward to on-premises DNS"
  visibility  = "private"

  private_visibility_config {
    networks {
      network_url = google_compute_network.main.id
    }
  }

  forwarding_config {
    target_name_servers {
      ipv4_address    = "10.200.0.53"
      forwarding_path = "private"
    }
    target_name_servers {
      ipv4_address    = "10.200.0.54"
      forwarding_path = "private"
    }
  }
}

# GCP: DNS peering for cross-VPC resolution
resource "google_dns_managed_zone" "peering" {
  name        = "peer-to-shared-vpc"
  dns_name    = "shared.internal."
  description = "Peer DNS resolution to shared VPC"
  visibility  = "private"

  private_visibility_config {
    networks {
      network_url = google_compute_network.consumer.id
    }
  }

  peering_config {
    target_network {
      network_url = google_compute_network.shared.id
    }
  }
}

Split-Horizon DNS

Split-horizon DNS returns different answers for the same domain name depending on where the query originates. Internal users resolve app.example.com to a private IP (via the private zone), while external users resolve it to a public IP (via the public zone). All three clouds support this pattern by maintaining separate public and private zones with the same domain name.

TLS Certificate Considerations

When using split-horizon DNS, ensure your TLS certificates cover both the public and private endpoints. The domain name is the same, so a single certificate works. However, if you use private CA certificates internally, external clients will not trust them. Use a publicly trusted certificate (Let's Encrypt, ACM, etc.) even for internal endpoints to avoid certificate management complexity.

Centralized DNS Strategy

For multi-cloud environments, choose one provider as the authoritative DNS host for public zones and establish forwarding rules for private zone resolution across clouds. Route 53 is a popular choice for centralized public DNS due to its routing policies (latency, geolocation, weighted, failover).

Recommended Architecture

ComponentRecommendationRationale
Public zonesSingle provider (Route 53 or Cloud DNS)Simplify management, use advanced routing
Private zonesPer-cloud provider native serviceBest integration with cloud-native services
Cross-cloud resolutionDNS forwarding via VPN/interconnectResolve private names across clouds
On-premisesConditional forwarders per cloudRoute queries to the correct cloud
Service discoveryConsul or Cloud Map per cloudDynamic service registration

DNS Automation with Terraform

hcl
# Centralized public zone in Route 53
resource "aws_route53_zone" "public" {
  name = "example.com"
}

# Latency-based routing to multi-cloud endpoints
resource "aws_route53_record" "app_aws" {
  zone_id        = aws_route53_zone.public.zone_id
  name           = "app.example.com"
  type           = "A"
  set_identifier = "aws-us-east"

  alias {
    name                   = aws_lb.main.dns_name
    zone_id                = aws_lb.main.zone_id
    evaluate_target_health = true
  }

  latency_routing_policy {
    region = "us-east-1"
  }
}

resource "aws_route53_record" "app_gcp" {
  zone_id        = aws_route53_zone.public.zone_id
  name           = "app.example.com"
  type           = "A"
  ttl            = 60
  set_identifier = "gcp-us-central"

  records = [google_compute_global_address.main.address]

  latency_routing_policy {
    region = "us-east-1"  # Closest AWS region to GCP us-central1
  }

  health_check_id = aws_route53_health_check.gcp.id
}

resource "aws_route53_health_check" "gcp" {
  fqdn              = "api.example.com"
  port               = 443
  type               = "HTTPS"
  resource_path      = "/health"
  failure_threshold  = 3
  request_interval   = 30
}

ExternalDNS for Kubernetes

If you run Kubernetes across clouds, use ExternalDNS to automatically manage DNS records based on Kubernetes Ingress and Service resources. ExternalDNS supports Route 53, Azure DNS, Cloud DNS, and many other providers. It creates and updates DNS records as you deploy services, eliminating manual DNS management.

Route 53 DNS PatternsMulti-Cloud Networking Comparison

Key Takeaways

  1. 1Host public zones in a single provider for simplified management and advanced routing.
  2. 2Private DNS zones are per-cloud with different linking and resolution mechanisms.
  3. 3Hybrid DNS requires forwarding rules between on-premises and cloud DNS services.
  4. 4Split-horizon DNS returns different IPs for the same domain based on query origin.

Frequently Asked Questions

Should I use one DNS provider for all public zones?
Yes, for simplicity. Route 53 is popular for its advanced routing policies. Cloud DNS is cheaper. Multiple providers add complexity without significant benefit.
How do I resolve private DNS names across clouds?
Use DNS forwarding over VPN or interconnect. Configure conditional forwarding rules in each cloud's DNS service to forward queries for other clouds' domains.

Written by CloudToolStack Team

Cloud engineers and architects with hands-on experience across AWS, Azure, and GCP. We write guides based on real-world production patterns, not just documentation rewrites.

Disclaimer: This guide is for educational purposes. Cloud services change frequently; always refer to official documentation for the latest information. AWS, Azure, and GCP are trademarks of their respective owners.