Adventures in DNSSEC

Posted: Sun, 29 June 2014 | permalink | 2 Comments

DNSSEC is one of those things that have been on the “I should poke at that sometime” list, but today I decided to actually get in and play around with it. Turns out it’s pretty trivially easy to setup, but I got bitten by a few “gotchas” during testing, that I thought worthwhile to document. Since I like to explain things, a lot of this article isn’t “how to” so much as “how does”.

Configuring The Resolver

First off, you need a resolver1 that you can trust, and which implements DNSSEC validation. In theory, you could use your ISP’s resolvers (if they’re DNSSEC-enabled), or even Google’s public resolvers (8.8.8.8 and 8.8.4.4), but it’s really not recommended – how much do you trust those, really? More importantly, how much do you trust the network path between them and you? Frankly, running a local on-host caching resolver is trivial, consumes next-to-no resources, and is highly recommended. It’s what I did.

I used unbound, finally casting free the venerable dnscache, which has served me well for many years. I chose unbound because it fits the “do one small thing, and do it well” philosophy that I cherish (unlike BIND), and because it’s what all the cool kids appear to be using these days. Installing it was as simple as apt-get install unbound – it’s available in pretty much every distro, I believe.

Out of the box, unbound in Debian wheezy comes configured for DNSSEC validation. Other methods of installation might not be so amenable, so just make sure your unbound.conf liiks like this, so that DNSSEC is enabled:

server:
    auto-trust-anchor-file: "/var/lib/unbound/root.key"
    val-log-level: 2

The val-log-level line isn’t strictly required, but I found it useful to have unbound log info on validation failures to syslog. Season to taste.

You also have to configure your system to actually use your new, shiny local resolver. Editing /etc/resolv.conf would, in an ideal world, work Just Fine, but between Magical Unhelpful Pixies (I’m looking at you, NetworkManager) and DHCP, it often isn’t that easy. Ultimately, though, you should configure your system so that the only resolver in /etc/resolv.conf is always 127.0.0.1. Anything else is a security hole waiting to happen. If you’re using DHCP and a recent version of ISC dhclient, adding supersede domain-name-servers 127.0.0.1; to dhclient.conf should do the needful.

Weighing the (Trust) Anchor

Whatever local resolver you choose, you need to tell it about “trust anchors”. This is a key (or keys) which are trusted to sign all the other data that the resolver will find. Like the rest of the DNS, DNSSEC is hierarchical, and you need to know who to “start with” before you can start.

To resolve a name using DNS, you ask the “root servers” for the answer to a question (say, “what is the address of www.example.com?”). The root server doesn’t know the answer, but it knows who to ask, and it tells you where to go (typically, “go ask the DNS servers for .com, which are X, Y, and Z”). Then you ask those servers, and they probably don’t know, but they know who to ask, and they tell you to go ask those servers. This continues until you finally get a server which says, “oh, yes, I know the answer to that!” and hands over the information you’re after.

In DNSSEC, you get digital signatures that prove that the answers you get from each DNS server you ask are legit, and not forged. So when you ask the root servers, “what is the address of www.example.com?”, they answer, “I don’t know, but go ask DNS servers at addresses X, Y, and Z – and by the way, you can trust this answer is legit because here’s this signature you can check”. To verify a signature is legit, you need to know that the key used to make the signature is trustworthy, and it wasn’t just any ol’ key that made it – similar to how an ink scribble on a page doesn’t mean anything unless you know what the signature you’re looking at should look like.

DNSSEC has two ways to make sure you know who to trust. Firstly, those “trust anchors” I mentioned three paragraphs ago. These are the keys that the root servers use to sign the responses they send out. You tell unbound (or your local DNSSEC-enabled resolver of choice), “if you see a signature provided by this trust anchor key, you can trust it to be legit”. The second way to trust is key is to have someone you already trust say, “oh, you can trust this key, too”. This is done by providing more data in the answer that you get from the root servers. So the full answer you get from the root servers when you ask, “what is the address of www.example.com?” looks like this:

I don’t know, but you should ask the DNS servers at addresses X, Y, and Z. You can trust their answers because they’ll sign their responses with key K. Finally, you can trust that I’m legit because of this signature I’m providing you, generated from key T.

Assuming that T is the trust-anchor key you’ve already told unbound to trust, it can then trust all of the information it got from that first question. When it then goes to DNS server X and asks, “Hey, do you know the address of www.example.com?”, that server can send back its own response saying:

Gee, shucks, I don’t know, but DNS servers at P and Q can help you. You can trust them because they’ll sign responses with key S. And just to show you I’m on the level, check out this nifty signature I made, signed with key K.

Since a server we trust told us to trust key K, and then we got a response signed by key K that told us to trust key S, when we then go and ask server P and get a response signed by S, we’re still demonstrably secure. Neat setup, right?

