Securing DNS

Why?
It is a good idea to protect XMPP DNS records (or for that matter, any DNS record) with DNSSEC. To do this, you need to "sign" the DNS zone that contains your XMPP DNS record(s). DNSSEC adds digital signatures for DNS records in the zone, and these signatures can then be verified by other people using DNSSEC aware resolvers.

This page provides some basic instructions for signing a DNS zone with DNSSEC, using the popular ISC BIND DNS server software. For best results, a relatively recent version of BIND should be used. The current version is 9.9.4, but the instructions outlined here should work with BIND 9.8 and above. There are many different configuration options that can be used to deploy DNSSEC with BIND, which can feel a bit daunting for newcomers. This document instead discusses a smaller number of simple configurations which should work for many sites.

Generating DNSSEC keys
DNSSEC uses asymmetric key cryptography, where every zone has at least one public and private key pair. The private key is kept securely on the signing server and is used to sign the zone contents. The public key is published into the zone itself so that remote DNS resolvers can obtain and use it to check signatures. In practice most sites use a 2 level hierarchy of key pairs, a Key Signing Key (KSK) and a Zone Signing Key (ZSK). The KSK is used to sign all the Key records, and ZSK is used to sign all the rest of the records in the zone. In the simplest case a zone will have one of each. This hierarchical configuration makes a number of security and operational tasks easier.

The first order of business is to use the "dnssec-keygen" command to generate DNSSEC keys. In BIND, it is common practice to configure a separate directory for each zone. This makes it easier to manage the zone files and their associated keys together, and I recommend this approach. In the example below, we generate a 2048-bit RSA-SHA256 keypair for the KSK and a 1024-bit 1024-bit RSA-SHA256 keypair for the ZSK for the hypothetical zone "example.net":

cd $ZONEDIR          (replace $ZONEDIR with the actual directory containing your zone) dnssec-keygen -a RSASHA256 -b 2048 -n ZONE -f KSK example.net dnssec-keygen -a RSASHA256 -b 1024 -n ZONE example.net

This will generate a number of key files that look something like this:

Kexample.net.+008+33738.key Kexample.net.+008+33738.private Kexample.net.+008+38125.key Kexample.net.+008+38125.private dsset-example.net.

The K* files contain the keys (public and private). The two numbers embedded in the file names represent the key algorithm, and a "key-id" which is a hash of the key. In this case 008 corresponds to DNSSEC-SHA256. The "dssec-example.net" file contains DS (Delegation Signer) records that can be communicated to operators of the parent zone, who would need to establish a secure delegation to you.

The next thing is to enable DNSSEC on your nameserver. This is done simply by adding "dnssec-enable yes" to the options section of your nameserver configuration file, typically "named.conf":

