DNSSEC: Get it Right the First Time
Signing my first zone was quite difficult and needlessly so.
This post will give those familiar with operating a DNS server an intuition about DNSSEC by helping you sign your first zone correctly.
What's DNSSEC about, anyway?
DNSSEC is based on public key cryptography. You will be signing your zones with a private key and clients will verify the signatures against your public key.
When you “sign a zone” you are really signing every record in the zone and adding those signatures as new records in the zone. The standard specifies that the nameserver will include the signatures with the records in the response.
DNSSEC adds new record types, in addition to the common A, PTR, MX, CNAME, SOA, TXT, and SRV records we get:
DNSKEY:
The DNSKEY record is your zone's public key. Clients will retrieve this record to verify the signatures that they receive. There can be many DNSKEY records, since you can sign your zone with multiple keys.
RRSIG:
These are the signature part of signing your zone. Every record (that is not an RRSIG record) will be signed by the private key and the per record signature will be stored in a RRSIG record in the zone.
DS:
The DS record is a hash (usually SHA-1 or SHA-256) of the zones public key. This record exists in the parent zone to establish a chain of trust (see below).
NSEC or NSEC3:
In non-secure DNS, when a name doesn't exist the nameserver returns no records... no records means nothing to sign... means no signatures. The NSEC records are a mechanism to allow DNSSEC to authenticate the non-existence of a name by returning the Next SECure record in the zone (which is signed).
Let's Sign a Zone
You have a zonefile, it should be named after your zone. It's not
called nocko.se
, but imagine it were or better yet just replace
nocko.se
with your zone name everywhere it occurs in this
document. Here's how you sign your zone:
dnssec-keygen -3 -n ZONE nocko.se dnssec-keygen -3 -n ZONE -f KSK nocko.se dnssec-signzone -S -3 – nocko.se
That's it you're done. There are some new files in the directory with
your zonefile. One of them is nocko.se.signed
, just point bind or
nsd at this file instead of the unsigned one and reload the
config. That's it, You're hosting a DNSSEC signed zone!
Break it down
dnssec-keygen -3 -n ZONE nocko.se
Here you generated what's called the Zone Signing Key (ZSK). This is
the key pair used to sign each record in the zone. The -3
flag tells
the program to use an algorithm compatible with NSEC3 (see NSEC
vs. NSEC3). -n ZONE
alerts the program to generate a key
suitable to for use with a zone (the keygen can generate other types
of keys). Tack the zone name on the end so it knows what to call the
keys. You'll two new files in the directory with odd names:
- Knocko.se.+007+XXXXX.key
- Knocko.se.+007+XXXXX.private
What does it all mean? The filename with a K, because that's how
dnssec-keygen rolls. Then concatenate the zone name. This is followed
by a numeric code that specifies what type of key you created
(details). A
five serial number used to identify this key in the zone. Finally the
suffix .private
is used to identify if this is the private key and
.key
for the public key.
dnssec-keygen -3 -n ZONE -f KSK nocko.se
This generates a Key Signing Key (KSK). The KSK is a new keypair
similar in type, but independant of the ZSK. The KSK is only used to
sign the ZSK. We simply added -f KSK
to the previous command. You'll
see that two new key files show up with similar filenames but
different serial numbers. The KSK is also called the Secure Entry
Point and Trust Anchor in the literature (see Why two
keys? for details). It anchors the trust in the ZSK which
signs everything else.
dnssec-signzone -S -3 – nocko.se
This is the moneymaker, it does all this:
- Takes the public keys from the Knocko.se.+007*key) and appends
them as DNSKEY records to the zone. (This is what the
-S
flag does) - Signs the DNSKEY record of the ZSK with the KSK
- Puts all the records in the zone in canonical (alphabetical) order
- Generates a NSEC3 records for each record and interleaves them into the ordered zonefile
- Creates RRSIG records (signatures) for all the records in the zone by signing them with the ZSK.
Easy, peasy. What's the -3 -
about? The NSEC3
standard allows
for the use of a salt when hashing these records to make
pre-calculated dictionary attacks more difficult. The -3
flag is
required to generate the newer NSEC3 tags and if you don't care to
provide a salt, you can skip the salt by adding the hyphen.
Chain of Trust
So now you're signing your zone... you're still not doing a good job authenticating your zone! What if a rogue server serves up an evil copy of your zone with a set of valid signatures based on keys they generated? How can the client know your public key is the public key?
What you need to do is store your public key in the parent zone. Public keys are large, however, so a better idea is to hash the public key and store the hash in the parent zone... it's way smaller and still unique to the key.
Clients can verify the DNSKEY of a zone by checking for a DS key (containing a hash of the DNSKEY) at the parent that matches the DNSKEY in the zone. The parent zone completes a similar process, submitting it's public key hashs to it's parent and so forth all the way back to the DNS root. From your zone to the top of the chain, lots of crypto love.
Getting your DS record into your parent zone
If you are deep in a zone hierarchy you can start by emailing the
contact email address in the SOA record of your parent zone. For
example, if your zone is cs.engr.podunkstate.edu, try dig +short
engr.podunkstate.edu SOA
. The second field in the response is an
email address (switch the first .
to an @
). Email this person
and attach the dsset-nocko.se.
file (it was automatically generated
by dnssec-keygen when you made the KSK). It contains the exact records
the parent needs to put in their zonefile.
If you have a zone on a TLD registered with a large registrar, they will have a form to fill out in their web management interface. Look for the only thing that says DNSSEC.
My current registrar is gandi.net. Their automated system wants you provide three pieces of information:
The entire public key
The public key is in the files ending in
.key
You'll have two of those, but you are only interested in the KSK. If you open the files you'll see that one is identified as a KSK in the comment section. You should also note that the number 257 should appear directly followingDNSKEY
in the file. You will only want to paste the garbled looking part after the7
and including the final=
into the first text box.Select the algorithm from the drop down box. You'll want 7, it's in the filename and in the file
Specify the key type from the dropdown. The two options are ZSK (256) or KSK (257). The DS record is for your KSK so choose
- You could publish DS records for ZSKs.... it's not clear to me why this would be useful.
I've hosted domains with a GoDaddy reseller in the past. Their
automated web form wants you to submit the DS records in chunks. Take
a look at the dsset-nocko.se.
file. The body of the records (part
after DS) has four parts:
1. Key serial number
1. Algorithm type (7 if you've been following along)
1. Hash type (what type of hash, e.g. SHA-1, SHA-256, et. al)
1. The hash
GoDaddy's form has an input field for each of the above. The file has two hashes (two records) by default... they are both of the KSK, one is simply a SHA-1 hash and the other is SHA-256. Feel free to submit the form twice with both sets of info, but only one is required to authenticate your KSK.
Now you wait.
You can check to see if your DS records are live at your parent zone
by running dig nocko.se ds
. If you see a response that looks like
your dsset file you're done. Check out the tests at
DNSViz and DNS Check
if you want confirmation that your zone is full of valid DNSSEC
goodness.
You have to resign your zone
The signatures on your zonefile are good for 30days. Every (30 days - TTL of the zone) you need to sign the zone again. That's this command (from above):
dnssec-signzone -S -3 – nocko.se
Make a cron job to run this command periodically. Do it now... you won't remember later.
If you've come this far you have working DNSSEC on your zone.
FAQs
Why two keys (ZSK & KSK), wouldn't one be simpler?
Yes. One would be simpler and largely accomplish the same goals.
However, there are known problems with using a key to sign lots of messages that are much shorter than the key. DNS records are very short messages. The ZSK signs every record in the zone, plus every NSEC record. The formula for signature count is akin to: (2 * numrecords * numzoneupdates) where numzone_updates is at least one per month. So the ZSK has a (potentially) large footprint for cryptoanalysis.
The KSK only signs the ZSK and so only reveals a small fraction of the number signatures as the ZSK. That limits its exposure, in turn making the KSK viable for a longer period of time than the ZSK.
Wait... My keys expire?
Keys don't expire, but they do have a shelf life. It's in your best interest to generate new keys on a regular schedule, especially ZSKs.
Current best practices recommend replacing the ZSK every one to three months (depending on how many records are in the zone). The KSK should be replaced every one to two years. The reason for the two key system is that it's much easier to update records in your zone than those in the parent. Using two keys allows those upstream changes to be safely postponed for a more realistic 1-2 years. Could you imagine having to coordinate with your parent zone every month?
So I don't have to change my keys?
No, but you should. There are software packages to automate rotation of DNSSEC keys and a really nice NIST DNSSEC deployment guide to help you rotate keys (see section 11.2).
Whats with the NSEC / NSEC3 thing?
With NSEC, when a name in the zone doesn't exist a NSEC record is returned that contains the next secure record name in it. This NSEC record is signed (which is great), but leaks other DNS record names (which is not ideal). An attacker could systematically walk the zone and enumerate all the hosts.
With NSEC3 the names returned in the NSEC records are hashed in such a way that proves there is no matching record without revealing the name of the surrounding records. It's been around since 2008, it's best practice for new deployments. If you've followed along with the commands above, you've already implemented it.
NSEC3 does take longer to sign a zone (all that extra hashing). With extremely large zones there may be an advantage to using NSEC.