Anyway, now you know all about trust anchors. How do you set it up? For unbound, it’s capable of “priming” the trust anchor itself. It does this by retrieving a copy of the trust anchor from [a well-known HTTPS URL]((https://data.iana.org/root-anchors/root-anchors.xml), which provides a reasonable measure of security – the trust anchor file should be safe as long as that HTTPS server is trustworthy. For the properly paranoid, you should determine an alternate means of verifying that you have the correct root key (a web search for “DNSSEC root key attestation” would probably be a good start).

Testing

It’s always handy to know that something’s working as you expect. For something that’s important for security, that goes double. So, how do you test that your DNSSEC-capable resolver is, indeed, working as designed?

Well, firstly, you can test that the resolver, by itself, is working. This is simple: do a query for a zone known to have broken DNSSEC. Thankfully, some nice people (Comcast, specifically) have already set this up. You can test a resolver for DNSSEC-correctness with this command:

dig @127.0.0.1 www.dnssec-failed.org

If dig gives you back an IP address, something is broken. The correct, “my DNSSEC works!” response should be a status: SERVFAIL response.

That’s all well and good, but having a resolver that works isn’t much good if nothing’s actually using it. Your system configuration has probably got some other resolvers configured into it (such as those provided by a DHCP server), and you’ll want to make sure those aren’t getting used2. The trivial test is to visit http://www.dnssec-failed.org in your browser. If that comes back with a page, then something’s still wrong.

A more user-friendly test of your DNSSEC configuration is provided by http://dnssectest.sidnlabs.nl/test.php, which will display a page either way, and give you a tick or a cross depending on whether you’re DNSSEC-enabled or not.

One thing to be wary of when you’re doing browser tests is caching. I spent far too long trying to work out why “unbound wasn’t working”, when in actual fact it was working fine, it’s just that both my browser and local caching proxy (squid) were caching DNS requests3. So, even after I’d correctly setup unbound, visiting the test sites was providing me with erroneous results.

Fixing up the browser was simple enough. In Chromium, visiting chrome://net-internals#dns will show you what’s being cached, what resolv.conf settings are being used, and allow you to clear the browser’s resolver cache.

Squid was similarly simple, although it took me a while to figure out that it was causing me grief (software that “just works”, being so rare, tends to slip your mind, and so I often forget that squid is actually doing me good). Restarting squid has the appropriate result (clears the DNS cache), but in the end I decided that having another layer of caching wasn’t going to help significantly when I’ve got an on-host DNS cache already, in unbound. So, I just turned the knobs for DNS caching in squid right down:

negative_dns_ttl 1 second
positive_dns_ttl 1 second

And voila! All was well.

In summary…

DNSSEC is cool. It’s easy to get going with, and over time it will provide more and more practical benefits (I am a DANE fanboi). Get started with it now, and you’ll be ahead of the curve.


  1. A “resolver” is a program which takes a name, does all the DNS queries required to get the data associated with that name, and return it to whoever wanted to know. This can be a library which links to a client application, or it can be a separate program which receives DNS requests itself.

    There are usually both types of resolvers in use for a typical Linux system to resolve names. On every machine, in every program, there is the so-called “stub resolver”, which is part of libc, and does nothing except create DNS requests and send them to the addresses listed in resolv.conf. Also present, although not always running on every machine (typically your ISP or network admin has some running for everyone to share) are one or more “recursive resolvers”, which are separate programs which take DNS requests, do all of the queries themselves, and return the result to the stub resolver for presentation to the client program which made the request in the first place.

    You will see this material again.

  2. You can configure dhclient to use your local resolver instead of the DHCP-provided ones by simply setting:

    supersede domain-name-servers 127.0.0.1;
    

    in your dhclient.conf file.

  3. It also didn’t help that I hadn’t correctly knobbled dhclient the first time around, and so even when I thought I was only resolving against my local unbound server, it was still actually using the DHCP-provided resolvers…


2 Comments

From: Robert Edmonds
2014-06-30 04:09

Actually, this description of unbound-anchor is not quite accurate. unbound-anchor has a built-in copy of the root trust anchor, which it tries to make sure is up to date via in-band DNS lookups to the root servers. Only if that fails does it do the HTTPS fetch of the trust anchor, but it doesn’t rely on SSL certificate validation of the HTTPS connection for security, instead it checks a detached PKCS#7 signature of the .xml. The built-in key material that it relies on for these two mechanisms can be printed with “unbound-anchor -l”.

The process is described in detail in the comments at the top of the unbound-anchor.c file.

From: Matt Palmer
2014-06-30 13:44

Hi Robert,

Thanks for the clarification. I must have misunderstood the documentation slightly.

Post a comment

All comments are held for moderation; markdown formatting accepted.

This is a honeypot form. Do not use this form unless you want to get your IP address blacklisted. Use the second form below for comments.
Name: (required)
E-mail: (required, not published)
Website: (optional)
Name: (required)
E-mail: (required, not published)
Website: (optional)