options { [...]       dnssec-enable yes; [...]

Signing a static DNS zone
One of the most common ways to use BIND is with text zone files that are edited by hand, and that are reloaded into the nameserver after changes are made. These files are written in the standard "Master Zone format" (See RFC 1035, Section 5) for details. The "dnssec-signzone" command can be used to sign this text file and produced a new file containing the signed zone. Let's say the example.net zone is contained in file "zonefile". The following command when executed in the directory containing this file and the DNSSEC keys generated previously, will sign the zone:

$ dnssec-signzone -N increment -o example.net -S zonefile

This will generate new file called "zonefile.signed". The "-S" flag invokes the "smart" signing mode, in which the program will automatically search the directory for valid key files to sign the zone with, and will automatically add DNSKEY records for the public keys into the zone. The "-N increment" flag will automatically update the serial number in the SOA record.

The last step is to instruct the BIND nameserver to use "zonefile.signed" instead of "zonefile" for the zone contents by modifying its configuration file (normally "named.conf"). An example zone configuration stanza follows:

zone "example.net" { type master; file "zones/example.net/zonefile.signed"; }

And lastly, reload or restart the nameserver, using whatever method you normally use. If you use the nameserver control utility "rndc", you can surgically reconfigure and reload only the affected zone with the command:

rdnc reconfig

Note that DNSSEC signatures have an expiration date. By default the signatures generated by dnssec-signzone expire 30 days into the future (this can be changed with the "-e" option). Expiration dates are needed to prevent potential attackers from being able to perpetually replay an old DNS record that might have been subsequently updated. So even if you don't make any changes to the base DNS records, you will need to periodically re-sign the zone, using this same procedure.

You will also need to co-ordinate with your parent zone to have a secure delegation established. This is described later in this document.

Signing a dynamic DNS zone
Some more sophisticated DNS installations use "Dynamic" zones. In this configuration zone files are no longer updated by manually with a text editor. Instead, the DNS "Dynamic Update" protocol is used to send instructions to a running nameserver to add/delete/modify specific DNS records. BIND has very good support for integrating DNSSEC with such zones. We describe below, a very simple and low maintenance configuration that works with dynamic zones.

We generate the DNSSEC signing keys using "dnssec-keygen" as usual. Then we simply configure a zone stanza in named.conf as follows:

zone "example.net" { type master; update-policy local; auto-dnssec maintain; file "zones/example.net/zonefile"; key-directory "zones/example.net"; };

The "update-policy local" directive tells the nameserver that a static TSIG key (only accessible locally on the machine) is used to authenticate dynamic updates. The "-l" option to "nsupdate" uses this key to send authenticated update commands.

The "auto-dnssec maintain" directive tells the nameserver that this is a dynamic zone, and then it should be automatically signed (if relevant DNSSEC keys are available), and periodically re-signed as necessary. The "key-directory" directive specifies where the keys for the zone are to be found, in this case, the same directory that contains our zone file.

Once the nameserver is reconfigured, it will look for any valid DNSSEC keys for the zone, and perform the necessary signing. Subsequently, dynamic update can be used to introduce changes into the zone, and the nameserver will automatically sign the changed records and generated associated metadata records as necessary.

You probably already have XMPP related records created in your zone, but here's an example of using "nsupdate" to add these records:

$ sudo -u named nsupdate -l > ttl 86400 > zone example.net. > update add xmpp.example.net. A 10.5.5.5 > update add _xmpp-client._tcp.xmpp.example.net. SRV > update add _xmpp-client._tcp.example.net. SRV 5 0 5222 xmpp.example.net. > update add _xmpp-server._tcp.example.net. SRV 5 0 5269 xmpp.example.net. > send $

Example output of DNS queries to a signed zone
The dig tool can be used to query records in a signed zone from the command line. The "+dnssec" flag causes it to request DNSSEC records and attempt to validate the signatures. The "+multi" option pretty prints and annotates the output of some of the records.

Here's an example query for some XMPP related records. For the sake of brevity the output has been trimmed to only show the "answer" section of the DNS response. The RRSIG record in the response contains the DNSSEC signature associated with the queried record.

$ dig xmpp.example.net. A +dnssec +multi

xmpp.example.net. 86400 IN A 10.5.5.5 xmpp.example.net. 86400 IN RRSIG A 8 3 86400 (                               20140201184024 20140102174024 33738 example.net.                                ZcRs5wBwyXYpY3vkgON1eXgT65VTlf+ZRwQVtpp0Bb00                                Fl4kQIsIcNONNfQchVdfi2adLM3IL1MhDtMhab0VRrWF                                zqkdALAKncaJ0FkF1x40oI9x0ku5LT/tNqWvkqqXTqbs                                4+LN2ubZqBbGaXWYR7oDHDdXqjeVKh7GsH0Vq2A= )
 * ANSWER SECTION:

$ dig _xmpp-client._tcp.example.net. SRV +dnssec +multi

_xmpp-client._tcp.example.net. 86400 IN SRV 5 0 5222 xmpp.example.net. _xmpp-client._tcp.example.net. 86400 IN RRSIG SRV 8 4 86400 (                               20140201184317 20140102174317 33738 example.net.                                XYCywqy4UowQ9EiLH0dfgR3Nz2qNSBAwJ+deyOCTos6x                                rQrppQgqg97WiZYLywP3RZtaucrQtQGb05j65x72I25P                                8jZF4eTJ3KSiLgghXtPH+qFvxjWxViIRGTIp+V6H3Jjo                                odm5IqPrCPfewfGaCq821i6BwMPqRPLcsmZKVWA= )
 * ANSWER SECTION:

$ dig _xmpp-server._tcp.example.net. SRV +dnssec +multi

_xmpp-server._tcp.example.net. 86400 IN SRV 5 0 5269 xmpp.example.net. _xmpp-server._tcp.example.net. 86400 IN RRSIG SRV 8 4 86400 (                               20140201184317 20140102174317 33738 example.net.                                ZFOhyosWq4wFZ/RA7FJLyK9/5ciu/hx0TTFFl4eywIkY                                ZLuwmu614lFxY4Cmy32B06Waovt1DQgBViJzAZ+ABcH1                                MGF9Etj40A4nihRUwsidwKzMZH00hgIIiIfwVN5OGNN4                                8q0QbmhdjBoyCBPW06Nk0cXRIGVs1U1nnVrMhXo= )
 * ANSWER SECTION:

NSEC3 zones
There is a newer variant of DNSSEC called NSEC3 (See RFC 5155 for details) that uses a different scheme for authenticating denial of existence (i.e. proving that a DNS name doesn't exist). The base DNSSEC protocol uses a record called NSEC for this purpose, which chains together DNS names in a zone. One side effect of its design is that all records in a zone can be enumerated by anyone. Although the DNS was always intended to be a public database, for some sites this is problematic. NSEC3 provides additional defense against zone enumeration by chaining together hashes of names rather than the actual names themselves. It also has a feature called opt-out that is needed by some very large delegation centric zones to aid incremental deployment. NSEC3 introduces a lot of additional complexity, and makes it more difficult to visually debug DNSSEC, so I would not recommend using it unless you have a specific reason do to do so. But NSEC3 is well supported by BIND.

Very briefly for static zones, you need to provide some additional parameters to dnssec-signzone, eg.

dnssec-signzone -o example.net -N increment \ -3 9EBA4228 -H 5 \ -S zonefile

Here, -3 says use NSEC3, the string following is a salt, and "-H 5" specifies how many iterations of hashes are to be applied to the DNS names.

For dynamic zones, you can use either send an update instruction to insert an NSEC3PARAM record (with these parameters) into the zone, or use "rndc" to achieve the same effect, e.g.:

sudo -u named rndc signing -nsec3param 1 0 5 9EBA4228 example.net

Obtaining a secure delegation
DNSSEC uses a hierarchical chain of trust, in which DNSSEC public keys (typically KSKs) for zones are signed by their parents following the top down DNS delegation hierarchy. In order to do this, you need to co-ordinate with the operator of the parent zone to have a special record called a Delegation Signer (DS) record installed which together with its signature in the parent authenticates your zone's key. How to do this varies by operator, so you should contact them for details. For a lot of the big gTLDs (.com, .net, .org etc), typically you interact with a "registrar", and provide them with either your KSK DNSKEY record, or its DS record. The parent zone signs and installs the DS record.

With BIND, the dnssec-signzone command automatically generates a file called "dsset- " with a correctly formed DS record set, which can be communicated to the registrar or parent zone operator. Note that currently, not all DNS registrars support DNSSEC, so you may have to find one that does.

If your parent zone isn't signed, or if for some other reason you are unable to obtain a secure delegation, you might want to look into use of a DNSSEC Lookaside Validation (DLV) registry. This is a mechanism for locating DNSSEC keys offpath from a well known repository. ISC.org operates one at https://dlv.isc.org/

Configuring a DNSSEC validating resolver
Setting up a DNS resolver to authenticate DNSSEC signed records in other zones is very easy with BIND. With modern versions of BIND, you just need to install 2 directives in the "options" section of named.conf:

options { [...]       dnssec-enable yes; dnssec-validation auto; [...] }

You may also want to add one more line to use the DNSSEC Lookaside Validation (DLV) registry operated by isc.org.

dnssec-lookaside auto;