Download the most recent version of the PDF version here: http://www.nlnetlabs.nl/dnssec_howto/dnssec_howto.pdf
This document was developed as part of the RIPE NCC project on the deployment of DNSSEC. The document started as being an addendum to the RIPE NCC DNSSEC course. It was found to be more useful as a stand alone ”HOWTO” for setting up DNSSEC in ones own environment.
In the cause of time the document has been updated during workshops and based on feedback by folk using the document. It has grown beyond the size of your typical HOWTO.
In this HOWTO, which, because of its bulky nature is more of a tutorial in disguise, we touch upon the following topics:
The documentation is based on the so called DNSSEC-bis specifications that where finalised by the IETF DNSEXT working group in July 2004 and published in March 2005 as [3, 5, 4].
As of November 2006 the author is aware of the following open-source and or freeware implementations of the DNSSEC-bis specifications: BIND 9.3.2 and NSD 3.0.3. All our examples are based on BIND 9.4.1-P1.
This document is not intended as an introduction to DNS. Basic knowledge of DNS and acronyms used is assumed. We have tried not to use jargon but when unavoidable we have tried to explain the meaning. If you want to know more about the topic of DNS in general then Paul Albitz and Cricket Lui’s[2] or Ron Aitchinson’s [1] text books provide an excelent introduction.
This document will be subject to change. Please regularly check for new versions. <http://www.nlnetlabs.nl/dnssec_howto/>. Your corrections and additions are appreciated.
This part deals with securing data in zone files. We describe how to generate and manage keys, how to set up a recursive name server to validate signed zone data and how to sign and serve zones.
We plan to configure a recursive name server to validate the data it receives. Users that use this recursive name server as their resolver will, then, only receive data that is either secure and validated or not secured in any way. As a result, secured data that fails validation will not find its way to the users1. Having a validating recursive name server protects all those that use it as a forwarder against receiving spoofed DNS data.
Figure 1 illustrates how to configure the recursive DNS servers with a trusted key for ”example.com” so that all the data served by the authoritative servers for ”example.com” is validated before it is handed to the protected infrastructure that have the recursive servers configured as their forwarder (the name servers that usually are assigned through DHCP or configured in /etc/resolv.conf).
By configuring a public key for a specific zone, we tell the caching forwarder that all data coming from that zone should be signed with the corresponding private key. The zone acts as a secure entry point into the DNS tree and the key configured in the recursive name server acts as the start for a chain of trust. In an ideal situation you have only one key configured as a secure entry point: the key of the root zone.
We assume you have configured your name server to be recursive only.
We also assume that that name server in your organisation has been configured to run as an authoritative server for a secured zone called example.net. Notes on how to set up a secured zone can be found below in Chapter 2, “Securing a DNS zone”
Your recursive name server will treat the zones for which you configured trust anchors as being secured. If the zones for which you have configured trust anchors change their keys you will also have to reconfigure your trust anchors. Failure to do so will result in the data in these zones, or any child, being marked as bogus and therefore becoming invisible to users.
See AppendixA for information on compiling BIND with the correct switches to allow for DNSSEC. Do not forget enter the dnssec-enable yes; and dnssec-validation yes; statements in the options directive of your named.conf.2
A trust anchor is a public key that is configured as the entry point for a chain of authority. In the ideal case —where the root is signed and chains of trusts can be constructed through top-level domains to end-nodes — validating name servers would only need one of these trust anchors to be configured. During early deployment you will probably want to configure multiple trust anchors.
In Figure 2 we show a zone tree. In this tree, the domains ripe.net, 194.in-addr.arpa, 193.in-addr.arpa and 0.0.193.in-addr.arpa are assumed to be signed. It is also assumed that there is a secure delegation between 193.in-addr.arpa and 0.0.193.in-addr.arpa. In order to validate all these domains, the validating DNS client would have to configure trust anchors for ripe.net, 194.in-addr.arpa and 193.in-addr.arpa.3
To configure a trust-anchor you have to obtain the public key of the zone that you want to use as the start of the chain of authority that is to be followed when the data is validated. It is possible to get these straight from from the DNS, but there are two reasons why this may not be advisable.
Firstly, you have to establish the authenticity of the key you are about to configure as your trust anchor. How you do this depends on on what method the zone owner has made available for out of band validation of the key.
Secondly, you may have a choice of public keys, in which case you need to select the the proper ”Secure Entry Point” key.
In DNSSEC a difference is made between key- and zone-signing keys. Key-signing keys exclusively sign the DNSKEY RR set at the apex, while zone-signing keys sign all RR sets in a zone. 4. Key-signing keys are often used as Secure Entry Points (SEP) keys. These SEP keys are the keys intended to be first used when building a chain of authority from a trust anchor to signed data. We advise a one-to-one mapping between SEP keys and key-signing keys. In practise key-signing keys have a lower rollover frequency than zone-signing keys so you should configure the SEP i.e. key-signing keys.
In addition to having the proper public key you should either be aware of the rollover policy of the zone owner, or that you have a tool that takes care of automated rollover. Failure to modify the trust anchor before the corresponding SEP key is rolled will result in validation failures.
Assume you have obtained the key-signing keys of nlnetlabs.nl., 193.in-addr.arpa., and 195.in-addr.arpa.. To configure those key as a trust anchor you will have to include those keys using the trusted-keys directive in the named.conf of the recursive name server. See figure 3.
The format is similar to the DNSKEY RR except that the ”DNSKEY” label, the CLASS and the TTL, are omitted and quotes are placed around the name and the public key material.
As soon as a trusted-key has been configured, data from that zone or its sub zones will be validated by the caching forwarder. You can test this by querying your server5. If data is validated by the caching forwarder the ad-bit will be set by the name server (see the ’flags’ in the following example).
; <<>> DiG 9.4.1-P1 <<>> @192.168.2.204 example.net SOA +dnssec +multiline +retry=1
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 52761
;; flags: qr rd ra ad; QUERY: 1, ANSWER: 2, AUTHORITY: 2, ADDITIONAL: 3
; EDNS: version: 0, flags: do; udp: 4096
example.net. 100 IN SOA ns.example.net. olaf.nlnetlabs.nl. (
100 ; refresh (1 minute 40 seconds)
200 ; retry (3 minutes 20 seconds)
100 ; minimum (1 minute 40 seconds)
example.net. 100 IN RRSIG SOA 5 2 100 20070921083615 (
20070822083615 17000 example.net.
hF5zE2007NcvrGtvUQ0PIjBxVKS+fgsP5VQi3iRkbfny
Av0MiSIY7+Ectq8Zg9gxZCBfUErUXIPm+xfxOtguZTTN
/X3gAldOgG4Eo3FAu4pkOk95S3QM8AvCYXqigNIL6HlX
PHOCR490VJAhVv28dLmwIQDMOyJEPiIHaqmcTDY= )
example.net. 100 IN NS ns.example.net.
example.net. 100 IN RRSIG NS 5 2 100 20070921083615 (
20070822083615 17000 example.net.
jy/ARrpR/RwVhvCHNkNaEiXTKnw+zbWHK8zASnCrSHgd
4jt7Wdz4esrD5FivpE8xuSlGuu1RQOKCtFfAFwdhgrGb
Dzq+KbkgwE8yMWRrLqzp9WTeJNeVBZj2yijfxkgIyCKp
xHQJJ7aUMhbb+K3UmiVshXjRHqq/brGcHAKzya0= )
ns.example.net. 100 IN A 192.168.2.203
ns.example.net. 100 IN RRSIG A 5 3 100 20070921083615 (
20070822083615 17000 example.net.
VA7RgWoOCctvEJlo6e8yIw6t9ZvcZ+df4TU0oIUzmvzY
WpW/M1mxRaAhr9m0no+tLfx3rOCIl3ARTHNa/ayCEeae
NiShYUlMfMvjmrowuNlDmrbAsVkYZQTp+4cqVF7IsQ88
Fm846aPdTF7hPuLAMQBn/ptb8GyJ7mcxOVRq0J4= )
;; SERVER: 192.168.2.204#53(192.168.2.204)
It is important that you check that the validation is working correctly. This can be done by using the BIND log facilities on the machine that is configured as the validating recursive name server.
In BIND messages of a certain category can be logged to separate channels. The channels determine where the messages go and to what severity level they will need to be reported. The relevant category for DNSSEC validation is dnssec. In the example below the errors of the dnssec category are directed to the dnssec_log channel. In order to follow the validation process the channel has to log at least severity debug 3.
channel dnssec_log { // a DNSSEC log channel
print-time yes; // timestamp the entries
print-category yes; // add category name to entries
print-severity yes; // add severity level to entries
severity debug 3; // print debug message <= 3 t
The output in the log file will look similar to the output below. The attempt for positive response validation shows how the validator tries to prove that the RR set is trusted by following the chain of trust to the appropriate secure entry point, your trusted-key statement. Chains of trust (see figure 4) start by the validation of a signature over a DNSKEY RRset, then these keys are used to validate the DS RRset that point to DNSKEY RRs in a child zone – which validates the DNSKEY RRs in the child zone –, or the DNSKEYs can be used to validate the data you have queried for. The log reflects the activity of the validator following the chain of trust.
validating @0x186bc00: example.net SOA: starting
validating @0x186bc00: example.net SOA: attempting positive response validation
validating @0x186c400: example.net DNSKEY: starting
validating @0x186c400: example.net DNSKEY: attempting positive response validation
validating @0x186c400: example.net DNSKEY: verify rdataset (keyid=49656): success
validating @0x186c400: example.net DNSKEY: signed by trusted key; marking as secure
validator @0x186c400: dns_validator_destroy
validating @0x186bc00: example.net SOA: in fetch_callback_validator
validating @0x186bc00: example.net SOA: keyset with trust 7
validating @0x186bc00: example.net SOA: resuming validate
validating @0x186bc00: example.net SOA: verify rdataset (keyid=17000): success
It is not trivial to find and maintain trust anchors. If you want to get started with validation of DNSSEC here are a few places where you can find more information.
Since maintaining trust anchors is a pain you may also want to read the section 1.5 on lookaside validation.
Remember figure 2. If you would like to validate all these islands you will have to configure many trust-anchors, as in the example in figure 3.
In order to deal with this problem in absence of secure delegation from a small set of trust-anchors (ideally only 1, the root), BIND supports, as of version 9.3.2, a 6 mechanism called lookaside validation [14, 13].
In the lookaside validation a DLV registry will maintain all the trust-anchors you trust them to do the “Good Thing”. The maintainers of zones that are secure register their trust-anchors with the DLV registry and (non-standard extensions) in BIND (as of 9.3.2) will allow you, operator of a validating nameserver, to make use of all trust anchors that are present in the DLV tree.
In the DLV scheme the trust anchors are published in a dedicated domain (dlv.isc.org in the figure 5). Whenever a validating resolver recognises that a zone is signed it will first try to validate it by assessing if it is within the island of trust configured by its local trust anchors. When the validated domain is not in a trusted island the resolver will lookup perform a lookup in the DLV domain and use the trust anchor from that zone if and when available.
What follows is a generic description if you want to configure ISC’s DLV as your authoritative lookaside domain you may want to read http://www.isc.org/ops/dlv/.
In the example below we assume that dlv-registry.org is the registry of our choice.
You have to perform two (additional) steps in order to turn on lookaside validation.
Configure a trust anchor for the DLV registry. You do this by defining a trust anchor for the island of trust defined by dlv-registry.org in named.conf. Obviously, this trust-anchor is not exclusive, any trust-anchor configured in your trusted-keys statement will have preference over the data in the DLV registry.
// this trust-anchor defines dlv-registry.org as a trusted island.
"AQPXP7B3JTdPPhMl ... u82ggY2BKPQ==";
"AQPzzTWMz8qSWI ... zMG1UBYtEIQ==";
"AwEAAc2RnCT1gj ... pWaM8qXXPN8E=";
Configuring how the DNS name space anchors in the DLV name space. By using the dnssec-lookaside statement in the options section of named.conf. The statement takes two arguments the first one is the domain in the DNS for which lookaside validation is to be applied. Usually this will be the full name space so the "." (root) is configured. The second argument is the name of the trust-anchor where a lookup should be performed for a DLV record.
It is best to configure only one DLV trust-anchor.
// DNSSEC should be turned on, do not forget
// This sets the dlv registry "dlv-registry.org"
dnssec-lookaside "." trust-anchor "dlv-registry.org.";
testing When you have your logging configured as described in section 1.3.2 i.e. you log errors of the dnssec category are directed to a channel that logs at least at severity debug 3, then your log output when querying for example.net SOA will be similar to what is shown below.
First, the amount of log-ouput to validate one query covers more than one page of fine print. On a production server this data for several validation sequences will be print mixed. It will be very hard to debug from logfiles on production servers if you have not first looked at what happens for a single query.
Second, the structure is that the validator first finds DNSSEC RRs, notices that those records are not secure according ’plain DNSSEC’ and then moves to DLV validation.
Third, small chains of trust are build, from the DLV trust-anchor, via DNSKEY RRs to the signatures over the data. Trie to follow these trust anchors in the example output so it will be easier to identify them in production logs.
validating @0x186bc00: . NS: starting
validating @0x186bc00: . NS: looking for DLV
validating @0x186bc00: . NS: plain DNSSEC returns unsecure (.): looking for DLV
validating @0x186bc00: . NS: looking for DLV dlv-registry.org
validating @0x186bc00: . NS: DLV lookup: wait
validating @0x186c400: example.net SOA: starting
validating @0x186c400: example.net SOA: looking for DLV
validating @0x186c400: example.net SOA: plain DNSSEC returns unsecure (.): looking for DLV
validating @0x186c400: example.net SOA: looking for DLV example.net.dlv-registry.org
validating @0x186c400: example.net SOA: DNS_R_COVERINGNSEC
validating @0x186c400: example.net SOA: covering nsec: trust 1
validating @0x186c400: example.net SOA: DLV lookup: wait
validating @0x1876200: dlv-registry.org DLV: starting
validating @0x1876200: dlv-registry.org DLV: attempting negative response validation
validating @0x1876a00: dlv-registry.org SOA: starting
validating @0x1876a00: dlv-registry.org SOA: attempting positive response validation
validating @0x1877200: dlv-registry.org DNSKEY: starting
validating @0x1877200: dlv-registry.org DNSKEY: attempting positive response validation
validating @0x1877200: dlv-registry.org DNSKEY: verify rdataset (keyid=8916): success
validating @0x1877200: dlv-registry.org DNSKEY: signed by trusted key; marking as secure
validator @0x1877200: dns_validator_destroy
validating @0x1876a00: dlv-registry.org SOA: in fetch_callback_validator
validating @0x1876a00: dlv-registry.org SOA: keyset with trust 7
validating @0x1876a00: dlv-registry.org SOA: resuming validate
validating @0x1876a00: dlv-registry.org SOA: verify rdataset (keyid=27467): success
validating @0x1876a00: dlv-registry.org SOA: marking as secure
validating @0x1877200: example.net.dlv-registry.org DLV: starting
validating @0x1877200: example.net.dlv-registry.org DLV: attempting positive response validation
validating @0x1877200: example.net.dlv-registry.org DLV: keyset with trust 7
validating @0x1877200: example.net.dlv-registry.org DLV: verify rdataset (keyid=27467): success
validating @0x1877200: example.net.dlv-registry.org DLV: marking as secure
validator @0x1877200: dns_validator_destroy
validating @0x186c400: example.net SOA: in dlvfetched: success
validating @0x186c400: example.net SOA: DLV example.net found
validating @0x186c400: example.net SOA: dlv_validator_start
validating @0x186c400: example.net SOA: restarting using DLV
validating @0x186c400: example.net SOA: attempting positive response validation
validator @0x1876a00: dns_validator_destroy
validating @0x1876200: dlv-registry.org DLV: in authvalidated
validating @0x1876200: dlv-registry.org DLV: resuming nsecvalidate
validating @0x1876a00: dlv-registry.org NSEC: starting
validating @0x1876a00: dlv-registry.org NSEC: attempting positive response validation
validating @0x1876a00: dlv-registry.org NSEC: keyset with trust 7
validating @0x1876a00: dlv-registry.org NSEC: verify rdataset (keyid=27467): success
validating @0x1876a00: dlv-registry.org NSEC: marking as secure
validator @0x1876a00: dns_validator_destroy
validating @0x1876200: dlv-registry.org DLV: in authvalidated
validating @0x1876200: dlv-registry.org DLV: looking for relevant nsec
validating @0x1876200: dlv-registry.org DLV: nsec proves name exists (owner) data=0
validating @0x1876200: dlv-registry.org DLV: resuming nsecvalidate
validating @0x1876200: dlv-registry.org DLV: nonexistence proof(s) found
validator @0x1876200: dns_validator_destroy
validating @0x186bc00: . NS: in dlvfetched: ncache nxrrset
validating @0x186bc00: . NS: DLV not found
validating @0x186bc00: . NS: marking as answer
validator @0x186bc00: dns_validator_destroy
validating @0x186bc00: example.net DNSKEY: starting
validating @0x186bc00: example.net DNSKEY: looking for DLV
validating @0x186bc00: example.net DNSKEY: plain DNSSEC returns unsecure (.): looking for DLV
validating @0x186bc00: example.net DNSKEY: looking for DLV example.net.dlv-registry.org
validating @0x186bc00: example.net DNSKEY: DLV example.net found
validating @0x186bc00: example.net DNSKEY: dlv_validator_start
validating @0x186bc00: example.net DNSKEY: restarting using DLV
validating @0x186bc00: example.net DNSKEY: attempting positive response validation
validating @0x186bc00: example.net DNSKEY: dlv_validatezonekey
validating @0x186bc00: example.net DNSKEY: Found matching DLV record: checking for signature
validating @0x186bc00: example.net DNSKEY: verify rdataset (keyid=17000): RRSIG failed to verify
validating @0x186bc00: example.net DNSKEY: verify rdataset (keyid=49656): success
validating @0x186bc00: example.net DNSKEY: marking as secure
validator @0x186bc00: dns_validator_destroy
validating @0x186c400: example.net SOA: in fetch_callback_validator
validating @0x186c400: example.net SOA: keyset with trust 7
validating @0x186c400: example.net SOA: resuming validate
validating @0x186c400: example.net SOA: verify rdataset (keyid=17000): success
When using lookaside validation assessing the log output in case of corrupted zone data is a challenge. Below is the output of the validator when it tries to figure out if a query that returns a corrupted result is valid or not. The conclusion is reached in the last few lines.
validating @0x186bc00: . NS: starting
validating @0x186bc00: . NS: looking for DLV
validating @0x186bc00: . NS: plain DNSSEC returns unsecure (.): looking for DLV
validating @0x186bc00: . NS: looking for DLV dlv-registry.org
validating @0x186bc00: . NS: DLV lookup: wait
validating @0x1875200: corrupt.example.net A: starting
validating @0x1875200: corrupt.example.net A: looking for DLV
validating @0x1875200: corrupt.example.net A: plain DNSSEC returns unsecure (.): looking for DLV
validating @0x1875200: corrupt.example.net A: looking for DLV corrupt.example.net.dlv-registry.org
validating @0x1875200: corrupt.example.net A: DNS_R_COVERINGNSEC
validating @0x1875200: corrupt.example.net A: covering nsec: trust 1
validating @0x1875200: corrupt.example.net A: DLV lookup: wait
validating @0x186c400: dlv-registry.org DLV: starting
validating @0x186c400: dlv-registry.org DLV: attempting negative response validation
validating @0x1876a00: dlv-registry.org SOA: starting
validating @0x1876a00: dlv-registry.org SOA: attempting positive response validation
validating @0x1877200: corrupt.example.net.dlv-registry.org DLV: starting
validating @0x1877200: corrupt.example.net.dlv-registry.org DLV: attempting negative response validation
validating @0x1877a00: dlv-registry.org SOA: starting
validating @0x1877a00: dlv-registry.org SOA: attempting positive response validation
validating @0x1878200: dlv-registry.org DNSKEY: starting
validating @0x1878200: dlv-registry.org DNSKEY: attempting positive response validation
validating @0x1878200: dlv-registry.org DNSKEY: verify rdataset (keyid=8916): success
validating @0x1878200: dlv-registry.org DNSKEY: signed by trusted key; marking as secure
validator @0x1878200: dns_validator_destroy
validating @0x1876a00: dlv-registry.org SOA: in fetch_callback_validator
validating @0x1876a00: dlv-registry.org SOA: keyset with trust 7
validating @0x1876a00: dlv-registry.org SOA: resuming validate
validating @0x1876a00: dlv-registry.org SOA: verify rdataset (keyid=27467): success
validating @0x1876a00: dlv-registry.org SOA: marking as secure
validator @0x1876a00: dns_validator_destroy
validating @0x186c400: dlv-registry.org DLV: in authvalidated
validating @0x186c400: dlv-registry.org DLV: resuming nsecvalidate
validating @0x1877a00: dlv-registry.org SOA: in fetch_callback_validator
validating @0x1877a00: dlv-registry.org SOA: keyset with trust 7
validating @0x1877a00: dlv-registry.org SOA: resuming validate
validating @0x1877a00: dlv-registry.org SOA: verify rdataset (keyid=27467): success
validating @0x1877a00: dlv-registry.org SOA: marking as secure
validator @0x1877a00: dns_validator_destroy
validating @0x1877200: corrupt.example.net.dlv-registry.org DLV: in authvalidated
validating @0x1877200: corrupt.example.net.dlv-registry.org DLV: resuming nsecvalidate
validating @0x1877a00: example.net.dlv-registry.org NSEC: starting
validating @0x1877a00: example.net.dlv-registry.org NSEC: attempting positive response validation
validating @0x1877a00: example.net.dlv-registry.org NSEC: keyset with trust 7
validating @0x1877a00: example.net.dlv-registry.org NSEC: verify rdataset (keyid=27467): success
validating @0x1877a00: example.net.dlv-registry.org NSEC: marking as secure
validator @0x1877a00: dns_validator_destroy
validating @0x1877200: corrupt.example.net.dlv-registry.org DLV: in authvalidated
validating @0x1877200: corrupt.example.net.dlv-registry.org DLV: looking for relevant nsec
validating @0x1877200: corrupt.example.net.dlv-registry.org DLV: nsec range ok
validating @0x1877200: corrupt.example.net.dlv-registry.org DLV: resuming nsecvalidate
validating @0x1877200: corrupt.example.net.dlv-registry.org DLV: in checkwildcard: *.example.net.dlv-registry.org
validating @0x1877200: corrupt.example.net.dlv-registry.org DLV: looking for relevant nsec
validating @0x1877200: corrupt.example.net.dlv-registry.org DLV: nsec range ok
validating @0x1877200: corrupt.example.net.dlv-registry.org DLV: nonexistence proof(s) found
validator @0x1877200: dns_validator_destroy
validating @0x1875200: corrupt.example.net A: in dlvfetched: ncache nxdomain
validating @0x1875200: corrupt.example.net A: looking for DLV example.net.dlv-registry.org
validating @0x1875200: corrupt.example.net A: DLV lookup: wait
validating @0x1876a00: dlv-registry.org NSEC: starting
validating @0x1876a00: dlv-registry.org NSEC: attempting positive response validation
validating @0x1876a00: dlv-registry.org NSEC: keyset with trust 7
validating @0x1876a00: dlv-registry.org NSEC: verify rdataset (keyid=27467): success
validating @0x1876a00: dlv-registry.org NSEC: marking as secure
validator @0x1876a00: dns_validator_destroy
validating @0x186c400: dlv-registry.org DLV: in authvalidated
validating @0x186c400: dlv-registry.org DLV: looking for relevant nsec
validating @0x186c400: dlv-registry.org DLV: nsec proves name exists (owner) data=0
validating @0x186c400: dlv-registry.org DLV: resuming nsecvalidate
validating @0x186c400: dlv-registry.org DLV: nonexistence proof(s) found
validator @0x186c400: dns_validator_destroy
validating @0x186bc00: . NS: in dlvfetched: ncache nxrrset
validating @0x186bc00: . NS: DLV not found
validating @0x186bc00: . NS: marking as answer
validator @0x186bc00: dns_validator_destroy
validating @0x186bc00: example.net.dlv-registry.org DLV: starting
validating @0x186bc00: example.net.dlv-registry.org DLV: attempting positive response validation
validating @0x186bc00: example.net.dlv-registry.org DLV: keyset with trust 7
validating @0x186bc00: example.net.dlv-registry.org DLV: verify rdataset (keyid=27467): success
validating @0x186bc00: example.net.dlv-registry.org DLV: marking as secure
validator @0x186bc00: dns_validator_destroy
validating @0x1875200: corrupt.example.net A: in dlvfetched: success
validating @0x1875200: corrupt.example.net A: DLV example.net found
validating @0x1875200: corrupt.example.net A: dlv_validator_start
validating @0x1875200: corrupt.example.net A: restarting using DLV
validating @0x1875200: corrupt.example.net A: attempting positive response validation
validating @0x186bc00: example.net DNSKEY: starting
validating @0x186bc00: example.net DNSKEY: looking for DLV
validating @0x186bc00: example.net DNSKEY: plain DNSSEC returns unsecure (.): looking for DLV
validating @0x186bc00: example.net DNSKEY: looking for DLV example.net.dlv-registry.org
validating @0x186bc00: example.net DNSKEY: DLV example.net found
validating @0x186bc00: example.net DNSKEY: dlv_validator_start
validating @0x186bc00: example.net DNSKEY: restarting using DLV
validating @0x186bc00: example.net DNSKEY: attempting positive response validation
validating @0x186bc00: example.net DNSKEY: dlv_validatezonekey
validating @0x186bc00: example.net DNSKEY: Found matching DLV record: checking for signature
validating @0x186bc00: example.net DNSKEY: verify rdataset (keyid=17000): RRSIG failed to verify
validating @0x186bc00: example.net DNSKEY: verify rdataset (keyid=49656): success
validating @0x186bc00: example.net DNSKEY: marking as secure
validator @0x186bc00: dns_validator_destroy
validating @0x1875200: corrupt.example.net A: in fetch_callback_validator
validating @0x1875200: corrupt.example.net A: keyset with trust 7
validating @0x1875200: corrupt.example.net A: resuming validate
validating @0x1875200: corrupt.example.net A: verify rdataset (keyid=17000): RRSIG failed to verify
validating @0x1875200: corrupt.example.net A: failed to verify rdataset
validating @0x1875200: corrupt.example.net A: verify failure: RRSIG failed to verify
validating @0x1875200: corrupt.example.net A: no valid signature found
Suppose that you have configured a trust anchor and you are experiencing problems. For instance, your nameserver returns “SERVFAIL” for particular queries. Well, “SERVFAIL” is the default return code that a validating nameserver returns when it flags data as being bogus. Bogus data can be caused by two things. Either you are under attack or you experiencing a configuration error either by the operator of one of the zones in the chain of trust or by the operator of the validating recursive nameserver.
In addition to looking at the logs there are a number of tools at your disposal (see III). To assess if problems occur because of misconfiguration, or bugs, in you validating nameserver, or because of problems with the signed zones you will need a troubleshooting strategy.
One of the approaches you could take is to first use drill (see 6) or dig (see 7) to perform a ’sigchase’ or a ’trace’ with a key copied to your local file system, circumventing you validating recursive nameserver. In that way you will be able to check if the chain of trust can actually be built from the data. Make sure you use the correct trust-anchor when tracing data.
When you have verified that the chain of trust can be build from the data in the DNS it is time to troubleshoot the validating nameserver. This is easy when you have access to the log files but may be more troublesome if you don’t. You could use dig to query the validating nameservers with and without the +cd flag. That flag sets a bit in the query that instructs the nameserver not to perform validation. When the individual pieces in the chain of trust (drill returned those when using the trace option) you may be able to find inconsistencies that indicate that an expired trust anchor has been configured. You start by querying the DNSKEY RRset for which you assume there is a trust-anchor considered and work your way down. Or, alternatively, you query for the data you were looking for, use the data in the RRSIG RR to find for which DNSKEY RR to query, then query for a DS RR at the same name and work your way up (similar to the ’sigchase’ in drill).
While troubleshooting there are a number of failures that are easily introduced. Take the following example.
In his ISP column [8, 7, 6], Geoff Huston documented his experiences as an early deployer. He blindly configured a trust-anchor for the “nlnetlabs.nl” zone. While this zone was signed it was done in an experimental setup whereby not all servers for the zone were configured with the same version of the protocol. In this case one of the servers would not provide RRSIGs with the answer, something which may give rise to re-occurring but hard to predict failures.
There are two things to learn from this: Never blindly configure trust anchors in validating resolvers and make sure that when you serve zones all your servers conform to the DNSSEC protocol specification.
Another failure is that one of the RRsets in the chain of trust has expired signatures. Check this by looking at the date fields in the RRSIG RRs.
More problematic to find may be a rollover, where DNSKEY RRs or RRSIG RRs have been removed to early so that there is an inconsistency between data in cache and data that needs to be validated (also see section 4). Using the +cd to with dig and looking at the TTLs might help to distinguish if you are trying to validate RRSIGs for which there are no DNSKEYs available (or vice versa).
If a zone has been signed and its key has been configured in a validating recursive name server we usually refer to it as being an ”island of security”. It apparently does not have a secured parent and stands alone in the sea of other unsecured domains. Usually creating an ”island of security” is the first step to becoming part of the secure DNS. The ”island of security” will remain ”insecure” for resolvers that have no trust anchor configured for the domain.
If a zone owner decides to create ”an island of security” she will sign her zones and distribute the ”secure entry points” to the system administrators that want to validate her zone data. Once the island of security has been set up the island can become part of the secure tree by exchanging the ”secure entry point” with the parent.
After creation of the key-pairs used for signing and validation we want to sign the zone data for our own organisation (e.g. example.net.) and configure the caching forwarders on our organisations network to validate data against the public key of our organisation.
In the text below, we assume that your organisation’s domain names are maintained in one zone. If domain name administration is delegated to sub-zones, see section Chapter 3, “Delegating of signing authority; becoming globally secure”.
Signing the zone data is the task of the zone administrator, configuring the caching forwarder is a task of system administrators.
The examples are based on the example zone in section Figure 7.
All the authoritative servers will need to be configured to deal with the DNSSEC protocol. How this is done for BIND is explained in AppendixA. The essential steps are compiling bind with openssl and enabling dnssec through the use of the dnssec-enable yes; directive in the options section of named.conf.
That is all there is to it.
Before generating keys, you will need to think about your key maintenance policy. Such policy should address
Some of these issues may be easy to address. For example, your organisation may have established mechanisms to distribute the public keys, there may be obvious ways to publish an upcoming rollover such as the possibility of publishing the event in a corporate newspaper. Alternatively, it may be possible to notify all relevant parties by mail when a corporate X.509 hierarchy is available for e-mail validation.
Key- and zone-signing keys. The author thinks it is good practise to use zone-signing keys and key-signing keys (also see Chapter 4, “Rolling keys”). The key-signing keys are usually the first keys from your zone that are used to build a chain of authority to the data that needs to be validated. Therefore, these keys are often called a secure entry point key (or SEP key). These SEP keys are the ones that you should exchange with your parents or that validating resolvers configure as their trust anchors.
Throughout this document we assume that you use separate key- and zone-signing keys and that the key-signing keys are exclusively used as secure entry point keys and can be identified by the SEP[10] bit in the flag field; the flag field is odd.
|
dnssec-keygen -a alg -b bits -n type [options] name -a algorithm: RSA | RSAMD5 | DH | DSA | RSASHA1 | HMAC-MD5 | HMAC-SHA1 | HMAC-SHA224 | HMAC-SHA256 | HMAC-SHA384 | HMAC-SHA512 DSA: [512..1024] and divisible by 64 -n nametype: ZONE | HOST | ENTITY | USER | OTHER -d <digest bits> (0 => max, default) -e use large exponent (RSAMD5/RSASHA1 only) -g <generator> use specified generator (DH only) -t <type>: AUTHCONF | NOAUTHCONF | NOAUTH | NOCONF (default: AUTHCONF) -p <protocol>: default: 3 [dnssec] -s <strength> strength value this key signs DNS records with (default: 0)
|
dnssec-keygen is the tool that we use to generate key pairs. The arguments that we have to provide dnssec-keygen are shown in Figure 6.
The output can be found in two files. The name of the files contain relevant information:
Kdomain_name+algorithm_id+key_id.extension
The domain_name is the name specified on the command line. It is used by other BIND DNSSEC tools, if you use a different name from the domain name, you might confuse those tools. The algorithm_id identifies the algorithm used: 1 for RSAMD5, 3 for DSA, 5 for RSASHA1 and 54 for HMAC-MD5 (TSIG only). The key_id is an identifier for the key material. This key_id is used by the RRSIG Resource Record. The extension is either key or private, the first is the public key, the second is the private key.
We create an RSASHA1 zone-signing key pair for example.net:
Because of the considerations in Section 2.3.1 you will also need to create SEP keys. Create keys with the SEP bit set by specifying the -f KSK flag with dnssec-keygen.
Lets have a look at the content of these files7
cat Kexample.net.+005+17000.key
example.net. IN DNSKEY 256 3 5 (
AQPI4+0M1V055RS2Hqv+8w8V20Dh+SQmFzHQtZMuzLH3UxWE0GmG5Gfj
The public key (.key extension) is exactly as it appears in your zone file. Note, that the TTL value is not specified. This key has a ”flag” value of 256. Since this value is an even number, the key is not marked as a SEP key and should be used for zone-signing.
The private key (.private extension) contains all the parameters that make an RSASHA1 private key. The private key of a RSA key contains different parameters to DSA. Here is the private key (with base64 material truncated):
cat Kexample.net.+005+17000.private
Modulus: yOPtDNVdOeUUth6r/vMPFdtA4fkkJhcx0LWTLsyx91MVhNBphu...
PrivateExponent: he1Iszjo0UNjJBRyqfdfY+eAlqYYGWTL4HkMyd3L+j...
Prime1: +X0kNW1JrepBnVw5o9fDUyWAT5zqxKt0YR4vJZ19991tLZAmdO4...
Prime2: ziIX5qfpZGBuzfd847TqtDfYcwv5UfUrPAIa/11g3leUUNERmsB...
Exponent1: plNtePOGc/GBE5LRF+Us4hkANRNHLcei62l0w75T+pOeHmAZ...
Exponent2: iWwP7xqbmEBJ3qT97SNHIs/logf7i/jHfVa8qj5AlDpi4Ith...
Coefficient: rmmgD9P7/ywQJ4F0epdGqOUoQZmqrPQsraDTD8vkU1wLju...
This private key should be kept secure8 i.e. the file permissions should be set so that the zone administrator will be able to access them when a zone needs to be signed. The BIND tools will, by default,9 look for the keys in the directory where signing is performed (see Section 2.4), that might not be the most secure place on your OS.
When you create key pairs, you should include them in your zone file. Refer to the example in Figure7, where we use the $include directive to include the keys. We increase the serial number in the SOA record before signing.
In the example below we will use the RSASHA1 type keys for zone and key-signing keys.
|
@ 100 IN SOA ns.example.net. ( ns.example.net. A 192.168.2.203 ; These are the keys that need to be publised in the DNSKEY RRset
|
Once the key is included in the zone file we are ready to sign the zone using the dnssec-signzone tool (see Figure 8 for all the arguments). We use the -o flag to specify the origin of the zone; by default the origin is deduced from the zone file name.
With the ’-k key_name’ we specify which key is to be used as the key-signing key. That key will only sign the DNSKEY RR set in the apex of the zone. The keys that come as arguments at the end of the command are used to sign all the RR data for which the zone is authoritative. If you do not specify the keys, BIND will use the ones for which the public keys are included in the zone and use the SEP flag to distinguish between key- and zone-signing keys.
In practise you would not want to rely on the default, since in key rollover scenarios you will have a public key in your zone file but you would not want to use that for zone-signing (in order to avoid double signatures and therefore longer signature generation times and more resource consumption on your name server). Below is the command issued to sign a zone with the 49656 key as key-signing key and the 17000 key as zone-signing key.
The signed zone file is reproduced in figure 2.4 . Note that the apex DNSKEY RRset is the only RRset with two signatures, made with the zone- and key-signing keys. The other RRsets are only signed with the zone-signing keys.
The signing process completed the following:
The signatures were created with a default life time of 30 days from the moment of signing. Once signatures have expired data can not be validated and your zone will marked ’bogus’. Therefore you will have to re-sign your zone within 30 days. Zone re-signing is discussed below.
The signed zone is stored in db.example.net.signed, make sure you have configured named to use this file to serve the zones from.
|
dnssec-signzone [options] zonefile [keys] Options: (default value in parenthesis) directory to find keyset files (.) -g: generate DS records from keyset files RRSIG start time - absolute|offset (now - 1 hour) -e [YYYYMMDDHHMMSS|+offset|"now"+offset]: RRSIG end time - absolute|from start|from now (now + 30 days) cycle interval - resign if < interval from end ( (end-start)/4 ) randomize signature end time up to jitter seconds zone origin (name of zonefile) file the signed zone is written in (zonefile + .signed) file format of input zonefile (text) file format of signed zone file (text) soa serial format of signed zone file (keep) -a: verify generated signatures -p: use pseudorandom data (faster but less secure) -n ncpus (number of cpus present) -z: ignore KSK flag in DNSKEYs Signing Keys: (default: all zone keys that have private keys) keyfile (Kname+alg+tag)
|
|
; File written on Wed Aug 22 11:36:14 2007 ; dnssec\_signzone version 9.4.1-P1 example.net. 100 IN SOA ns.example.net. olaf.nlnetlabs.nl. ( 100 ; refresh (1 minute 40 seconds) 200 ; retry (3 minutes 20 seconds) 100 ; minimum (1 minute 40 seconds) 100 RRSIG SOA 5 2 100 20070921083614 ( 20070822083614 17000 example.net. U9hMfeJiAs6aNn7bj++g1FDVslHoTfvMCXMB y94EwaJMwKsukQ+pHUheStvxF4iksEOmcV0v ab2ZuwAazATZLzsWfjn4RbcM7U9EE3WQoaiT AWuADMM8OGPDX1lR5Ynk4c9bpL5MNKSd/u9G AOvceMDEjGFkebgBKWS9Z/PtAA0= ) 100 RRSIG NS 5 2 100 20070921083614 ( 20070822083614 17000 example.net. rOzRinjHQzWqNvLUhzk/oXlyx59kyZf0zV5U MF+HzWxIlGHZtYWOJGE09sibWPl8L9k6/JbX dsWdPKiyNn5MvCZ+y9BdmuFVUW305SXiwynG /vzZW6UdC/rmQPCY7MP8uyUaHX/POPVtSIkb K75G1a4jKMWWb1qcqb2IiHo/2VQ= ) 100 NSEC *.example.net. NS SOA RRSIG NSEC DNSKEY 100 RRSIG NSEC 5 2 100 20070921083614 ( 20070822083614 17000 example.net. LXBHKZzPLfN7UxmsUnbx1gtUXxgHuTF6mpio mfJpTA2+g4vXmL4T0PkLcgob1TlnwsMtrH4f h7+HnNmOFEe+kqbXDa+tcCm6PtVu7TqEBO2x IIew271xiqS+Ia4f9ksPWF+pD6c4Z3SnuEwL /0ta6G/AupVD2sX7urHD0As2auY= ) AQPI4+0M1V055RS2Hqv+8w8V20Dh+SQmFzHQ tZMuzLH3UxWE0GmG5GfjijandJeAZTKLpERX B6RfHTHGG8lD3IO1azWN6DiVFEVzgr0otAdD onfYF8gUT03ZnRcXlkJk41h12NOfq6rkODaF nfMHCppI3WZ/MJqe+9hLJtis+oEsRw== AQOzgs4qea+ImJ1OCworkabHqFnvPKybVT7b nDIkJ2HvXWslbwNWJ66Ox3N6ftpCTc9wWBMw 5+xOh7ilTwFPruMa2gURwEywZaMG9ipILOXm KO4a5I+8R2QTH4BM0WaIKnv5jCHose/l9LL3 Y8MApsjP6gOWNM8b9aVTjBFnf0xEF7sOSBBB
|
|
20070822083614 17000 example.net. LXLxA/ECoylvwW2yo8D9DNaMZ59PBS+lXDAF PJg19e935p7lr8tLtBmxhhMUctcfANobkBA9 IJZRXD/hCCxzq6yEtVeWPyCc2hX0ZlV5PtAM bmTOWYFebEta9oaFUrC5qop+S28Di62bfclD FgqnCPOPZkFD3ueCqlBdbtV3TVo= ) 100 RRSIG DNSKEY 5 2 100 20070921083614 ( 20070822083614 49656 example.net. SWlHzmbvNGNsBGlqdx/K7RF3FMMMRKzkFKok XeOH82lm/apBjBQ5J+IwModHCfDtWWEu/QLw areD3iDGNy3rk530CGtYeRomqiNb/Xrv6X0v n/8krbcV/6QxNwmlPs1cBC84dXmaOQ5jttOJ mBKj9o9I+sjdujp6nxb3emsnTVmNK+Siv78k mBdTJgnG6rNCxwfNJMOa1+3FBNx6HfuwKg== ) *.example.net. 100 IN A 192.168.2.10 100 RRSIG A 5 2 100 20070921083614 ( 20070822083614 17000 example.net. VVMxoTePJsLt/ZaTC9zpMySxWtNcz+R7RuIM zQSpEPSlm9wF1bApKNJC9xf1kUWFUmmN+cXj IsGrfMB4JW1/e+HVMRfIibzIcbQg3xmt42eo qudbBFgjgTUpjNj6HEYywPqUecFAD8TLLL9B vHx0HwlRFnxSGzO0f/1s4NQWmiY= ) 100 NSEC a.example.net. A RRSIG NSEC 100 RRSIG NSEC 5 2 100 20070921083614 ( 20070822083614 17000 example.net. lKGp1n+j6a65GPgvsgKPohZH8ITlEVcYtdKe SUfWsEWe+Fm0h6dfTvRQb2ylqIsPTMjzIJXS 088lKhUX5emSV7Pp9/elY8h0E6cXRdrzEJKk Jhh1fdDG4caGu6yHAaoAotI1Mo6yrL/Kr+wH mzGd+wSB3r3/GYTZsDqDPp1aah8= ) a.example.net. 100 IN A 192.168.2.1 100 RRSIG A 5 3 100 20070921083614 ( 20070822083614 17000 example.net. H81aKqnGh2+Q7R7vA+O1Eepwn/5AnjDJGHl+ yCU7uf+zgfI28d/bp23aJROzZABq04EBdc7v 48cqEf4jcpwgHykW4LRgy9o3c162RWaDoRrX oWHubYHJU6HEY69Pl7pbD4ryz3itmghYUlwz 15nJ5wVQjYSJgMOcZ8MpHO20HzU= ) 100 NSEC b.a.example.net. A RRSIG NSEC 100 RRSIG NSEC 5 3 100 20070921083614 ( 20070822083614 17000 example.net. iiYhMLbmgdunr/HrhcCRZ+0COsJsFe7/9BNN WWwjgyZfFvhAnxak5EFxsB31jbT52hsLUsn9 XQNoBcWaZgHjnkrEgw+2UyeNOOSG8nNPpDMw UF4FVBBS3PE2HCJ6EhtJzm21yWvAA2nkcxI4 8b+Vrv2C/HoZFXZ6iWjsXWDfiDI= ) b.a.example.net. 100 IN A 192.168.2.11 100 RRSIG A 5 4 100 20070921083614 (
|
|
pMxWIdaaCl8eOhooY7NVc38TqLSN2mTPdTU8 WRU0t9iXXfqMlbdzVbCKgW4HPpEilCjABo1M U3o0vpZagr8odp9Q6Oxlb1MntSA= ) 100 NSEC b.example.net. A RRSIG NSEC 100 RRSIG NSEC 5 4 100 20070921083614 ( 20070822083614 17000 example.net. eIeNU2T4VFcdZPEeWRlup2TRP51EQbVNkvnu /mexajPrqbnbfq1JV3EnIMszE+RSXOMwJ+OU kMUAhKyta5PhnnDfbwOrfTrD/z8DOcd13bQv 6NqRaPVUolObj7OrRBH+iZBedLBG8P3aPgsb 6RfRk9CKE1eigygUg7rspISmjc4= ) b.example.net. 100 IN A 192.168.2.2 100 RRSIG A 5 3 100 20070921083614 ( 20070822083614 17000 example.net. PePJMo5cgNumk1lGVCjl0iG/fxNxyry/Fzfz 0wiiWj5T0qHMDMCeBr99IisPo5NfqkXFxA6i uK46Hflaja0AvY151WN186bE/zZh/LoT6CZu jFI21bOpL9+AegQLovjW41MV4aXHWu6a2gzU cikVYyJ377g5yTndy/dIJFTkUZ4= ) 100 NSEC ns.example.net. A RRSIG NSEC 100 RRSIG NSEC 5 3 100 20070921083614 ( 20070822083614 17000 example.net. rK7hoZHGtTFuzep/yoh4QbQDSFxo20mC7F+U IEm6CEgfrli9q1yL58Ikuxgg9BcahKI/QGup ukfqo9kVRqspojtH7cUqRyYPr7m7WUDfNimn doYZ6/99tb4cXFa0WS3wAPwPCE3GCKslZNbH PMGP59PQIPseqsNIDc0toQxxdpI= ) ns.example.net. 100 IN A 192.168.2.203 100 RRSIG A 5 3 100 20070921083614 ( 20070822083614 17000 example.net. oQIH3uWW4J8DmgRZE+9Pp5yPzL0zTxXTVM0/ BKFoKHfrt4ujKhySWV0L2v7lwjFG3N7G9c4n |