CVE 25th Anniversary
On the long-term scale of human history, 25 years is nothing.
Read postThis is a repost of a blog by Richard Neal from TalkDNS, reprinted with permission.
DNS over HTTPS (DoH) is becoming much more prevalent now. Both Google Chrome and Mozilla Firefox have supported it since 2019 and Microsoft Windows 10 21H2 is expected to introduce support for it later in 2021. With this in mind it might be time to start planning to support DNS over HTTPS if you run a BIND DNS server.
This article shows how to configure BIND 9.17 (with experimental DNS over HTTPS support) on Ubuntu 21.04 and using a LetsEncrypt certificate. Using LetsEncrypt means it’s a no-cost solution and is fully supported by most DNS over HTTPS clients – including Google Chrome, Mozilla Firefox, Microsoft Edge, and of course BIND’s own dig
command.
Throughout this article I’ll use the following values for email address (for the LetsEncrypt certificate) and for the server name:
Wherever you see these values below you should of course replace them with your own email address and your own server name.
We’ll go through the following steps in this article:
named.conf.options
purely to get a running BIND instancenamed
to access our LetsEncrypt foldersnamed.conf.options
to support DNS over HTTPSnamed
’s configuration files whenever it does soWhilst the following steps may very well work with an older Ubuntu release I have specifically tested this on Ubuntu 21.04 (Server edition). You can download their ISO from here.
The Ubuntu 21.04 repositories include BIND 9.16, but DNS over HTTPS is currently only available in the BIND 9.17 Development release (specifically 9.17.10 or higher). In order to install BIND 9.17 we therefore need to add the ISC’s development branch repo’s:
$ sudo add-apt-repository ppa:isc/bind-dev
$ sudo apt-get update
$ sudo apt install bind9
As BIND9 installs you will see references to ppa.launchpad.net. This confirms that it’s the BIND 9.17 development release that’s being installed rather than Ubuntu’s default BIND 9.16.
Now we need to make sure BIND starts whenever the server (re)boots:
$ sudo systemctl enable named
If you’re running ufw
(the Uncomplicated firewall) then you’ll also need to open the necessary ports for BIND9:
$ sudo ufw allow Bind9
$ sudo ufw allow http
$ sudo ufw allow https
We need both HTTP and HTTPS because LetsEncrypt’s Certbot runs on HTTP to validate and generate an HTTPS certificate for our BIND server.
named.conf.options
Purely To Get A Running BIND InstanceI’m going to make the assumption that your BIND server is behind a firewall on your LAN. As such it won’t be accessible to any clients other than those on your network. For the purposes of this article I’m therefore including only a very basic rudimentary named.conf.options
file which will allow BIND to start successfully. You shouldn’t use this bare bones named.conf.options
file on a production instance or one that’s exposed outside your LAN.
$ sudo nano /etc/bind/named.conf.options
Update the file so it has only the following rows. Alternatively if you’re a seasoned BIND administrator and you have your own standard configuration then please use it. The purpose of the following configuration is simply to prove that BIND “works” before we then start enabling DNS over HTTPS.
options {
directory "/var/cache/bind";
recursion yes;
allow-recursion { any; };
listen-on { any; };
listen-on-v6 { any; }; # you can remove this line if you don't need IPv6 support
dnssec-validation auto;
};
We should now start named
and make sure traditional DNS name resolution is working (over UDP and TCP port 53). First we validate our named.conf.options
file:
$ sudo named-checkconf /etc/bind/named.conf.options
If that command returns no results then we’re all good – BIND has found no errors in our configuration file. So now we’ll start the named
daemon and then run a quick test to make sure DNS name resolution is working correctly. We issue the systemctl restart
command in case this system has been rebooted already (remember that we set named
to start automatically earlier in this process):
$ sudo systemctl restart named
$ dig @ns1.talkdns.net isc.org A
If all goes well you should get the IP address of isc.org: 149.20.1.66
Now it’s time to install Certbot to manage our LetsEncrypt certificate:
$ sudo apt install certbot
Once installed we’ll use Certbot to issue our certificate. Remember to replace the email address and server name with your own of course!
$ sudo certbot certonly --standalone --preferred-challenges http --agree-tos --email certs@talkdns.net -d ns1.talkdns.net
If all goes well you should see a message similar to the following:
Congratulations! Your certificate and chain have been saved at:
/etc/letsencrypt/live/ns1.talkdns.net/fullchain.pem
Your key file has been saved at:
/etc/letsencrypt/live/ns1.talkdns.net/privkey.pem
Your certificate will expire on 2021-08-28.
The contents of the “live” folder are actually symlinks to the real certificate which is stored in the “archive” subfolder of /etc/letsencrypt/
Now we need to fix the permissions on the live and archive folders so that named
has permission to read these files:
$ sudo chmod 0755 /etc/letsencrypt/live
$ sudo chmod 0755 /etc/letsencrypt/archive
And then we need to change the group and permissions for the private key file
$ sudo chgrp bind /etc/letsencrypt/live/ns1.talkdns.net/privkey.pem
$ sudo chmod 0640 /etc/letsencrypt/live/ns1.talkdns.net/privkey.pem
named
To Access Our LetsEncrypt FolderBy default AppArmor will block named
from accessing the certificates in the LetsEncrypt folder. Rather than modifying AppArmor’s named
profile (which would be overwritten during an upgrade) we create a special AppArmor local
file. These local
files are a supported way of telling AppArmor that we have a slightly special configuration and they are preserved during an upgrade.
$ sudo nano /etc/apparmor.d/local/usr.sbin.named
This file should contain a single line as follows, including the comma at the end. It allows recursive read-only access to all files and folders in /etc/letsencrypt
:
/etc/letsencrypt/** r,
Now we need to reload the named AppArmor profile:
$ sudo apparmor_parser -r /etc/apparmor.d/usr.sbin.named
named.conf.options
To Enable DNS Over HTTPSEnabling DNS over HTTPS support in BIND means editing the named.conf.options
file again. We need to make two changes:
$ sudo nano /etc/bind/named.conf.options
Add the following lines to the very top, above the options {
statement:
tls local-tls {
key-file "/etc/letsencrypt/live/ns1.talkdns.net/privkey.pem";
cert-file "/etc/letsencrypt/live/ns1.talkdns.net/fullchain.pem";
};
Then add the following lines in the main options
statement (e.g. right before the final “};“:
listen-on port 443 tls local-tls http default {any;};
listen-on-v6 port 443 tls local-tls http default {any;}; # you can remove this line if you don't need IPv6 support
Save the file, and then let’s check again that our named.conf.options
file is OK:
$ sudo named-checkconf /etc/bind/named.conf.options
Provided all is well we now reload named
so that it reads our configuration changes. We use reconfig
rather than reload
because we haven’t made any changes to our zone files:
$ sudo rndc reconfig
If we now quickly check the syslog we should find that BIND has loaded successfully:
$ tail /var/log/syslog
Make sure there are no errors regarding file access, the TLS cert, or AppArmor
We can test DNS over HTTPS from the local system by using dig
and specifying a DoH query by using the +https
parameter:
dig +https @ns1.talkdns.net isc.org A
If all is well then you should once again get the IP address of isc.org: 149.20.1.66. If you look closely at dig
’s output you should also see something similar to the following. This confirms that the query/response operation was performed successfully over HTTPS (TCP port 443) rather than traditional UDP port 53:
;; SERVER: 51.210.161.197#443(ns1.talkdns.net) (HTTPS)
Alternatively if DNS over HTTPS isn’t working then you’ll either get an error message or dig
will timeout.
Ideally you should now test from a remote system as well. If you’re using ufw
or any other software firewall then that will also confirm that you have the necessary ports open. If you’re running more than one name server (and if not, why not?!) then you can run dig
(from BIND 9.17.11 upwards) to make an identical query as above.
named
’s Configuration Files Whenever It Does SoOur last step is to make sure that Certbot is setup to renew the certificate when necessary, and to reload named
’s configuration whenever it does so. This steps is important because otherwise named
won’t be using the correct HTTPS certificate.
$ ls /etc/cron.d
Make sure that “certbot” exists (if not then go to the Certbot homepage to read how to setup automated renewal)
Now we need to add a deploy hook to Certbot so that named
reloads its configuration files whenever Certbot renews a certificate. Here again we use reconfig
rather than reload
because we’re not making any changes to zone files at this point. On a BIND server with many zone files it’s much quicker to simply reconfig
rather than go through a full (and unnecessary) reload:
$ sudo nano /etc/letsencrypt/cli.ini
Add the following line at the end:
deploy-hook = rndc reconfig
You can test this by running:
$ sudo certbot renew --dry-run
You should see:
Dry run: slipping deploy hook command: rndc reconfig
That’s it! You’re all done. You now have a BIND 9.17 name server running DNS over HTTPS using an auto-renewing LetsEncrypt certificate.
What's New from ISC