Hybrid DNS Solution with Azure

peepeepopapapeepeepo

Sawit M.

Posted on November 4, 2022

Hybrid DNS Solution with Azure

หลังจากที่ Azure ประกาศ GA Azure DNS Private Resolver ก็ได้ฤกษ์ ลองเล่นซะที หลังจากเก็บไว้ในกองดองอยู่นาน มาเข้าเรื่องกันเลยครับ

Azure DNS Private Resolver คืออะไร

สั้นๆ มันคือ resource ที่ทำหน้าที่เป็น DNS server นั้นเอง ในโลก internet DNS เป็นส่วนที่สำคัญมากๆ มันทำให้เราพิมพ์ google.co.th แล้วสามารถ connect ไปที่ google ได้เลยแทนที่จะต้องพิมพ์ 142.251.12.94 ซึ่งเป็น IP address ของ goole ที่ผม resolve ได้ในตอนที่เขียน blog นี้

โดย resource ตัวนี้จะทำงานใน private network ของเราบน Azure คอย resolve private domain name ของเราให้เป็น private IP address

แล้วก่อนหน้านี้ resolve domain name กันอย่างไรล่ะ

ใน Azure จริงๆ แล้ว มัมมี built-in DNS อยู่แล้ว เรียกว่า Azure-provided DNS มันจะเป็น configuration เนียนๆ อยู่ใน virtual network ของเรา ตรงนี้

Image description

โดย มันจะปรากฏในรูปแบบของ IP 168.63.129.16 ใน ใน VM ของเรา ที่ deploy ใน virtual network ที่ configure DNS server ไว้ตามข้างต้น โดย 168.63.129.16 สามารถ connect จาก Azure resources เท่านั้น

$ systemd-resolve --status | grep 'DNS Servers'
DNS Servers: 168.63.129.16
Enter fullscreen mode Exit fullscreen mode

รายละเอียดเพิ่มเติม ของ 168.63.129.16 สามารถอ่านเพิ่มได้จาก What is IP address 168.63.129.16?

ทีนี้หากเราต้องการ เพิ่ม private domain name ก็แค่สร้าง private dns zone แล้ว link มันกับ virtual network ของเรา เท่านี้ Azure DNS ก็จะสามารถ resolve private domain name ของเราได้แล้ว

พอเราใช้ไปซักพักความต้องการเริ่มมากขึ้น เริ่มมี requirement ให้เราไปต่อกับ on-premise network ในส่วนของ connetivity นั้นก็ใช้ VPN หรือ Express Route ได้ตามปกติ แต่ในเรื่อง domain name resolution ล่ะ จะทำอย่างไรดี เพราะ on-prem ไม่สามารถ connect มาที่ 168.63.129.16 ที่อยู่บน Azure ของเราได้

ก่อนการมาของ Azure DNS Private Resolver เราใช้วิธีการสร้าง VM-Based DNS server ขึ้นมา พูดง่ายๆ สร้าง VM แล้วเอา DNS software เช่น Bind9 มา install เอง ถ้าอยากได้ SLA ที่เพิ่มขึ้นก็เอา VM มาใส่ VM Scale Set แล้ว ขั้นหน้าด้วย Load Balancer

นั่นหมายความว่าเราต้อง manage ทุกอย่างเอง ไม่ว่าจะเป็นการ hardening, OS update, Software upgrade, Backup และอื่นๆ อีกมากมาย

แล้วให้ on-premise DNS server ทำ Conditional Forward มาที่ VM-Based DNS server ของเรา

ในทางกลับกัน เราต้องต้อง configure Conditional Forward ลงไปที่ on-prem ด้วย เพื่อให้ server บน Azure สามารถ resolve domain name ของ on-premise ได้

Conditional Forward คือการ configure ใน DNS server ทำการ forward request ต่อยัง อีก DNS server หนึ่ง เช่น เรามี zone *.example.com อยู่ที่ server-A เราสามารถ configure ให้ DNS ของเราไปถามต่อที่ server-A ได้ หากมี client ถามว่า demo.example.com เป็น IP อะไร โดยที่ client ไม่ต้องรู้จัก server-A เลย

Azure DNS Private Resolver ทำงานอย่างไร

