The Goal

Todays excursion goes to enable DNSSEC and DANE on a test domain. This should go a long way towards making my systems more independent and resilient.

As a first step I’m going to enable locally validated DNSSEC resolving on my hosts. If I can’t listen, I don’t need to speak.

Then I’ll start signing my test zone and when everything goes well, I’ll also add DS records for this domain.

The motivation and guidance for this post was brought to you by c’t’s article about DNSSEC and DANE.

Enable DNSSEC validation

Since I’m running my own ISC Bind installaction, and I do not want to resolve with my authoritative bind, I’ve got to clean up that first.

In /etc/bind/named.conf.options add the following:

# disable recursion to avoid being open as reflector for DoS attacks
recursion no;
# only listen on specific NS IPs to allow local resolver to bind to localhost:53
listen-on { 144.76.55.125; };
# no external IPv6. yet.
listen-on-v6 { none; };

This keeps bind from blocking the port 53 on localhost needed for the next step: install a dedicated resolver, unbound.

The only configuratoin necessary is to configure unbound to only listen on localhost, so that it in turn does not interfere with the authoritative nameserver on the external IP. Note that a restart is required for unbound to change it’s interface bindings.

Finally, I can change resolve.conf to point to the new nameserver and dig +dnssec and everyone else now can rely on a trustworthy and fast resolver for DNSSEC.

Preparing the zone

A little digression: bind can automatically keep all the ephemeral ducks^Wkeys lined up, if told to do so. Luckily, this test zone is static, so I can just enable

auto-dnssec maintain;
inline-signing yes;

and bind will happily ever after keep that zone signed.

Except that bind 9.8 (which is the bind in Debian 7) does not yet support inline-signing. A bind, so to say. There is a backport of 9.9, which has introduced inline-signing, so not much is lost here. EXCEPT that the bind9 backport requires an upgraded systemd, and while I do appreciate its features, I do not appreciate unrequested major upgrades on a slow afternoon. So back to the drawing board. The dependency seems to go via the init-system-helpers package, which in this case, is not helping at all. Going from the description, I do not believe that anything there should keep me from staying on systemd 44, except the laziness of the responsible developers. Since this is FLOSS, I count myself the the latter group and start poking at bind’s backported source.

Only a “few” minutes later, 1:9.9.5.dfsg-4~bpo70+1~dasz1 is installed, and running, and it already has created a “.signed” file for this zone. In /etc.

Preparing the keys

I prepared a secure directory, /etc/bind/keys, to store the keying material. Creating the keys seems simple enough:

dnssec-keygen -a RSASHA256 -b 2048 -K /etc/bind/keys -n ZONE example.com
dnssec-keygen -a RSASHA256 -b 2560 -f KSK  -K /etc/bind/keys -n ZONE example.com

It will take “a while” though, as dnssec-keygen is using /dev/random and this VM is notoriously starved for entropy. “A while” is now around ten minutes and counting. N.b.: Putting aside the laptop on pattery will lead to unintended disconnects, when it goes to sleep. In the end it took 30 minutes for the first and 101 minutes for the second keypair.

Note to self: deploy egd or similar.

If bind does not have rights on the key material, it will complain when trying to load them on startup/reload - as I can report from having it tried out. The dnssec-keygen creates the private key mode 0600, so I opted for the simpler method of making the keys owned by the bind runtime user. A more defensive approach would be to let root own the keys and only give g=r rights to the bind runtime group. I might consider that when coding this all up in puppet.

Publishing the keys

Bind has already done the most tedious work for us: signing the zone and records and it will also keep the signature up to date by recycling the key every 30 days. The final missing piece is to publish our public key in the parent zone, so that everyone has a verifiably trustpath from the DNS root zone to my testing zone’s keys and content.

The proper records to add to the parent zone are generated by

dnssec-dsfromkey PATH_TO_KSK.key

the KSK is obviously the bigger of the two keyfiles, although dsfromkey will happily use the normal key too. I presume it’ll just create a non-functional DS delegation, breaking everything horribly. I’ll try to avoid testing this theory.

So, off to the registrar and submit those records!

Finishing touches

So after deploying the inline-signing to my test zone, nagios noticed that my serial numbers were off between my master and my slave NS. It turns out, that bind does increment the serial number when doing the signing dance. Which is only proper, given that the serial number should be incremented every time something changes in the zone. I’ll need to keep that in mind when doing manual updates.