Setting up Forwarding Bind DNS Server in Azure Linux Virtual Machine

The objectives are to setup a forwarding DNS server (maybe only exposed to our internal VNET) that redirects all the incoming queries to the Azure Magic address (168.63.129.16) and responds to the results. Set this up in an Azure VM with Redhat CIS 8 hardened image.

Another reason: Azure Magic DNS drops forwarded packets

Whenever you spin a VM, you are set to resolve the DNS for all traffic via Azure Magic address (168.63.129.16). Doing so will also make your DNS query traverse through all the Azure Private DNS you may have linked to the VNET of this VM via VNET Links.

The not so happy situation is when you want to send traffic to Azure Magic address for DNS queries which is originating from an external network. Example of external network is Azure VPN Gateway clients connected to your VNET and trying to do split tunneling and asking Azure VNET Gateway for DNS resolution. Clients of your Azure VNET Gateway will not able to resolve a DNS by sending DNS queries to Azure Magic address. I found by packet capture that the Azure Magic address drop these DNS queries. I believe this is by security design.

As a workaround, I found that spinning an intermediary BIND DNS VM that can act as DNS forwarder within your VNET and asking your VPN’s VNET to use a custom DNS setting to that of the IP of this newly spun DNS VM fixes the issue. Such that going forward, your VPN clients will be sending DNS queries to the BIND VM, which in return forwarding these requests to Azure Magic address, thus will include all your Azure Private DNS zones (including zones for your private endpoints!).

You can setup a DNS forwarder to essentially any DNS server over the Internet if you wish.

Quick Setup

This guide makes use of something called cloud-init. You can check out the tutorial available on the official site.

The process is just to save the script and execute it as part of the spinning the VM. And you’re done.

Save Cloud Init script

Save the following code as cloud-init.txt in your shell.

#cloud-config
runcmd:
  - dnf install bind bind-utils -y
  - iptables -A INPUT -p udp -m udp --dport 53 -j ACCEPT
  - iptables -A INPUT -p tcp -m tcp --dport 53 -j ACCEPT
  - sudo systemctl disable systemd-resolved
  - sudo systemctl stop systemd-resolved
  - systemctl start named
  - systemctl enable named
  - setenforce Permissive
  - cp /etc/named.conf /etc/named.conf.orig
  - echo 'options { listen-on port 53 { any; }; listen-on-v6 port 53 { ::1; }; allow-query { any; }; recursion yes; dnssec-enable yes; dnssec-validation yes; forwarders { 168.63.129.16; }; };' > /etc/named.conf
  - systemctl restart named

Execute the AZ CLI to start VM

The following script will create a resource group and spin a VM. Pay attention to the last parameter of the AZ CLI where “custom-data” is passed, that is file name from the previous step containing cloud init script.

az group create --resource-group BindVMRg --location eastus
az vm create --resource-group "BindVMRg" --name "BindVM" --image "center-for-internet-security-inc:cis-rhel-8-l1:cis-rhel8-l1:latest" --generate-ssh-keys --custom-data cloud-init.txt

Future work

You are free to utilize something similar to spin and automate your Linux virtual machine setup in Azure. For example, you can setup a web server, an FTP server, a DevOps agent and so on using the above automation.

Leave a Reply