การที่จะทำ Hybrid DNS Solution บน Azure จะมี 2 resources ที่ทำงานร่วมกัน

  1. DNS Private Resolver
  2. DNS Forwarding Ruleset

DNS Private Resolver

ทำหน้าที่เป็น endpoint ในการทำ name resolution โดยประกอบด้วย 2 endpoints ที่ deploy อยู่คนละ dedicated subnet คือ

  • Inbound endpoints: เป็น ingress subnet โดย 1 endpoint จะมี 1 IP address ของ Load Balancer สำหรับ รับ domain name resolution request จาก on-premise หรือ resource ใน virtual network อื่น

Inbound endpoints

  • Outbound endpoints: เป็น egress subnet ที่ใช้ออกไป query DNS servers อื่นๆ ใน subnet นี้จะไม่มี IP address ปรากฏ นั่นหมายความว่า outgoing IP address มีโอกาสเป็นไปได้ทั้ง subnet (ผมเดาว่าน่าจะใช้ technic เดียวกับ vnet integration ของ app service)

Outbound endpoints

DNS Forwarding Ruleset

ทำหน้าที่เป็น conditional forward configuration ใน vnet ของเรา โดย Ruleset ก็ตามชื่อเลยครับ เป็นกลุ่มของ conditional forward rule โดย rule จะมีหน้าตาดังนี้

DNS Forwarding Rule

และการจะใช้งาน DNS Forwarding Ruleset ได้ ก็ต้องเอามันไป link กับ virtual network ตาม concept เดียวกับ Private DNS Zone

DNS Forwarding Ruleset Link

ยังจำได้ไหม ตัว resolver มี outbound endpoint ซึ่ง deploy ใน dedicated subnet ใน virtual network ดังนั้น ตัว outbound endpoint ก็จะทำตาม DNS Forwarding Ruleset ที่เรา link ไว้ด้วย

เอ๊ะ! ถ้าเรามีทั้ง Private DNS Zone Link และ DNS Forwarding Ruleset Link ด้วยมันจะทำงานอย่างไร ?

มันจะ resolve ตาม order นี้ครับ

  1. Private DNS Zone
  2. DNS Forwarding Ruleset
  3. Azure-provided DNS Servers

สรุป ถ้า resolver ได้รับ name resolution request มาจาก client ผ่านทาง inbound endpoint IP address มันจะ forward ออกไปยัง outbound endpoint IP address ซึ่งจะทำการ resolve domain name ตามลำดับข้างต้น แล้ว response สิ่งที่ได้ไปให้กับ client

ถ้าพอนึกภาพออกแล้วเรามาลองลงมือทำกันดีกว่า

Architecure ที่เราจะลองทำหน้าตาประมาณนี้ครับ

demo-architecture

เราจะมี 3 virtual network ดังนี้

  1. On-Prem: เป็นตัวแทนของ on-premise
  2. Hub: เป็นตัวแทนของ Hub network บน Azure ที่เป็นศูนย์รวมของ connectivity ต่างๆ
  3. Spoke: เป็น virtual network ของ application ที่จะมา deploy ใน Azure

โดย

  • ที่ On-Prem จะมี DNS server ที่มี DNS records ของ domain *.onprem.contoso.com และทำ conditional forward domain *.private.contoso.com ไปที่ Resolver ที่ Hub
  • ที่ Hub จะมี DNS Private Resolver พระเอกของเรา, Private DNS Zone *.private.contoso.com และ DNS Forwarding Ruleset พระเอกของเราอีกคน เอาไว้ทำ conditional forward *.onprem.contoso.com ลงไปที่ On-Prem โดยใน virtual network นี้จะมี VM 1 server เอาไว้ทดสอบ name resolution
  • ที่ Spoke มี VM 1 server เอาไว้ทดสอบ name resolution เช่นกัน

เรามาเริ่มสร้างกันเลย

Create Resource Group
az group create \
--name rg-demodns-az-asse-sbx-001 \
--location southeastasia
Enter fullscreen mode Exit fullscreen mode
Create Hub
  • Virtual Network
az network vnet create \
--resource-group rg-demodns-az-asse-sbx-001 \
--name vnet-demodnshub-az-asse-sbx-001 \
--address-prefixes 10.1.0.0/16

az network vnet subnet create \
--resource-group rg-demodns-az-asse-sbx-001 \
--name snet-default-az-asse-sbx-001 \
--vnet-name vnet-demodnshub-az-asse-sbx-001 \
--address-prefixes 10.1.1.0/24

az network vnet subnet create \
--resource-group rg-demodns-az-asse-sbx-001 \
--name snet-inbound-az-asse-sbx-001 \
--vnet-name vnet-demodnshub-az-asse-sbx-001 \
--address-prefixes 10.1.2.0/28

az network vnet subnet create \
--resource-group rg-demodns-az-asse-sbx-001 \
--name snet-outbound-az-asse-sbx-001 \
--vnet-name vnet-demodnshub-az-asse-sbx-001 \
--address-prefixes 10.1.2.16/28
Enter fullscreen mode Exit fullscreen mode
  • Virtual Machine
SUBNET_ID=$(
az network vnet subnet show \
--resource-group rg-demodns-az-asse-sbx-001 \
--vnet-name vnet-demodnshub-az-asse-sbx-001 \
--name snet-default-az-asse-sbx-001 \
--query "id" \
--output tsv
)

az vm create \
--resource-group rg-demodns-az-asse-sbx-001 \
--name vm-hub-az-asse-sbx-001 \
--computer-name vm-hub-az-asse-sbx-001 \
--image UbuntuLTS \
--size Standard_D2s_v4 \
--accelerated-networking true \
--subnet ${SUBNET_ID} \
--nsg-rule SSH \
--admin-username azureuser \
--ssh-key-values /home/sawitmee/.ssh/id_rsa.pub
Enter fullscreen mode Exit fullscreen mode
  • Private DNS Zone
az network private-dns zone create \
--resource-group rg-demodns-az-asse-sbx-001 \
--name private.contoso.com

az network private-dns record-set a add-record \
--resource-group rg-demodns-az-asse-sbx-001 \
--zone-name private.contoso.com \
--record-set-name test \
--ipv4-address 10.10.10.10

az network private-dns link vnet create \
--resource-group rg-demodns-az-asse-sbx-001 \
--name link-vnet-demodnshub-az-asse-sbx-001 \
--zone-name private.contoso.com \
--virtual-network vnet-demodnshub-az-asse-sbx-001 \
-e false
Enter fullscreen mode Exit fullscreen mode
  • Private Resolver
VNET_ID=$(
az network vnet show \
--resource-group rg-demodns-az-asse-sbx-001 \
--name vnet-demodnshub-az-asse-sbx-001 \
--query "id" \
--output tsv
)

az dns-resolver create \
--resource-group rg-demodns-az-asse-sbx-001 \
--name adpr-hub-az-asse-sbx-001 \
--id ${VNET_ID}

SUBNET_ID=$(
az network vnet subnet show \
--resource-group rg-demodns-az-asse-sbx-001 \
--vnet-name vnet-demodnshub-az-asse-sbx-001 \
--name snet-inbound-az-asse-sbx-001 \
--query "id" \
--output tsv
)

az dns-resolver inbound-endpoint create \
--resource-group rg-demodns-az-asse-sbx-001 \
--dns-resolver-name adpr-hub-az-asse-sbx-001 \
--name snet-inbound-az-asse-sbx-001 \
--ip-configurations "[{private-ip-address:'',private-ip-allocation-method:'Dynamic',id:'$SUBNET_ID'}]"

SUBNET_ID=$(
az network vnet subnet show \
--resource-group rg-demodns-az-asse-sbx-001 \
--vnet-name vnet-demodnshub-az-asse-sbx-001 \
--name snet-outbound-az-asse-sbx-001 \
--query "id" \
--output tsv
)

az dns-resolver outbound-endpoint create \
--resource-group rg-demodns-az-asse-sbx-001 \
--dns-resolver-name adpr-hub-az-asse-sbx-001 \
--name snet-outbound-az-asse-sbx-001 \
--id "${SUBNET_ID}"
Enter fullscreen mode Exit fullscreen mode
Create Spoke ( + Peering )
  • Virtual Network
az network vnet create \
--resource-group rg-demodns-az-asse-sbx-001 \
--name vnet-demodnsspoke-az-asse-sbx-001 \
--address-prefixes 10.2.0.0/16 \
--dns-servers 10.1.2.4

az network vnet subnet create \
--resource-group rg-demodns-az-asse-sbx-001 \
--name snet-default-az-asse-sbx-001 \
--vnet-name vnet-demodnsspoke-az-asse-sbx-001 \
--address-prefixes 10.2.1.0/24

az network vnet subnet create \
--resource-group rg-demodns-az-asse-sbx-001 \
--name snet-inbound-az-asse-sbx-001 \
--vnet-name vnet-demodnsspoke-az-asse-sbx-001 \
--address-prefixes 10.2.2.0/28

az network vnet subnet create \
--resource-group rg-demodns-az-asse-sbx-001 \
--name snet-outbound-az-asse-sbx-001 \
--vnet-name vnet-demodnsspoke-az-asse-sbx-001 \
--address-prefixes 10.2.2.16/28
Enter fullscreen mode Exit fullscreen mode
  • Peering
az network vnet peering create \
--resource-group rg-demodns-az-asse-sbx-001 \
--name vpeer-vnet-demodnsspoke-az-asse-sbx-001-vnet-demodnshub-az-asse-sbx-001 \
--vnet-name vnet-demodnsspoke-az-asse-sbx-001 \
--remote-vnet vnet-demodnshub-az-asse-sbx-001 \
--allow-vnet-access

az network vnet peering create \
--resource-group rg-demodns-az-asse-sbx-001 \
--name vpeer-vnet-demodnshub-az-asse-sbx-001-vnet-demodnsspoke-az-asse-sbx-001 \
--vnet-name vnet-demodnshub-az-asse-sbx-001 \
--remote-vnet vnet-demodnsspoke-az-asse-sbx-001 \
--allow-vnet-access
Enter fullscreen mode Exit fullscreen mode
  • Virtual Machine
SUBNET_ID=$(
az network vnet subnet show \
--resource-group rg-demodns-az-asse-sbx-001 \
--vnet-name vnet-demodnsspoke-az-asse-sbx-001 \
--name snet-default-az-asse-sbx-001 \
--query "id" \
--output tsv
)

az vm create \
--resource-group rg-demodns-az-asse-sbx-001 \
--name vm-spoke-az-asse-sbx-001 \
--computer-name vm-spoke-az-asse-sbx-001 \
--image UbuntuLTS \
--size Standard_D2s_v4 \
--accelerated-networking true \
--subnet ${SUBNET_ID} \
--nsg-rule SSH \
--admin-username azureuser \
--ssh-key-values /home/sawitmee/.ssh/id_rsa.pub
Enter fullscreen mode Exit fullscreen mode
  • Test
nslookup test.private.contoso.com
Enter fullscreen mode Exit fullscreen mode
Create On-Premise ( +Peering )
  • Virtual Network
az network vnet create \
--resource-group rg-demodns-az-asse-sbx-001 \
--name vnet-demodnsonprem-az-asse-sbx-001 \
--address-prefixes 10.3.0.0/16

az network vnet subnet create \
--resource-group rg-demodns-az-asse-sbx-001 \
--name snet-default-az-asse-sbx-001 \
--vnet-name vnet-demodnsonprem-az-asse-sbx-001 \
--address-prefixes 10.3.1.0/24
Enter fullscreen mode Exit fullscreen mode
  • Peering
az network vnet peering create \
--resource-group rg-demodns-az-asse-sbx-001 \
--name vpeer-vnet-demodnsonprem-az-asse-sbx-001-vnet-demodnshub-az-asse-sbx-001 \
--vnet-name vnet-demodnsonprem-az-asse-sbx-001 \
--remote-vnet vnet-demodnshub-az-asse-sbx-001 \
--allow-vnet-access

az network vnet peering create \
--resource-group rg-demodns-az-asse-sbx-001 \
--name vpeer-vnet-demodnshub-az-asse-sbx-001-vnet-demodnsonprem-az-asse-sbx-001 \
--vnet-name vnet-demodnshub-az-asse-sbx-001 \
--remote-vnet vnet-demodnsonprem-az-asse-sbx-001 \
--allow-vnet-access
Enter fullscreen mode Exit fullscreen mode
  • DNS Server ( Windows )
SUBNET_ID=$(
az network vnet subnet show \
--resource-group rg-demodns-az-asse-sbx-001 \
--vnet-name vnet-demodnsonprem-az-asse-sbx-001 \
--name snet-default-az-asse-sbx-001 \
--query "id" \
--output tsv
)

az vm create \
--resource-group rg-demodns-az-asse-sbx-001 \
--name vm-dns-az-asse-sbx-001 \
--computer-name vmdns101s01 \
--image Win2019Datacenter \
--size Standard_D4s_v3 \
--accelerated-networking true \
--subnet ${SUBNET_ID} \
--nsg-rule RDP \
--admin-username azureuser \
--admin-password "<YOUR-PASSWORD>"
Enter fullscreen mode Exit fullscreen mode
  • Setup DNS server

ทำตามนี้นะครับ Install and Configure DNS Server on Windows Server 2019

  • Create Zone And Conditional Forward

1 Open DNS Manager

2 Create New Zone

3 Create New Zone

4 Create New Zone

5 Create New Zone

6 Create New Zone

7 Create New Zone

8 Create New Zone

9 Create New Zone

10 Set conditional forward to cloud

11 Set conditional forward to cloud

  • Test
nslookup test.onprem.contoso.com 127.0.0.1
nslookup test.private.contoso.com 127.0.0.1
Enter fullscreen mode Exit fullscreen mode

Create DNS Forwarding Ruleset

  • Create Rulesets

OUTBOUND_ID=$(
az dns-resolver outbound-endpoint show \
--resource-group rg-demodns-az-asse-sbx-001 \
--dns-resolver-name adpr-hub-az-asse-sbx-001 \
--name snet-outbound-az-asse-sbx-001 \
--query id \
--output tsv
)

az dns-resolver forwarding-ruleset create \
--resource-group rg-demodns-az-asse-sbx-001 \
--dns-forwarding-ruleset-name dfrs-onpremcontosocom-az-asse-sbx-001 \
--outbound-endpoints "[{id:'${OUTBOUND_ID}'}]"

VM_ID=$(
az vm show \
--resource-group rg-demodns-az-asse-sbx-001 \
--name vm-dns-az-asse-sbx-001 \
--query id \
--output tsv
)

VM_IPADDR=$(
az vm list-ip-addresses \
--ids ${VM_ID} \
--query '[].virtualMachine.network.privateIpAddresses' \
--output tsv
)

az dns-resolver forwarding-rule create \
--resource-group rg-demodns-az-asse-sbx-001 \
--ruleset-name dfrs-onpremcontosocom-az-asse-sbx-001 \
--forwarding-rule-name onprem-contoso-com \
--domain-name onprem.contoso.com. \
--target-dns-servers "[{ip-address:'${VM_IPADDR}',port:53}]"
Enter fullscreen mode Exit fullscreen mode
  • Link DNS forwarding ruleset to VNET
VNET_ID=$(
az network vnet show \
--resource-group rg-demodns-az-asse-sbx-001 \
--name vnet-demodnshub-az-asse-sbx-001 \
--query "id" \
--output tsv
)

az dns-resolver vnet-link create \
--resource-group rg-demodns-az-asse-sbx-001 \
--name link-vnet-demodnshub-az-asse-sbx-001 \
--ruleset-name dfrs-onpremcontosocom-az-asse-sbx-001 \
--id ${VNET_ID}
Enter fullscreen mode Exit fullscreen mode
  • Test from VM in Hub
nslookup test.private.contoso.com
nslookup test.onprem.contoso.com
Enter fullscreen mode Exit fullscreen mode
  • Test from VM in Spoke
nslookup test.private.contoso.com
nslookup test.onprem.contoso.com
Enter fullscreen mode Exit fullscreen mode

เพิ่มเติม
ถ้าเรามี firewall ที่ Hub

  • แนะนำให้ enable DNS Proxy ที่ firewall แล้วชี้ DNS Server ของ firewall มาที่ Inbound Endpoint ของ DNS Private Zone Resolver
  • ส่วนที่ Spoke Virtual Network ให้ set DNS Server เป็น Private IP address ของ Firewall

References

💖 💪 🙅 🚩
peepeepopapapeepeepo
Sawit M.

Posted on November 4, 2022

Join Our Newsletter. No Spam, Only the good stuff.

Sign up to receive the latest update from our blog.

Related