Chapter 11. Security

“I hope you’ve got your hair well fastened on?” he continued, as they set off.

“Only in the usual way,” Alice said, smiling.

“That’s hardly enough,” he said, anxiously. “You see the wind is so very strong here. It’s as strong as soup.”

“Have you invented a plan for keeping the hair from being blown off?” Alice enquired.

“Not yet,” said the Knight. “But I’ve got a plan for keeping it from falling off.”

Why should you care about DNS security? Why go to the trouble of securing a service that mostly maps names to addresses? Let us tell you a story.

In July 1997, during two periods of several days, users around the Internet who typed www.internic.net into their web browsers thinking they were going to the InterNIC’s web site instead ended up at a web site belonging to the AlterNIC. (The AlterNIC runs an alternate set of root nameservers that delegate to additional top-level domains with names like med and porn.) How’d it happen? Eugene Kashpureff, then affiliated with the AlterNIC, had run a program to “poison” the caches of major nameservers around the world, making them believe that www.internic.net’s address was actually the address of the AlterNIC web server.

Kashpureff hadn’t made any attempt to disguise what he had done; the web site that users reached was plainly the AlterNIC’s, not the InterNIC’s. But imagine someone poisoning your nameserver’s cache to direct www.amazon.com or www.wellsfargo.com to his own web server, conveniently located well outside local law enforcement jurisdiction. Further, imagine your users typing in their credit card numbers and expiration dates. Now you get the idea.

Protecting your users against these kinds of attacks requires DNS security. DNS security comes in several flavors. You can secure transactions—the queries, responses, and other messages your nameserver sends and receives. You can secure your nameserver, refusing queries, zone transfer requests, and dynamic updates from unauthorized addresses, for example. You can even secure zone data by digitally signing it.

Since DNS security is one of the most complicated topics in DNS, we’ll start you off easy and build up to the hard stuff.

TSIG

BIND 8.2 introduced a new mechanism for securing DNS messages called transaction signatures, or TSIG for short. TSIG uses shared secrets and a one-way hash function to authenticate DNS messages, particularly responses and updates.

TSIG, now codified in RFC 2845, is relatively simple to configure, light-weight for resolvers and nameservers to use, and flexible enough to secure DNS messages (including zone transfers) and dynamic updates. (Contrast this with the DNS Security Extensions, which we’ll discuss at the end of this chapter.)

With TSIG configured, a nameserver or updater adds a TSIG record to the additional data section of a DNS message. The TSIG record “signs” the DNS message, proving that the message’s sender had a cryptographic key shared with the receiver and that the message wasn’t modified after it left the sender.[*]

One-Way Hash Functions

TSIG provides authentication and data integrity through the use of a special type of mathematical formula called a one-way hash function. A one-way hash function, also known as a cryptographic checksum or message digest, computes a fixed-size hash value based on arbitrarily large input. The magic of a one-way hash function is that each bit of the hash value depends on each and every bit of the input. Change a single bit of the input, and the hash value changes dramatically and unpredictably—so unpredictably that it’s “computationally infeasible” to reverse the function and find an input that produces a given hash value.

TSIG uses a one-way hash function called MD5. In particular, it uses a variant of MD5 called HMAC-MD5. HMAC-MD5 works in a keyed mode in which the 128-bit hash value depends not only on the input, but also on a key.

The TSIG Record

We won’t cover the TSIG record’s syntax in detail because you don’t need to know it: TSIG is a “meta-record” that never appears in zone data and is never cached by a resolver or nameserver. A signer adds the TSIG record to a DNS message, and the recipient removes and verifies the record before doing anything further, such as caching the data in the message.

You should know, however, that the TSIG record includes a hash value computed over the entire DNS message as well as some additional fields. (When we say “computed over,” we mean that the raw, binary DNS message and the additional fields are fed through the HMAC-MD5 algorithm to produce the hash value.) The hash value is keyed with a secret shared between the signer and the verifier. Verifying the hash value proves both that the DNS message was signed by a holder of the shared secret and that it wasn’t modified after it was signed.

The additional fields in the TSIG record include the time the DNS message was signed. This helps combat replay attacks, in which a hacker captures a signed, authorized transaction (say a dynamic update deleting an important resource record) and replays it later. The recipient of a signed DNS message checks the time signed to make sure it’s within the allowable “fudge” (another field in the TSIG record).

Configuring TSIG

Before using TSIG for authentication, we need to configure one or more TSIG keys on either end of the transaction. For example, if we want to use TSIG to secure zone transfers between the master and slave nameservers for movie.edu, we need to configure both nameservers with a common key:

key toystory-wormhole.movie.edu. {
    algorithm hmac-md5;
    secret "skrKc4Twy/cIgIykQu7JZA==";
};

The argument to the key statement in this example, toystory-wormhole.movie.edu , is actually the name of the key, though it looks like a domain name. (It’s encoded in the DNS message in the same format as a domain name.) The TSIG RFC suggests you name the key after the two hosts that use it. The RFC also suggests that you use different keys for each pair of hosts. This prevents the disclosure of one key from compromising all of your communications, and limits the use of each key.

It’s important that the name of the key—not just the binary data the key points to—be identical on both ends of the transaction. If it’s not, the recipient tries to verify the TSIG record and finds it doesn’t know the key that the TSIG record says was used to compute the hash value. That causes errors such as the following:

Jan  4 16:05:35 wormhole named[86705]: client 192.249.249.1#4666:
request has invalid signature: TSIG tsig-key.movie.edu: tsig verify failure (BADKEY)

The algorithm, for now, is always hmac-md5. The secret is the base 64 encoding of the binary key. You can create a base-64-encoded key using the dnssec-keygen program included in BIND 9 or the dnskeygen program included in BIND 8. Here’s how you’d create a key using dnssec-keygen, the easier of the two to use:

#dnssec-keygen -a HMAC-MD5 -b 128 -n HOST toystory-wormhole.movie.edu.
Ktoystory-wormhole.movie.edu.+157+28446

The -a option takes as an argument the name of the algorithm the key will be used with. (That’s necessary because dnssec-keygen can generate other kinds of keys, as you’ll see in the section "The DNS Security Extensions.”) The -b option takes the length of the key as its argument; the RFC recommends using keys 128 bits long. The -n option takes as an argument HOST, the type of key to generate. (DNSSEC uses ZONE keys.) The final argument is the name of the key.

dnssec-keygen and dnskeygen both create files in their working directories that contain the keys generated. dnssec-keygen prints the base name of the files to its standard output. In this case, dnssec-keygen created the files Ktoystory-wormhole.movie.edu.+157+28446.key and Ktoystory-wormhole.movie.edu.+157+28446.private. You can extract the key from either file. The funny numbers (157 and 28446), in case you’re wondering, are the key’s DNSSEC algorithm number (157 is HMAC-MD5) and the key’s fingerprint (28446), a hash value computed over the key to identify it. The fingerprint isn’t particularly useful in TSIG, but DNSSEC supports multiple keys per zone, so identifying which key you mean by its fingerprint is important.

Ktoystory-wormhole.movie.edu.+157+28446.key contains:

toystory-wormhole.movie.edu. IN KEY 512 3 157 skrKc4Twy/cIgIykQu7JZA==

and Ktoystory-wormhole.movie.edu.+157+28446.private contains:

Private-key-format: v1.2
Algorithm: 157 (HMAC_MD5)
Key: skrKc4Twy/cIgIykQu7JZA==

If you prefer, you can choose your own key and encode it in base 64 using mmencode:

%mmencode
foobarbaz
Zm9vYmFyYmF6

Since the actual binary key is, as the substatement implies, a secret, we should take care in transferring it to our nameservers (e.g., by using ssh) and make sure that not just anyone can read it. We can do that by making sure our named.conf file isn’t world-readable or by using the include statement to read the key statement from another file, which isn’t world-readable:

include "/etc/dns.keys.conf";

There’s one last problem that we see cropping up frequently with TSIG: time synchronization. The timestamp in the TSIG record is useful for preventing replay attacks, but it tripped us up initially because the clocks on our nameservers weren’t synchronized. (They need to be synchronized to within five minutes, the default value for “fudge.”) That produced error messages like the following:

wormhole named[86705]: client 192.249.249.1#54331: request has
invalid signature: TSIG toystory-wormhole.movie.edu.: tsig verify failure (BADTIME)

We quickly remedied the problem using NTP, the network time protocol.[*]

Using TSIG

Now that we’ve gone to the trouble of configuring our nameservers with TSIG keys, we should probably configure them to use those keys for something. In BIND 8.2 and later and all BIND 9 nameservers, we can secure queries, responses, zone transfers, and dynamic updates with TSIG.

The key to configuring this is the server statement’s keys substatement, which tells a nameserver to sign queries and zone transfer requests sent to a particular remote nameserver. This server substatement, for example, tells the local nameserver, wormhole.movie.edu , to sign all such requests sent to 192.249.249.1 (toystory.movie.edu ) with the key toystory-wormhole.movie.edu :

server 192.249.249.1 {
    keys { toystory-wormhole.movie.edu.; };
};

If you’re only concerned about zone transfers (and not about general query traffic, for example), you can specify the key in the masters substatement for any slave zones:

zone "movie.edu" {
    type slave;
    masters { 192.249.249.1 key toystory-wormhole.movie.edu.; };
    file "bak.movie.edu";
};

Now, on toystory.movie.edu , we can restrict zone transfers to those signed with the toystory-wormhole.movie.edu key:

zone "movie.edu" {
    type master;
    file "db.movie.edu";
    allow-transfer { key toystory-wormhole.movie.edu.; };
};

toystory.movie.edu also signs the zone transfer, which allows wormhole.movie.edu to verify it.

You can also restrict dynamic updates with TSIG using the allow-update and update-policy substatements, as we showed you in the last chapter.

The nsupdate programs shipped with BIND 8.2 and later and BIND 9 support, sending TSIG-signed dynamic updates. If you have the key files created by dnssec-keygen lying around, you can specify either of those as an argument to nsupdate’s -k option. Here’s how you’d do that with BIND 9’s version of nsupdate:

%nsupdate -k Ktoystory-wormhole.movie.edu.+157+28446.key

or:

%nsupdate -k Ktoystory-wormhole.movie.edu.+157+28446.private

With the BIND 8.2 or later nsupdate, the syntax is a little different: -k takes a directory and a key name as an argument, separated by a colon:

%nsupdate -k /var/named:toystory-wormhole.movie.edu.

If you don’t have the files around (maybe you’re running nsupdate from another host), you can still specify the key name and the secret on the command line with the BIND 9 nsupdate:

%nsupdate -y toystory-wormhole.movie.edu.:skrKc4Twy/cIgIykQu7JZA==

The name of the key is the first argument to the -y option, followed by a colon and the base-64-encoded secret. You don’t need to quote the secret because base-64 values can’t contain shell metacharacters, but you can if you like.

Michael Fuhr’s Net::DNS Perl module also lets you send TSIG-signed dynamic updates and zone transfer requests. For more information on Net::DNS, see Chapter 15.

Now that we have a handy mechanism for securing DNS transactions, let’s talk about securing our whole nameserver.

Securing Your Nameserver

BIND 8 and 9 support a wide variety of security mechanisms. These features are particularly important if your nameserver is running on the Internet, but they’re also useful on purely internal nameservers.

We’ll start by discussing measures you should take on all nameservers for which security is important. Then we’ll describe a model in which your nameservers are split into two communities, one for serving only resolvers and one for answering other nameservers’ queries.

BIND Version

One of the most important ways you can enhance the security of your nameserver is to run a recent version of BIND. All versions of BIND 8 before 8.4.7 and all versions of BIND 9 older than 9.3.2 are susceptible to at least a few known attacks. Check the ISC’s list of vulnerabilities in various BIND versions at http://www.isc.org/sw/bind/bind-security.php for updates.

But don’t stop there: new attacks are being thought up all the time, so you’ll have to do your best to keep abreast of BIND’s vulnerabilities and the latest “safe” version of BIND. One good way to do that is to read the comp.protocols.dns.bind newsgroup or its mailing list equivalent, bind-users, regularly. If you’d prefer less noise, there’s always the bind-announce mailing list, which carries only announcements of patches and new releases of BIND.[*]

There’s another aspect of BIND’s version relevant to security: if a hacker can easily find out which version of BIND you’re running, he may be able to tailor his attacks to that version of BIND. And, wouldn’t you know it, since about BIND 4.9, BIND nameservers have replied to a certain query with their version. If you look up TXT records in the CHAOSNET class attached to the domain name version.bind, BIND graciously returns something like this:

%dig txt chaos version.bind.

; <<>> DiG 9.3.2 <<>> txt chaos version.bind.
;; global options:  printcmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 14286
;; flags: qr aa rd; QUERY: 1, ANSWER: 1, AUTHORITY: 1, ADDITIONAL: 0

;; QUESTION SECTION:
;version.bind.                  CH      TXT

;; ANSWER SECTION:
version.bind.           0       CH      TXT     "9.3.2"

;; AUTHORITY SECTION:
version.bind.           0       CH      NS      version.bind.

;; Query time: 17 msec
;; SERVER: 192.168.0.1#53(192.168.0.1)
;; WHEN: Sat Jan  7 16:14:39 2006
;; MSG SIZE  rcvd: 62

To address this, BIND versions 8.2 and later let you tailor your nameserver’s response to the version.bind query:

options {
    version "None of your business";
};

Of course, receiving a response like “None of your business” will tip off the alert hacker to the fact that you’re likely running BIND 8.2 or better, but that still leaves a number of possibilities. If you’d rather the reply was less obvious, you can use “version none” with BIND 9.3.0 and later:

options {
    directory "/var/named";
    version none;
};

Now your nameserver will respond to version queries like this:

; <<>> DiG 9.3.2 <<>> txt chaos version.bind.
;; global options:  printcmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 21957
;; flags: qr aa rd; QUERY: 1, ANSWER: 0, AUTHORITY: 1, ADDITIONAL: 0

;; QUESTION SECTION:
;version.bind.                  CH      TXT

;; AUTHORITY SECTION:
version.bind.           86400   CH      SOA     version.bind.
hostmaster.version.bind. 0 28800 7200 604800 86400

;; Query time: 2 msec
;; SERVER: 192.168.0.1#53(192.168.0.1)
;; WHEN: Sat Jan  7 16:16:43 2006
;; MSG SIZE  rcvd: 77

Restricting Queries

Back in the old days of BIND 4, administrators had no way to control who could look up names on their nameservers. That makes a certain amount of sense; the original idea behind DNS was to make information easily available all over the Internet.

The neighborhood is not such a friendly place anymore, though. In particular, people who run Internet firewalls may have a legitimate need to hide certain parts of their namespace from most of the world while making it available to a limited audience.

The BIND 8 and 9 allow-query substatement lets you apply an IP address-based access control list to queries. The ACL can apply to queries for data in a particular zone or to any queries received by the nameserver. In particular, the ACL specifies which IP addresses are allowed to send queries to the server.

Restricting all queries

The global form of the allow-query substatement looks like this:

options {
      allow-query { address_match_list; };
};

So to restrict our nameserver to answering queries from the three main Movie U. networks, we’d use:

options {
      allow-query { 192.249.249/24; 192.253.253/24; 192.253.254/24; };
};

Restricting queries in a particular zone

BIND 8 and 9 also allow you to apply an ACL to a particular zone. In this case, just use allow-query as a substatement to the zone statement for the zone you want to protect:

acl "HP-NET" { 15/8; };

zone "hp.com" {
      type slave;
      file "bak.hp.com";
      masters { 15.255.152.2; };
      allow-query { "HP-NET"; };
};

Any kind of authoritative nameserver, master or slave, can apply an ACL to the zone.[*] Zone-specific ACLs take precedence over a global ACL for queries in that zone. The zone-specific ACL may even be more permissive than the global ACL. If there’s no zone-specific ACL defined, any global ACL will apply.

Preventing Unauthorized Zone Transfers

Arguably even more important than controlling who can query your nameserver is ensuring that only your real slave nameservers can transfer zones from your nameserver. Users on remote hosts that can query your nameserver’s zone data can only look up records (e.g., addresses) for domain names they already know, one at a time. Users who can start zone transfers from your server can list all the records in your zones. It’s the difference between letting random folks call your company’s switchboard and ask for John Q. Cubicle’s phone number and sending them a copy of your corporate phone directory.

BIND 8 and 9’s allow-transfer substatement lets administrators apply an ACL to zone transfers. allow-transfer restricts transfers of a particular zone when used as a zone substatement and restricts all zone transfers when used as an options substatement. It takes an address match list as an argument.

The slave servers for our movie.edu zone have the IP addresses 192.249.249.1 and 192.253.253.1 (wormhole.movie.edu ) and 192.249.249.9 and 192.253.253.9 (zardoz.movie.edu ). The following zone statement:

zone "movie.edu" {
      type master;
      file "db.movie.edu";
      allow-transfer { 192.249.249.1; 192.253.253.1; 192.249.249.9; 192.253.253.9; };
};

allows only those slaves to transfer movie.edu from the primary master nameserver. Note that because the default for BIND 8 or 9 is to allow zone transfer requests from any IP address, and because hackers can just as easily transfer the zone from your slaves, you should probably also have a zone statement like this on your slaves:

zone "movie.edu" {
      type slave;
      masters { 192.249.249.3; };
      file "bak.movie.edu";
      allow-transfer { none; };
};

BIND 8 and 9 also let you apply a global ACL to zone transfers. This applies to any zones that don’t have their own explicit ACLs defined as zone substatements. For example, we might want to limit all zone transfers to our internal IP addresses:

options {
      allow-transfer { 192.249.249/24; 192.253.253/24; 192.253.254/24; };
};

Finally, as we mentioned earlier in the chapter, those newfangled BIND 8.2 and later and BIND 9 nameservers let you restrict zone transfers to slave nameservers that include a correct transaction signature with their request. On the master nameserver, you need to define the key in a key statement and then specify the key in the address match list:

key toystory-wormhole. {
    algorithm hmac-md5;
    secret "UNd5xYLjz0FPkoqWRymtgI+paxW927LU/gTrDyulJRI=";
};

zone "movie.edu" {
    type master;
    file "db.movie.edu";
    allow-transfer { key toystory-wormhole.; };
};

On the slave’s end, you need to configure the slave to sign zone transfer requests with the same key:

key toystory-wormhole. {
    algorithm hmac-md5;
    secret "UNd5xYLjz0FPkoqWRymtgI+paxW927LU/gTrDyulJRI=";
};

server 192.249.249.3 {
    keys { toystory-wormhole.; };  // sign all requests to 192.249.249.3
                                   // with this key
};

zone "movie.edu" {
    type slave;
    masters { 192.249.249.3; };
    file "bak.movie.edu";
};

For a primary nameserver accessible from the Internet, you probably want to limit zone transfers to just your slave nameservers. You probably don’t need to worry about securing zone transfers from nameservers inside your firewall, unless you’re worried about your own employees listing your zone data.

Running BIND with Least Privilege

Running a network server like BIND as the root user can be dangerous, and BIND normally runs as root. If a hacker finds a vulnerability in the nameserver through which he can read or write files, he’ll have unfettered access to the filesystem. If he can exploit a flaw that allows him to execute commands, he’ll execute them as root.

BIND 8.1.2 and later and all BIND 9 nameservers include code that allows you to change the user and group the nameserver runs as. This allows you to run the nameserver with what’s known as least privilege: the minimal set of rights it needs to do its job. That way, if someone breaks into your host through the nameserver, at least that person won’t have root privileges.

These nameservers also include an option that allows you to chroot() the nameserver: to change its view of the filesystem so that its root directory is actually a particular directory on your host’s filesystem. This effectively traps your nameserver in this directory, along with any attackers who successfully compromise your nameserver’s security.

Here are the command-line options that implement these features:

-u

Specifies the username or user ID the nameserver changes to after starting, e.g., named -u bind.

-g

Specifies the group or group ID the nameserver changes to after starting, e.g., named -g other. If you specify -u without -g, the nameserver uses the user’s primary group. BIND 9 nameservers always change to the user’s primary group, so they don’t support -g.

-t

Specifies the directory for the nameserver to chroot() to.

If you opt to use the -u and -g options, you’ll have to decide what user and group to use. Your best bet is to create a new user and group for the nameserver to run as, such as bind or named. Since the nameserver reads named.conf before giving up root privileges, you don’t have to change that file’s permissions. However, you may have to change the permissions and ownership of your zone datafiles so that the user the nameserver runs as can read them. If you use dynamic update, you’ll have to make the zone datafiles for dynamically updated zones writable by the nameserver.

If your nameserver is configured to log to files (instead of to syslog), make sure that those files exist and are writable by the nameserver before starting the server.

The -t option takes a little more specialized configuration. In particular, you need to make sure that all the files named uses are present in the directory you’re restricting the server to. Here’s a procedure to set up your chrooted environment, which we’ll assume lives under /var/named:[*]

  1. Create the /var/named directory, if it doesn’t exist. Create dev, etc, lib, usr, and var subdirectories. Within usr, create an sbin subdirectory. Within var, create subdirectories named named and run:

    #mkdir /var/named
    # cd /var/named
    # mkdir -p dev etc lib usr/sbin var/named var/run
  2. Copy named.conf to /var/named/etc/named.conf:

    #cp /etc/named.conf etc
  3. If you’re running BIND 8, copy the named-xfer binary to the usr/sbin/ or etc subdirectory (depending on whether you found it in /usr/sbin or /etc):

    #cp /usr/sbin/named-xfer usr/sbin

    Alternatively, you can put it wherever you like under /var/named and use the named-xfer substatement to tell named where to find it. Just remember to strip /var/named off of the pathname because when named reads named.conf, /var/named will look like the root of the filesystem. (If you’re running BIND 9, skip this step because BIND 9 doesn’t use named-xfer.)

  4. Create dev/null in the chrooted environment:[]

    #mknod dev/null c 2 2
  5. If you’re running BIND 8, copy the standard shared C library and the loader to the lib subdirectory:

    #cp /lib/libc.so.6 /lib/ld-2.1.3.so lib

    The pathnames may vary on your operating system. BIND 9 nameservers are self-contained, so you don’t need to copy libraries.

  6. Edit your startup files to start syslogd with an additional option and option argument: -a /var/named/dev/log. On many modern versions of Unix, syslogd is started from /etc/rc or /etc/rc.d/init.d/syslog. When syslogd restarts next, it creates /var/named/dev/log, and named logs to it.

    If your syslogd doesn’t support the -a option, use the logging statement described in Chapter 7 to log to files in the chrooted directory.

  7. If you’re running BIND 8 and use the -u or -g options, create passwd and group files in the etc subdirectory to map the arguments of -u and -g to their numeric values (or just use numeric values as arguments):

    # echo "named:x:42:42:named:/:" > etc/passwd
    # echo "named::42" > etc/group

    Then add the entries to the system’s /etc/passwd and /etc/group files. If you’re running BIND 9, you can just add the entries to the system’s /etc/passwd and /etc/group files because BIND 9 nameservers read the information they need before calling chroot().

  8. Finally, edit your startup files to start named with the -t option and option argument: -t /var/named. Similar to syslogd, many modern versions of Unix start named from /etc/rc or /etc/rc.d/init.d/named.

If you’re hooked on using ndc to control your BIND 8 nameserver, you can continue to do so as long as you specify the pathname to the Unix domain socket as the argument to ndc’s -c option:

#ndc -c /var/named/var/run/ndc reload

rndc will continue to work as before with your BIND 9 nameserver because it just talks to the server via port 953.

Split-Function Nameservers

Nameservers really have two major roles: answering iterative queries from remote nameservers and answering recursive queries from local resolvers. If we separate these roles, dedicating one set of nameservers to answering iterative queries and another to answering recursive queries, we can more effectively secure those nameservers.

“Advertising” nameserver configuration

Some of your nameservers answer nonrecursive queries from other nameservers on the Internet because these nameservers appear in NS records delegating your zones to them. We’ll call these nameservers advertising nameservers, because their role is to advertise your zones to the Internet.

There are special measures you can take to secure your advertising nameservers. But first, you should make sure that these nameservers don’t receive any recursive queries (that is, you don’t have any resolvers configured to use these servers and no nameservers use them as forwarders). Some of the precautions we’ll take—like making the server respond nonrecursively even to recursive queries—preclude your resolvers from using these servers. If you do have resolvers using your advertising nameservers, consider establishing another class of nameservers to serve just your resolvers or using the two nameservers in one configuration, both described later in this chapter.

Once you know your nameserver answers queries only from other nameservers, you can turn off recursion. This eliminates a major vector of attack: the most common spoofing attacks involve inducing the target nameserver to query nameservers under the hacker’s control by sending the target a recursive query for a domain name in a zone served by the hacker’s servers. To turn off recursion, use the following statement on a BIND 8 or 9 nameserver:

options {
     recursion no;
};

You should also restrict zone transfers of your zones to known slave servers, as described in the earlier section "Preventing Unauthorized Zone Transfers.” Finally, you might also want to turn off glue fetching. Some nameservers will automatically try to resolve the domain names of any nameservers in NS records; to prevent this from happening and keep your nameserver from sending any queries of its own, use this on a BIND 8 nameserver (BIND 9 nameservers don’t support glue fetching):

options {
      fetch-glue no;
};

“Resolving” nameserver configuration

We’ll call a nameserver that serves one or more resolvers or that is configured as another nameserver’s forwarder a resolving nameserver. Unlike an advertising nameserver, a resolving nameserver can’t refuse recursive queries. Consequently, we have to configure it a little differently to secure it. Since we know our nameserver should receive queries only from our own resolvers, we can configure it to deny queries from any but our resolvers’ IP addresses.

This allow-query substatement restricts queries to just our internal network:

options {
    allow-query { 192.249.249/24; 192.253.253/24; 192.253.254/24; };
};

With this configuration, the only resolvers that can send our nameserver recursive queries and induce them to query other nameservers are our own internal resolvers, which are presumably relatively benign.

There’s one other option we can use to make our resolving nameserver a little more secure: use-id-pool:

options {
    use-id-pool yes;
};

use-id-pool was introduced in BIND 8.2. It tells our nameserver to take special care to use random message IDs in queries. Normally, the message IDs aren’t random enough to prevent brute-force attacks that try to guess the IDs our nameserver has outstanding in order to spoof a response.

The ID pool code became a standard part of BIND 9, so you don’t need to specify it on a BIND 9 nameserver.

Two Nameservers in One

What if you have only one nameserver to advertise your zones and serve your resolvers, and you can’t afford the additional expense of buying another computer to run a second nameserver on? There are still a few options open to you. Two are single-server solutions that take advantage of the flexibility of BIND 8 and 9. One of these configurations allows anyone to query the nameserver for information in zones it’s authoritative for, but only our internal resolvers can query the nameserver for other information. While this doesn’t prevent remote resolvers from sending our nameserver recursive queries, those queries have to be in its authoritative zones so they won’t induce our nameserver to send additional queries.

Here’s a named.conf file to do that:

acl "internal" {
    192.249.249/24; 192.253.253/24; 192.253.254/24; localhost;
};

acl "slaves" {
    192.249.249.1; 192.253.253.1; 192.249.249.9; 192.253.253.9;
};

options {
    directory "/var/named";
    allow-query { "internal"; };
    use-id-pool yes;
};

zone "movie.edu" {
    type master;
    file "db.movie.edu";
    allow-query { any; };
    allow-transfer { "slaves"; };
};

zone "249.249.192.in-addr.arpa" {
    type master;
    file "db.192.249.249";
    allow-query { any; };
    allow-transfer { "slaves"; };
};

zone "." {
    type hint;
    file "db.cache";
};

Here, the more permissive zone-specific ACLs apply to queries in the nameserver’s authoritative zones, but the more restrictive global ACL applies to all other queries.

If we were running BIND 8.2.1 or newer, or any version of BIND 9, we could simplify this configuration somewhat using the allow-recursion substatement:

acl "internal" {
    192.249.249/24; 192.253.253/24; 192.253.254/24; localhost;
};

acl "slaves" {
    192.249.249.1; 192.253.253.1; 192.249.249.9; 192.253.253.9;
};

options {
    directory "/var/named";
    allow-recursion { "internal"; };
    use-id-pool yes;
};

zone "movie.edu" {
    type master;
    file "db.movie.edu";
    allow-transfer { "slaves"; };
};

zone "249.249.192.in-addr.arpa" {
    type master;
    file "db.192.249.249";
    allow-transfer { "slaves"; };
};

zone "." {
    type hint;
    file "db.cache";
};

We don’t need the allow-query substatements anymore: although the nameserver may receive queries from outside our internal network, it’ll treat those queries as nonrecursive, regardless of whether they are or not. Consequently, external queries won’t induce our nameserver to send any queries. This configuration also doesn’t suffer from a gotcha the previous setup is susceptible to: if your nameserver is authoritative for a parent zone, it may receive queries from remote nameservers resolving domain names in a delegated subdomain of the zone. The allow-query solution will refuse those legitimate queries, but the allow-recursion solution won’t.

Another option is to run two named processes on a single host. One is configured as an advertising nameserver, another as a resolving nameserver. Since we have no way of telling remote servers or configuring resolvers to query one of our nameservers on a port other than 53, the default DNS port, we have to run these servers on different IP addresses.

Of course, if your host already has more than one network interface, that’s no problem. Even if it has only one, the operating system may support IP address aliases. These allow you to attach more than one IP address to a single network interface. One named process can listen on each. Finally, if the operating system doesn’t support IP aliases, you can still bind one named against the network interface’s IP address and one against the loopback address. Only the local host will be able to send queries to the instance of named listening on the loopback address, but that’s fine if the local host’s resolver is the only one you need to serve.

First, here’s the named.conf file for the advertising nameserver, listening on the network interface’s IP address:

acl "slaves" {
    192.249.249.1; 192.253.253.1; 192.249.249.9; 192;253.253.9;
};

options {
    directory "/var/named-advertising";
    recursion no;
    fetch-glue no;
    listen-on { 192.249.249.3; };
    pid-file "/var/run/named.advertising.pid";
};

zone "movie.edu" {
    type master;
    file "db.movie.edu";
    allow-transfer { "slaves"; };
};

zone "249.249.192.in-addr.arpa" {
    type master;
    file "db.192.249.249";
    allow-transfer { "slaves"; };
};

Next, here’s the named.conf file for the resolving nameserver, listening on the loopback address:

options {
    directory "/var/named-resolving";
    listen-on { 127.0.0.1; };
    pid-file "/var/run/named.resolving.pid";
    use-id-pool yes;
};

zone "." {
    type hint;
    file "db.cache";
};

Note that we didn’t need an ACL for the resolving nameserver because it’s only listening on the loopback address and can’t receive queries from other hosts. (If our resolving nameserver were listening on an IP alias or a second network interface, we could use allow-query to prevent others from using our nameserver.) We turn off recursion on the advertising nameserver, but we must leave it on on the resolving nameserver. We also give each nameserver its own PID file so that the servers don’t try to use the same default filename for their PID files, and we give each nameserver its own directory so debug files and statistics files are saved in separate locations.

To use the resolving nameserver listening on the loopback address, the local host’s resolv.conf file must include the following:

nameserver 127.0.0.1

as the first nameserver directive.

If you’re running BIND 9, you can even consolidate the two nameserver configurations into one using views:

options {
    directory "/var/named";
};

acl "internal" {
    192.249.249/24; 192.253.253/24; 192.253.254/24; localhost;
};

view "internal" {
    match-clients { "internal"; };
    recursion yes;

    zone "movie.edu" {
        type master;
        file "db.movie.edu";
    };

    zone "249.249.192.in-addr.arpa" {
        type master;
        file "db.192.249.249";
    };

    zone "." {
        type hint;
        file "db.cache";
    };
};

view "external" {
    match-clients { any; };
    recursion no;

    zone "movie.edu" {
        type master;
        file "db.movie.edu";
    };

    zone "249.249.192.in-addr.arpa" {
        type master;
        file "db.192.249.249";
    };

    zone "." {
        type hint;
        file "db.cache";
    };
};

It’s a fairly simple configuration: two views, internal and external. The internal view, which applies only to our internal network, has recursion on. The external view, which applies to everyone else, has recursion off. The zones movie.edu and 249.249.192.in-addr.arpa are defined identically in both views. You could do a lot more with it—define different versions of the zones internally and externally, for example—but we’ll hold off on that until the next section.

DNS and Internet Firewalls

The Domain Name System wasn’t designed to work with Internet firewalls. It’s a testimony to the flexibility of DNS and of its BIND implementation that you can configure DNS to work with, or even through, an Internet firewall.

That said, configuring BIND to work in a firewalled environment, although not difficult, takes a good, complete understanding of DNS and a few of BIND’s more obscure features. Describing it also requires a large portion of this chapter, so here’s a roadmap.

We’ll start by describing the two major families of Internet firewall software: packet filters and proxies. The capabilities of each family have a bearing on how you’ll need to configure BIND to work through the firewall. Next, we’ll detail the two most common DNS architectures used with firewalls, forwarders and internal roots, and describe the advantages and disadvantages of each. We’ll then introduce a solution using a new feature, forward zones, which combines the best of internal roots and forwarders. Finally, we’ll discuss split namespaces and the configuration of the bastion host, the host at the core of your firewall system.

Types of Firewall Software

Before you start configuring BIND to work with your firewall, it’s important to understand what your firewall is capable of. Your firewall’s capabilities will influence your choice of DNS architecture and determine how you implement it. If you don’t know the answers to the questions in this section, track down someone in your organization who does know and ask. Better yet, work with your firewall’s administrator when designing your DNS architecture to ensure it will coexist with the firewall.

Note that this is far from a complete explanation of Internet firewalls. These few paragraphs describe only the two most common types of Internet firewalls and only in enough detail to show how the differences in their capabilities affect nameservers. For a comprehensive treatment of Internet firewalls, see Building Internet Firewalls by Elizabeth D. Zwicky, Simon Cooper, and D. Brent Chapman (O’Reilly).

Packet filters

The first type of firewall we’ll cover is the packet-filtering firewall. Packet-filtering firewalls operate largely at the transport and network levels of the TCP/IP stack (layers three and four of the OSI reference model, if you dig that). They decide whether to route a packet based on packet-level criteria such as the transport protocol (e.g., whether it’s TCP or UDP), the source and destination IP address, and the source and destination port (see Figure 11-1).

Packet filters operate at the network and transport layers of the stack
Figure 11-1. Packet filters operate at the network and transport layers of the stack

What’s most important to us about packet-filtering firewalls is that you can typically configure them to allow DNS traffic selectively between hosts on the Internet and your internal hosts. That is, you can let an arbitrary set of internal hosts communicate with Internet nameservers. Some packet-filtering firewalls can even permit your nameservers to query nameservers on the Internet, but not vice versa. All router-based Internet firewalls are packet-filtering firewalls. Checkpoint’s FireWall-1, Cisco’s PIX, and Juniper’s NetScreen are popular commercial packet-filtering firewalls.

Proxies

Proxies operate at the application protocol level, several layers higher in the OSI reference model than most packet filters (see Figure 11-2). In a sense, they “understand” the application protocol in the same way that a server for that particular application does. An FTP proxy, for example, can make the decision to allow or deny a particular FTP operation, such as a RETR (a get) or a STOR (a put).

Proxies operate at the application layer of the stack
Figure 11-2. Proxies operate at the application layer of the stack

The bad news, and what’s important for our purposes, is that most proxy-based firewalls handle only TCP-based application protocols. DNS, of course, is largely UDP-based. This implies that if you run a proxy-based firewall, your internal hosts will likely not be able to communicate directly with nameservers on the Internet.

The original Firewall Toolkit from Trusted Information Systems (now part of McAfee) was a suite of proxies for common Internet protocols such as Telnet, FTP, and HTTP. Secure Computing’s Sidewinder firewall products are also based on proxies, as are Symantec’s firewalls.

Note that these two categories of firewall are really just generalizations. The state of the art in firewalls changes very quickly. New packet filter-based firewalls can inspect application protocol-layer data, while some proxy-based firewalls include DNS proxies. Which family your firewall falls into is important only because it suggests what that firewall is capable of; what’s more important is whether your particular firewall will let you permit DNS traffic between arbitrary internal hosts and the Internet.

A Bad Example

The simplest configuration is to allow DNS traffic to pass freely through your firewall (assuming you can configure your firewall to do that). That way, any internal nameserver can query any nameserver on the Internet, and any Internet nameserver can query any of your internal nameservers. You don’t need any special configuration.

Unfortunately, this is a really bad idea, for two main reasons:

Version control

The developers of BIND are constantly finding and fixing security-related bugs in the BIND code. Consequently, it’s important to run a recent version of BIND, especially on nameservers directly exposed to the Internet. If one or just a few of your nameservers communicate directly with nameservers on the Internet, upgrading them to a new version is easy. If any of the nameservers on your network can communicate directly with nameservers on the Internet, upgrading all of them is vastly more difficult.

Possible vector for attack

Even if you’re not running a nameserver on a particular host, a hacker might be able to take advantage of your allowing DNS traffic through your firewall to attack that host. For example, a co-conspirator working on the inside could set up a Telnet daemon listening on the host’s DNS port, allowing the hacker to telnet right in.

For the rest of this chapter, we’ll try to set a good example.

Internet Forwarders

Given the dangers of allowing bidirectional DNS traffic through the firewall unrestricted, most organizations limit the internal hosts that can “talk DNS” to the Internet. In a proxy-based firewall, or any firewall without the ability to pass DNS traffic, the only hosts that can communicate with Internet nameservers are the bastion hosts (see Figure 11-3).

A small network, showing the bastion host
Figure 11-3. A small network, showing the bastion host

In a packet-filtering firewall, the firewall’s administrator can configure the firewall to let any set of internal nameservers communicate with Internet nameservers. Often, this is a small set of hosts that run nameservers under the direct control of the network administrator (see Figure 11-4).

A small network, showing select internal nameservers
Figure 11-4. A small network, showing select internal nameservers

Internal nameservers that can directly query nameservers on the Internet don’t require any special configuration. Their root hints files contain the Internet’s root nameservers, which enables them to resolve Internet domain names. Internal nameservers that can’t query nameservers on the Internet, however, need to know to forward queries they can’t resolve to one of the nameservers that can. This is done with the forwarders substatement, introduced in Chapter 10.

Figure 11-5 illustrates a common forwarding setup, with internal nameservers forwarding queries to a nameserver running on a bastion host.

Using forwarders
Figure 11-5. Using forwarders

At Movie U., we put in a firewall to protect ourselves from the Big Bad Internet several years ago. Ours is a packet-filtering firewall, and we negotiated with our firewall administrator to allow DNS traffic between Internet nameservers and two of our nameservers, toystory.movie.edu and wormhole.movie.edu . Here’s how we configured the other internal nameservers at the university. For our BIND 8 and 9 nameservers, we used the following:

options {
    forwarders { 192.249.249.1; 192.249.249.3; };
    forward only;
};

We vary the order in which the forwarders appear to help spread the load between them, though that’s not necessary with BIND 8.2.3 and later or 9.3.0 and later nameservers, which choose a forwarder to query according to roundtrip time.

When an internal nameserver receives a query for a name it can’t resolve locally, such as an Internet domain name, it forwards that query to one of our forwarders, which can resolve the name using nameservers on the Internet. Simple!

The trouble with forwarding

Unfortunately, it’s a little too simple. Forwarding starts to get in the way once you delegate subdomains or build an extensive network. To explain what we mean, take a look at part of the configuration file on zardoz.movie.edu :

options {
    directory "/var/named";
    forwarders { 192.249.249.1; 192.253.253.3; };
};

zone "movie.edu" {
    type slave;
    masters { 192.249.249.3; };
    file "bak.movie.edu";
};

zardoz.movie.edu is a slave for movie.edu and uses our two forwarders. What happens when zardoz.movie.edu receives a query for a name in fx.movie.edu? As an authoritative movie.edu nameserver, zardoz.movie.edu has the NS records that delegate fx.movie.edu to its authoritative nameservers. But it’s also been configured to forward queries it can’t resolve locally to toystory.movie.edu and wormhole.movie.edu . Which will it do?

It turns out that zardoz.movie.edu ignores the delegation information and forwards the query to toystory.movie.edu . That works because toystory.movie.edu receives the recursive query and asks an fx.movie.edu nameserver on zardoz.movie.edu ’s behalf. But it’s not particularly efficient because zardoz.movie.edu could easily have sent the query directly.

Now imagine that the scale of the network is much larger: a corporate network that spans continents, with tens of thousands of hosts and hundreds or thousands of nameservers. All the internal nameservers that don’t have direct Internet connectivity—the vast majority of them—use a small set of forwarders. What’s wrong with this picture?

Single point of failure

If the forwarders fail, your nameservers lose the ability to resolve both Internet domain names and internal domain names that they don’t have cached or stored as authoritative data.

Concentration of load

The forwarders have an enormous query load placed on them. This is both because of the large number of internal nameservers that use them, and because the queries are recursive and require a good deal of work to answer.

Inefficient resolution

Imagine two internal nameservers, authoritative for west.acmebw.com and east.acmebw.com , respectively, both on the same network segment in Boulder, Colorado. Both are configured to use the company’s forwarder in Bethesda, Maryland. For the west.acmebw.com nameserver to resolve a name in east.acmebw.com , it sends a query to the forwarder in Bethesda. The forwarder in Bethesda then sends a query back to Boulder to the east.acmebw.com nameserver, the original querier’s neighbor. The east.acmebw.com nameserver replies by sending a response back to Bethesda, which the forwarder sends back to Boulder.

In a traditional configuration with root nameservers, the west.acmebw.com nameserver would have quickly learned that an east.acmebw.com nameserver was next door and would favor it (because of its low roundtrip time). Using forwarders short-circuits the normally efficient resolution process.

The upshot is that forwarding is fine for small networks and simple namespaces, but probably inadequate for large networks and complex namespaces. We found this out the hard way at Movie U., as our network grew, and we were forced to find an alternative.

Using forward zones

We can solve the previous problem using the forward zones introduced in BIND 8.2 and 9.1.0.[*] We change zardoz.movie.edu ’s configuration to this:

options {
    directory "/var/named";
    forwarders { 192.249.249.1; 192.253.253.3; };
};

zone "movie.edu" {
    type slave;
    masters { 192.249.249.3; };
    file "bak.movie.edu";
    forwarders {};
};

Notice the forwarders substatement with the null list of forwarders. Now, if zardoz.movie.edu receives a query for a domain name ending in movie.edu but outside the movie.edu zone (e.g., in fx.movie.edu), it ignores the forwarders configured in the options statement and sends iterative queries.

With this configuration, zardoz.movie.edu still sends queries for domain names in our reverse-mapping zones to our forwarders. To relieve that load, we can add a few zone statements to named.conf:

zone "249.249.192.in-addr.arpa" {
    type stub;
    masters { 192.249.249.3; };
    file "stub.192.249.249";
    forwarders {};
};

zone "253.253.192.in-addr.arpa" {
    type stub;
    masters { 192.249.249.3; };
    file "stub.192.253.253";
    forwarders {};
};

zone "254.253.192.in-addr.arpa" {
    type stub;
    masters { 192.253.254.2; };
    file "stub.192.253.254";
    forwarders {};
};

zone "20.254.192.in-addr.arpa" {
    type stub;
    masters { 192.253.254.2; };
    file "stub.192.254.20";
    forwarders {};
};

These new zone statements bear some explaining. First of all, they configure Movie U.’s reverse-mapping zones as stubs. That makes our nameserver track the NS records for those zones by periodically querying the master nameservers for those zones. The forwarders substatement then turns off forwarding for domain names in the reverse-mapping domains. Now, instead of querying the forwarders for, say, the PTR record for 2.254.253.192.in-addr.arpa, zardoz.movie.edu will query one of the 254.253.192.in-addr.arpa nameservers directly.

We’ll need zone statements like these on all our internal nameservers, which implies that we’ll need all our nameservers to run some version of BIND 8 after 8.2 or 9.2.0.

This gives us a fairly robust resolution architecture that minimizes our exposure to the Internet: it uses efficient, robust iterative name resolution to resolve internal domain names, and forwarders only when necessary to resolve Internet domain names. If our forwarders fail, or we lose our connection to the Internet, we only lose our ability to resolve Internet domain names.

Internal Roots

If you want to avoid the scalability problems of forwarding, you can set up your own root nameservers. These internal roots will serve only the nameservers in your organization. They’ll know only about the portions of the namespace relevant to your organization.

What good are they? By using an architecture based on root nameservers, you gain the scalability of the Internet’s namespace (which should be good enough for most companies), plus redundancy, distributed load, and efficient resolution. You can have as many internal roots as the Internet has roots—13 or so—whereas having that many forwarders may be an undue security exposure and a configuration burden. Most of all, the internal roots don’t get used frivolously. Nameservers need to consult an internal root only when they time out the NS records for your top-level zones. Using forwarders, nameservers may have to query a forwarder once per resolution.

The moral of our story is that if you have, or intend to have, a large namespace and lots of internal nameservers, internal root nameservers will scale better than any other solution.

Where to put internal root nameservers

Since nameservers “lock on” to the closest root nameserver by favoring the one with the lowest roundtrip time, it pays to pepper your network with internal root nameservers. If your organization’s network spans the United States, Europe, and the Pacific Rim, consider locating at least one internal root nameserver on each continent. If you have three major sites in Europe, give each of them an internal root.

Forward-mapping delegation

Here’s how an internal root nameserver is configured. An internal root delegates directly to any zones you administer. For example, on the movie.edu network, the root zone’s datafile contains:

movie.edu.  86400  IN  NS  toystory.movie.edu.
            86400  IN  NS  wormhole.movie.edu.
            86400  IN  NS  zardoz.movie.edu.
toystory.movie.edu.    86400  IN  A  192.249.249.3
wormhole.movie.edu.    86400  IN  A  192.249.249.1
                       86400  IN  A  192.253.253.1
zardoz.movie.edu.      86400  IN  A  192.249.249.9
                       86400  IN  A  192.253.253.9

On the Internet, this information appears in the edu nameservers’ zone datafiles. On the movie.edu network, of course, there aren’t any edu nameservers, so you delegate directly to movie.edu from the root.

Notice that this doesn’t contain delegation to fx.movie.edu or to any other subdomain of movie.edu. The movie.edu nameservers know which nameservers are authoritative for all movie.edu subdomains, and all queries for information in those subdomains pass through the movie.edu nameservers, so there’s no need to delegate them here.

in-addr.arpa delegation

We also need to delegate from the internal roots to the in-addr.arpa zones that correspond to the networks at the university:

249.249.192.in-addr.arpa.  86400  IN  NS  toystory.movie.edu.
                           86400  IN  NS  wormhole.movie.edu.
                           86400  IN  NS  zardoz.movie.edu.
253.253.192.in-addr.arpa.  86400  IN  NS  toystory.movie.edu.
                           86400  IN  NS  wormhole.movie.edu.
                           86400  IN  NS  zardoz.movie.edu.
254.253.192.in-addr.arpa.  86400  IN  NS  bladerunner.fx.movie.edu.
                           86400  IN  NS  outland.fx.movie.edu.
                           86400  IN  NS  alien.fx.movie.edu.
20.254.192.in-addr.arpa.   86400  IN  NS  bladerunner.fx.movie.edu.
                           86400  IN  NS  outland.fx.movie.edu.
                           86400  IN  NS  alien.fx.movie.edu.

Notice that we did include delegation for the 254.253.192.in-addr.arpa and the 20.254.192.in-addr.arpa zones, even though they correspond to the fx.movie.edu zone. We don’t need to delegate to fx.movie.edu because we already delegated to its parent, movie.edu. The movie.edu nameservers delegate to fx.movie.edu, so, by transitivity, the roots delegate to fx.movie.edu. Since neither of the other in-addr.arpa zones is a parent of 254.253.192.in-addr.arpa or 20.254.192.in-addr.arpa, we need to delegate both zones from the root. As we explained earlier, we don’t need to add address records for the three Special Effects nameservers, bladerunner.fx.movie.edu , outland.fx.movie.edu , and alien.fx.movie.edu , because a remote nameserver can already find their addresses by following delegation from movie.edu.

The db.root file

All that’s left is to add an SOA record for the root zone and NS records for this internal root nameserver and any others:

$TTL 1d
.  IN  SOA  rainman.movie.edu.  hostmaster.movie.edu.  (
            1    ; serial
            3h   ; refresh
            1h   ; retry
            1w   ; expire
            1h ) ; negative caching TTL

   IN  NS  rainman.movie.edu.
   IN  NS  awakenings.movie.edu.

rainman.movie.edu.    IN  A  192.249.249.254
awakenings.movie.edu. IN  A  192.253.253.254

rainman.movie.edu and awakenings.movie.edu are the hosts running the internal root nameservers. We shouldn’t run an internal root on a bastion host, because of the danger of the root becoming corrupt by caching external data.

So the whole db.root file (by convention, we call the root zone’s datafile db.root) looks like this:

$TTL 1d
.  IN  SOA  rainman.movie.edu.  hostmaster.movie.edu.  (
            1    ; serial
            3h   ; refresh
            1h   ; retry
            1w   ; expire
            1h ) ; negative caching TTL

   IN  NS  rainman.movie.edu.
   IN  NS  awakenings.movie.edu.

rainman.movie.edu.    IN  A  192.249.249.254
awakenings.movie.edu. IN  A  192.253.253.254

movie.edu.  IN  NS  toystory.movie.edu.
            IN  NS  wormhole.movie.edu.
            IN  NS  zardoz.movie.edu.

toystory.movie.edu.    IN  A  192.249.249.3
wormhole.movie.edu.    IN  A  192.249.249.1
                       IN  A  192.253.253.1
zardoz.movie.edu.      IN  A  192.249.249.9
                       IN  A  192.253.253.9

249.249.192.in-addr.arpa.  IN  NS  toystory.movie.edu.
                           IN  NS  wormhole.movie.edu.
                           IN  NS  zardoz.movie.edu.
253.253.192.in-addr.arpa.  IN  NS  toystory.movie.edu.
                           IN  NS  wormhole.movie.edu.
                           IN  NS  zardoz.movie.edu.
254.253.192.in-addr.arpa.  IN  NS  bladerunner.fx.movie.edu.
                           IN  NS  outland.fx.movie.edu.
                           IN  NS  alien.fx.movie.edu.
20.254.192.in-addr.arpa.   IN  NS  bladerunner.fx.movie.edu.
                           IN  NS  outland.fx.movie.edu.
                           IN  NS  alien.fx.movie.edu.

The named.conf file on both the internal root nameservers, rainman.movie.edu and awakenings.movie.edu , contains the lines:

zone "." {
    type master;
    file "db.root";
};

This replaces a zone statement of type hint—a root nameserver doesn’t need a root hints file to tell it where the other roots are; it can find that in db.root. Did we really mean that each root nameserver is a primary for the root zone? No, the root zone is just like any zone, so you’ll probably have one primary nameserver and the rest slaves.

If you don’t have a lot of idle hosts sitting around that you can turn into internal roots, don’t despair! Any internal nameserver (i.e., one that’s not running on a bastion host or outside your firewall) can serve double duty as an internal root and as an authoritative nameserver for whatever other zones you need it to load. Remember, a single nameserver can be authoritative for many, many zones, including the root zone.

Configuring other internal nameservers

Once you’ve set up internal root nameservers, configure all your nameservers on hosts anywhere on your internal network to use them. Any nameserver running on a host without direct Internet connectivity (i.e., behind the firewall) should list the internal roots in its root hints file:

; Internal root hints file, for Movie U. hosts without direct
; Internet connectivity
;
; Don't use this file on a host with Internet connectivity!
;

.  99999999  IN  NS  rainman.movie.edu.
   99999999  IN  NS  awakenings.movie.edu.

rainman.movie.edu.     99999999  IN  A  192.249.249.254
awakenings.movie.edu.  99999999  IN  A  192.253.253.254

Nameservers running on hosts using this root hints file can resolve domain names in movie.edu and in Movie U.’s in-addr.arpa domains, but not outside those domains.

How internal nameservers use internal roots

To tie together how this whole scheme works, let’s go through an example of name resolution on an internal caching-only nameserver using these internal root nameservers. First, the internal nameserver receives a query for a domain name in movie.edu, say the address of gump.fx.movie.edu . If the internal nameserver doesn’t have any “better” information cached, it starts by querying an internal root nameserver. If it has communicated with the internal roots before, it has a round-trip time associated with each, telling it which of the internal roots responded to it most quickly. It then sends a nonrecursive query to that internal root for gump.fx.movie.edu ’s address. The internal root answers with a referral to the movie.edu nameservers on toystory.movie.edu , wormhole.movie.edu , and zardoz.movie.edu . The caching-only nameserver follows up by sending another nonrecursive query to one of the movie.edu nameservers for gump.fx.movie.edu ’s address. The movie.edu nameserver responds with a referral to the fx.movie.edu nameservers. The caching-only nameserver sends the same nonrecursive query for gump.fx.movie.edu ’s address to one of the fx.movie.edu nameservers and finally receives a response.

Contrast this with the way a forwarding setup works. Let’s imagine that instead of using internal root nameservers, our caching-only nameserver is configured to forward queries first to toystory.movie.edu and then to wormhole.movie.edu . In that case, the caching-only nameserver checks its cache for the address of gump.fx.movie.edu and, not finding it, forwards the query to toystory.movie.edu . Then toystory.movie.edu queries an fx.movie.edu nameserver on the caching-only nameserver’s behalf and returns the answer. Should the caching-only nameserver need to look up another name in fx.movie.edu, it still asks the forwarder, even though the forwarder’s response to the query for gump.fx.movie.edu ’s address probably contains the names and addresses of the fx.movie.edu nameservers.

Mail from internal hosts to the Internet

But wait! That’s not all internal roots will do for you. We talked about getting mail to the Internet without changing sendmail’s configuration all over the network.

Wildcard records are the key to getting mail to work—specifically, wildcard MX records. Let’s say that we want mail to the Internet to be forwarded through postmanrings2x.movie.edu , the Movie U. bastion host, which has direct Internet connectivity. Adding the following records to db.root gets the job done:

*        IN    MX    5 postmanrings2x.movie.edu.
*.edu.   IN    MX    10 postmanrings2x.movie.edu.

We need the *.edu MX record in addition to the * record because of wildcard production rules, which you can read more about in the section "Wildcards" in Chapter 16. Basically, since there is explicit data for movie.edu in the zone, the first wildcard won’t match movie.edu or any other subdomains of edu. We need another, explicit wildcard record in edu to match subdomains of edu besides movie.edu.

Now mailers on our internal movie.edu hosts will send mail addressed to Internet domain names to postmanrings2x.movie.edu for forwarding. For example, mail addressed to nic.ddn.mil matches the first wildcard MX record:

%nslookup -type=mx nic.ddn.mil.  Matches the MX record for *
Server:  rainman.movie.edu
Address:  192.249.249.19

nic.ddn.mil
     preference = 5, mail exchanger = postmanrings2x.movie.edu
postmanrings2x.movie.edu    internet address = 192.249.249.20

Mail addressed to vangogh.cs.berkeley.edu matches the second MX record:

%nslookup -type=mx vangogh.cs.berkeley.edu.  Matches the MX record for *.edu
Server:  rainman.movie.edu
Address:  192.249.249.19

vangogh.cs.berkeley.edu
     preference = 10, mail exchanger = postmanrings2x.movie.edu
postmanrings2x.movie.edu    internet address = 192.249.249.20

Once the mail has reached postmanrings2x.movie.edu , our bastion host, postmanrings2x.movie.edu ’s mailer looks up the MX records for these addresses itself. Since postmanrings2x.movie.edu resolves the destination’s domain name in the Internet’s namespace instead of the internal namespace, it will find the real MX records for the domain name and deliver the mail. No changes to sendmail’s configuration are necessary.

Mail to specific Internet domain names

Another nice perk of this internal root scheme is that it enables you to forward mail addressed to certain Internet domain names through particular bastion hosts, if you have more than one. We can choose, for example, to send all mail addressed to recipients in the uk domain to our bastion host in London first and then out onto the Internet. This can be very useful if we want our mail to travel across our own network as far as possible or if we’re billed for our usage of some network in the United Kingdom.

Movie U. has a private network connection to our sister university in London near Pinewood Studios. For security reasons, we’d like to send mail addressed to correspondents in the United Kingdom. across our private link and then through the Pinewood host. So we add the following wildcard records to db.root:

; holygrail.movie.ac.uk is at the other end of our U.K. Internet link
*.uk.    IN    MX    10 holygrail.movie.ac.uk.
holygrail.movie.ac.uk.    IN   A    192.168.76.4

Now mail addressed to users in subdomains of uk will be forwarded to the host holygrail.movie.ac.uk at our sister university, which presumably has facilities to forward that mail to other points in the United Kingdom.

The trouble with internal roots

Unfortunately, just as forwarding has its problems, internal root architectures have their limitations. Chief among these is the fact that your internal hosts can’t see the Internet namespace. On some networks, this isn’t an issue because most internal hosts don’t have any direct Internet connectivity. The few that do can have their resolvers configured to use a nameserver on a bastion host. Some of these hosts will probably need to run proxy servers to allow other internal hosts access to services on the Internet.

On other networks, however, the Internet firewall or other software may require that all internal hosts be able to resolve names in the Internet’s namespace. For these networks, an internal root architecture won’t work.

A Split Namespace

Many organizations would like to advertise different zone data to the Internet than they advertise internally. In most cases, much of the internal zone data is irrelevant to the Internet because of the organization’s Internet firewall. The firewall may not allow direct access to most internal hosts and may also translate internal, unregistered IP addresses into a range of IP addresses registered to the organization. Therefore, the organization might need to trim out irrelevant information from the external view of the zone or change internal addresses to their external equivalents.

Unfortunately, BIND doesn’t support automatic filtering and translation of zone data. Consequently, many organizations manually create what have become known as split namespaces. In a split namespace, the real namespace is available only internally, while a pared-down, translated version of it called the shadow namespace is visible to the Internet.

The shadow namespace contains the name-to-address and address-to-name mappings of only those hosts on your perimeter network (i.e., outside your firewall) or accessible from the Internet through the firewall. The addresses advertised may be the translated equivalents of internal addresses. The shadow namespace may also contain one or more MX records to direct mail from the Internet through the firewall to a mail server.

Since Movie U. has an Internet firewall that greatly limits access from the Internet to the internal network, we elected to create a shadow namespace. For the zone movie.edu, the only information we need to give out is about the domain name movie.edu (an SOA record and a few NS records); the bastion host (postmanrings2x.movie.edu ); our new external nameserver, ns.movie.edu ; and our external web server, www.movie.edu. The address of the external interface on the bastion host is 200.1.4.2, the address of the nameserver is 200.1.4.3, and the address of the web server is 200.1.4.4. The shadow movie.edu zone datafile looks like this:

$TTL 1d
@    IN    SOA    ns.movie.edu.    hostmaster.movie.edu. (
                           1    ; Serial
                           3h   ; Refresh
                           1h   ; Retry
                           1w   ; Expire
                           1h ) ; Negative caching TTL

    IN    NS    ns.movie.edu.
    IN    NS    ns1.isp.net.        ; our ISP's name server is a movie.edu slave

    IN    A     200.1.4.4    ; for people who try to access http://movie.edu
    IN    MX    10 postmanrings2x.movie.edu.
    IN    MX    100 mail.isp.net.

www             IN    A     200.1.4.4

postmanrings2x  IN    A     200.1.4.2
                IN    MX    10 postmanrings2x.movie.edu.
                IN    MX    100 mail.isp.net.

;postmanrings2x.movie.edu handles mail addressed to ns.movie.edu
ns              IN    A     200.1.4.3
                IN    MX    10 postmanrings2x.movie.edu.
                IN    MX    100 mail.isp.net.

*               IN    MX    10 postmanrings2x.movie.edu.
                IN    MX    100 mail.isp.net.

Note that there’s no mention of any of the subdomains of movie.edu, including any delegation to the nameservers for those subdomains. The information simply isn’t necessary because there’s nothing in any of the subdomains that you can get to from the Internet, and inbound mail addressed to hosts in the subdomains is caught by the wildcard.

The db.200.1.4 file, which we need in order to reverse-map the two Movie U. IP addresses that hosts on the Internet might see, looks like this:

$TTL 1d
@    IN    SOA    ns.movie.edu.    hostmaster.movie.edu. (
                           1    ; Serial
                           3h   ; Refresh
                           1h   ; Retry
                           1w   ; Expire
                           1h ) ; Negative caching TTL

    IN    NS    ns.movie.edu.
    IN    NS    ns1.isp.net.

2    IN    PTR    postmanrings2x.movie.edu.
3    IN    PTR    ns.movie.edu.
4    IN    PTR    www.movie.edu.

One precaution we have to take is to make sure that the resolvers on our bastion host, on our mail server, and on our web server aren’t configured to use the server on ns.movie.edu . Since that server can’t see the real, internal movie.edu, using it renders these hosts unable to map internal domain names to addresses or internal addresses to names.

Configuring the bastion host

The bastion host is a special case in a split namespace configuration. It has a foot in each environment: one network interface connects it to the Internet and another connects it to the internal network. Now that we have split our namespace in two, how can our bastion host see both the Internet namespace and our real internal namespace? If we configure it with the Internet’s root nameservers in its root hints file, it will follow delegation from the Internet’s edu nameservers to an external movie.edu nameserver with shadow zone data. It would be blind to our internal namespace, which it needs to see to log connections, deliver inbound mail, and more. On the other hand, if we configure it with our internal roots, it won’t see the Internet’s namespace, which it clearly needs to do in order to function as a bastion host. What to do?

If we have internal nameservers that can resolve both internal and Internet domain names—using forward zones per the configuration earlier in this chapter, for example—we can simply configure the bastion host’s resolver to query those nameservers. But if we use forwarding internally, depending on the type of firewall we’re running, we may also need to run a forwarder on the bastion host itself. If the firewall won’t pass DNS traffic, we’ll need to run at least a caching-only nameserver, configured with the Internet roots, on the bastion host so that our internal nameservers will have somewhere to forward their unresolved queries.

If our internal nameservers don’t support forward zones, the nameserver on our bastion host must be configured as a slave or stub for movie.edu and any in-addr.arpa zones in which it needs to resolve addresses. This way, if it receives a query for a domain name in movie.edu, it uses its local authoritative data to resolve the name (in the case of a slave zone) or follows internal NS records to the authoritative nameservers (for a stub zone). (If our internal nameservers support forward zones and are configured correctly, the nameserver on our bastion host will never receive queries for names in movie.edu.) If the domain name is in a delegated subdomain of movie.edu, it follows NS records that are in the movie.edu zone data or received from a movie.edu nameserver to query an internal nameserver for the name. Therefore, it doesn’t need to be configured as a slave or stub for any movie.edu subdomains, such as fx.movie.edu, just the “topmost” zone (see Figure 11-6).

A split DNS solution
Figure 11-6. A split DNS solution

The named.conf file on our bastion host looks like this:

options {
    directory "/var/named";
};

zone "movie.edu" {
    type slave;
    masters { 192.249.249.3; };
    file "bak.movie.edu";
};

zone "249.249.192.in-addr.arpa" {
    type slave;
    masters { 192.249.249.3; };
    file "bak.192.249.249";
};

zone "253.253.192.in-addr.arpa" {
    type slave;
    masters { 192.249.249.3; };
    file "bak.192.253.253";
};

zone "254.253.192.in-addr.arpa" {
    type slave;
    masters { 192.253.254.2; };
    file "bak.192.253.254";
};

zone "20.254.192.in-addr.arpa" {
    type slave;
    masters { 192.253.254.2; };
    file "bak.192.254.20";
};

zone "." {
    type hint;
    file "db.cache";
};

Protecting zone data on the bastion host

Unfortunately, loading these zones on the bastion host also exposes them to the possibility of disclosure on the Internet, which we were trying to avoid by splitting the namespace in the first place. But we can protect the zone data using the allow-query substatement, discussed earlier in the chapter. With allow-query, we can place a global access list on our zone data. Here’s the new options statement from our named.conf file:

options {
    directory "/var/named";
    allow-query { 127/8; 192.249.249/24; 192.253.253/24;
        192.253.254/24; 192.254.20/24; };
};

Don’t forget to include the loopback address in the list, or the bastion host’s resolver may not get answers from its own nameserver!

The final configuration

Finally, we need to apply the other security precautions we discussed earlier to our bastion host’s nameserver. In particular, we should:

  • Restrict zone transfers

  • Use the ID pool feature (on BIND 8.2 or newer nameservers but not BIND 9)

  • (Optionally) Run BIND chrooted and with least privilege

In the end, our named.conf file ends up looking like this:

acl "internal" {
    127/8; 192.249.249/24; 192.253.253/24;
    192.253.254/24; 192.254.20/24;
};

options {
    directory "/var/named";
    allow-query { "internal"; };
    allow-transfer { none; };
};

zone "movie.edu" {
    type slave;
    masters { 192.249.249.3; };
    file "bak.movie.edu";
};

zone "249.249.192.in-addr.arpa" {
    type slave;
    masters { 192.249.249.3; };
    file "bak.192.249.249";
};

zone "253.253.192.in-addr.arpa" {
    type slave;
    masters { 192.249.249.3; };
    file "bak.192.253.253";
};

zone "254.253.192.in-addr.arpa" {
    type slave;
    masters { 192.253.254.2; };
    file "bak.192.253.254";
};

zone "20.254.192.in-addr.arpa" {
    type slave;
    masters { 192.253.254.2; };
    file "bak.192.254.20";
};

zone "." {
    type hint;
    file "db.cache";
};

Using views on the bastion host

If we’re running BIND 9 on our bastion host, we can use views to safely present the shadow movie.edu to the outside world on the same nameserver that resolves Internet domain names. That may obviate the need to run an external nameserver on ns.movie.edu . If not, it’ll give us an additional nameserver to advertise the external movie.edu.

This configuration is very similar to one shown in the “Views” section in Chapter 10:

options {
    directory "/var/named";
};

acl "internal" {
    127/8; 192.249.249/24; 192.253.253/24; 192.253.254/24; 192.254.20/24;
};

view "internal" {
    match-clients { "internal"; };
    recursion yes;

    zone "movie.edu" {
        type slave;
        masters { 192.249.249.3; };
        file "bak.movie.edu";
     };

    zone "249.249.192.in-addr.arpa" {
        type slave;
        masters { 192.249.249.3; };
        file "bak.192.249.249";
    };

    zone "253.253.192.in-addr.arpa" {
        type slave;
        masters { 192.249.249.3; };
        file "bak.192.253.253";
    };

    zone "254.253.192.in-addr.arpa" {
        type slave;
        masters { 192.253.254.2; };
        file "bak.192.253.254";
    };

    zone "20.254.192.in-addr.arpa" {
        type slave;
        masters { 192.253.254.2; };
        file "bak.192.254.20";
    };

    zone "." {
        type hint;
        file "db.cache";
    };
};

acl "ns1.isp.net" { 199.11.28.12; };

view "external" {
    match-clients { any; };
    recursion no;

    zone "movie.edu" {
        type master;
        file "db.movie.edu.external";
        allow-transfer { "ns1.isp.net"; };
    };

    zone "4.1.200.in-addr.arpa" {
        type master;
        file "db.200.1.4";
        allow-transfer { "ns1.isp.net"; };
    };

    zone "." {
        type hint;
        file "db.cache";
    };
};

Notice that the internal and external views present different versions of movie.edu: one loaded from the primary nameserver for the internal movie.edu and one loaded from the zone datafile db.movie.edu.external. If there were more than a few zones in our external view, we probably would have used a different subdirectory for our external zone datafiles than we used for the internal zone datafiles.

The DNS Security Extensions

TSIG, which we described earlier in this chapter, is well suited to securing the communications between two nameservers or between an updater and a nameserver. However, it won’t protect you if one of your nameservers is compromised: if someone breaks into the host that runs one of your nameservers, he may also gain access to its TSIG keys. Moreover, because TSIG uses shared secrets, it isn’t practical to configure TSIG among many nameservers. You couldn’t use TSIG to secure your nameservers’ communications with arbitrary nameservers on the Internet because you can’t distribute and manage that many keys.

The most common way to deal with key management problems like these is to use public-key cryptography. The DNS Security Extensions (DNSSEC), described in RFCs 4033, 4034, and 4035, use public-key cryptography to enable zone administrators to digitally sign their zone data, thereby proving its authenticity.

Tip

We’ll describe the DNS Security Extensions in their current form as described by RFCs 4033 through 4035. These RFCs reflect substantial changes in DNSSEC since its original version, described in RFC 2065 (and in the previous edition of this book). However, the IETF’s DNSEXT working group is still working on DNSSEC and may change aspects of it before it becomes a standard.

Also know that though BIND 8 provided preliminary support of DNSSEC as early as BIND 8.2,[*] DNSSEC wasn’t really usable before BIND 9, and it isn’t implemented as described in this section (and in the latest RFCs) until 9.3.0. Consequently, we’ll use BIND 9.3.2 in our examples. If you want to use DNSSEC, you really shouldn’t use anything older.

Public-Key Cryptography and Digital Signatures

Public-key cryptography solves the key distribution problem by using asymmetric cryptographic algorithms. In an asymmetric cryptographic algorithm, one key is used to decrypt data that another has encrypted. These two keys—a key pair—are generated at the same time using a mathematical formula. That’s the only easy way to find two keys that have this special asymmetry (one decrypts what the other encrypts): it’s very difficult to determine one key given the other. (In the most popular asymmetric cryptographic algorithm, RSA, that determination involves factoring very large numbers, a notoriously hard problem.)

In public-key cryptography, an individual first generates a key pair. Then, one key of the key pair is made public (e.g., published in a directory), while the other is kept private. Someone who wants to communicate securely with that individual can encrypt a message with the individual’s public key and then send the encrypted message to the individual. (Or he could even post the message to a newsgroup or on a web site.) If the recipient has kept his private key private, only he can decrypt the message.

Conversely, the individual can encrypt a message with his private key and send it to someone. The recipient can verify that it came from that individual by attempting to decrypt it with the individual’s public key. If the message decrypts to something reasonable (i.e., not gibberish), and the sender kept his private key to himself, the individual must have encrypted it. Successful decryption also proves that the message wasn’t modified in transit (e.g., while passing through a mail server), because if it had been, it wouldn’t have decrypted correctly. So the recipient has authenticated the message.

Unfortunately, encrypting large amounts of data with asymmetric encryption algorithms tends to be slow—much slower than encryption using symmetric encryption algorithms. But when using public-key encryption for authentication (and not for privacy), we don’t have to encrypt the whole message. Instead, we run the message through a one-way hash function first. Then we can encrypt just the hash value, which represents the original data. We attach the encrypted hash value, now called a digital signature, to the message we want to authenticate. The recipient can still authenticate the message by decrypting the digital signature and running the message through his own copy of the one-way hash function. If the hash values match, the message is authentic. We call the process of computing the hash value and encrypting it signing, and the process of validating the digital signature verifying. The process of signing and verifying a message is shown in Figure 11-7.

Signing and verifying a message
Figure 11-7. Signing and verifying a message

The DNSKEY Record

In the DNS Security Extensions, each signed zone has a key pair associated with it. The zone’s private key is stored somewhere safe, often in a file on the primary nameserver’s filesystem. The zone’s public key is advertised as a new type of record attached to the domain name of the zone, the DNSKEY record.

The previous version included a general-purpose KEY record: you could use the record to store different kinds of cryptographic keys, not just zones’ public keys for use with DNSSEC. However, the revised DNSSEC uses the DNSKEY record only to store a zone’s public key.

A DNSKEY record looks like this:

movie.edu. IN DNSKEY 257 3 5 AQPWA4BRyjB3eqYNy/oykeGcSXjl+HQK9CciAxJfMcS1vEuwz9c
+QG7s EJnQuH5B9i5o/ja+DVitY3jpXNa12mEn

The owner is the domain name of the zone that owns this public key. The first field after the type, 257, is the flags field. The flags field is two bytes long and encodes a set of two one-bit values:

  0   1   2   3   4   5   6   7   8   9   0   1   2   3   4   5
+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
|                           |ZK |                           |SEP|
+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+

The first seven bits (0 through 6) and bits 8 through 14 are reserved and must have a value of 0.

The eighth bit encodes the type of key:

0

This is not a DNS zone key and can’t be used to verify signed zone data.

1

This is a DNS zone key. The DNSKEY record’s owner name is the domain name of the zone.

The last bit (15) is the Secure Entry Point (SEP) flag, which has an experimental use documented in RFC 3757. We’ll discuss it in more detail later in the chapter.

In the DNSKEY record shown earlier, the flags field (the first field in the record after the type) says that this DNSKEY is movie.edu’s zone key.

The next field in the record, which in the example has the value 3, is called the protocol field. This is a holdover from the older version of DNSSEC, when you could use KEY records for different purposes. In the current version of DNSSEC, however, you can use DNSKEY records only with DNSSEC, so this field is always set to 3, which historically indicated a DNSSEC key.

The next (third) field in the DNSKEY record, which here has the value 5, is the algorithm field. DNSSEC can work with a number of public-key encryption algorithms, so you need to identify which algorithm a zone uses and which algorithm this key is used with here. The following values are defined:

0

Reserved.

1

RSA/MD5. The use of RSA/MD5 is no longer recommended, mostly due to recently discovered shortcomings in the MD5 one-way hash algorithm.

2

Diffie-Hellman. Diffie-Hellman can’t be used to sign zones, but it can be used for other DNSSEC-related purposes.

3

DSA/SHA-1. The use of DSA/SHA-1 (in addition to any mandatory algorithm) is optional.

4

Reserved for an elliptic curve-based public-key algorithm.

5

RSA/SHA-1. The use of RSA/SHA-1 is mandatory.

253-254

Private. These algorithm numbers are reserved for private use per RFC 4034.

255

Reserved.

We’ll use RSA/SHA-1 keys in our examples, naturally.

The final field in the DNSKEY record is the public key itself, encoded in base 64. DNSSEC supports keys of many lengths, as we’ll see shortly when we generate the movie.edu public key. The longer the key, the more secure (because it’s harder to find the corresponding private key), but the longer it takes to sign zone data with the private key and verify it with the public key, and the longer the DNSKEY record and signatures created.

The RRSIG Record

If the DNSKEY record stores a zone’s public key, then there must be a new record to store the corresponding private key’s signature, right? Sure enough, that’s the RRSIG record. The RRSIG record stores the private key’s digital signature on an RRset. An RRset is a group of resource records with the same owner, class, and type; for example, all of wormhole.movie.edu ’s address records make up an RRset. Likewise, all of movie.edu’s MX records are another RRset.

Why sign RRsets rather than individual records? It saves time. There’s no way to look up just one of wormhole.movie.edu ’s address records; a nameserver will always return them as a group. So why go to the trouble of signing each one individually when you can sign them together?

Here’s the RRSIG record that “covers” wormhole.movie.edu ’s address records:

wormhole.movie.edu.        86400   RRSIG   A 5 3 86400 20060219233605 (
                                        20060120233605 3674 movie.edu.
                                        ZZP9AV28r824SZJqyIT+3WKkMQgcu1YTuFzp
                                        LgU3EN4USgpJhLZbYBqTHL77mipET5aJr8Od
                                        RxZvfFHHYV6UGw== )

The owner name is wormhole.movie.edu , the same as the owner of the records signed. The first field after the type, which holds the value A, is called the type covered. That tells us which of wormhole.movie.edu ’s records were signed—in this case, its address records. There would be a separate RRSIG record for each type of record wormhole.movie.edu might own.

The second field, which has the value 5, is the algorithm field. This is one of the same values used in the DNSKEY record’s algorithm field, so 5 means RSA/SHA-1. If you generate an RSA/SHA-1 key and use it to sign your zone, you’ll get RSA/SHA-1 signatures, naturally. If you sign your zone with multiple types of keys, say an RSA/SHA-1 key and a DSA key, you’ll end up with two RRSIG records for each RRset, one with an algorithm number of 5 (RSA/SHA-1) and one with an algorithm number of 3 (DSA).[*]

The third field is called the labels field. It indicates how many labels there are in the owner name of the records signed. wormhole.movie.edu obviously has three labels, so the labels field contains 3. When would the labels field ever differ from the number of labels in the RRSIG’s owner? When the RRSIG record covered a wildcard record of some type. We won’t cover the nuances of wildcards in signed zones in this book.

The fourth field is the original TTL on the records in the RRset that was signed. (All the records in an RRset are supposed to have the same TTL.) The TTL needs to be stored here because a nameserver caching the RRset that this RRSIG record covers will decrement the TTLs on the cached records. Without the original TTL, it’s impossible to reconstruct the original address records to feed them through the one-way hash function to verify the digital signature.

The next two fields are the signature expiration and inception fields, respectively. They’re both stored as an unsigned integer number of seconds since the Unix epoch, January 1, 1970, but in the RRSIG record’s text representation, they’re presented in the format YYYYMMDDHHMMSS for convenience. (The signature expiration time for the RRSIG record we showed you earlier is just after 11:36 p.m. on February 19, 2006.) The signature inception time is usually the time you ran the program to sign your zone. You choose the signature expiration time when you run that program, too. After the signature’s expiration, the RRSIG record is no longer valid and can’t be used to verify the RRset. Bummer. This means you have to re-sign your zone data periodically to keep the signatures valid. Fun. Thankfully, re-signing takes much less work than signing it for the first time.

The next (seventh) field in the RRSIG record, which in this record contains 3674, is the key tag field. The key tag is a fingerprint derived from the public key that corresponds to the private key that signed the zone. If the zone has more than one public key (and yours probably will), DNSSEC verification software uses the key tag to determine which key to use to verify this signature.

The eighth field, which contains movie.edu, is the signer’s name field. As you’d expect, it’s the domain name of the public key that a verifier should use to check the signature. It, together with the key tag, identifies the DNSKEY record to use. The signer’s name field is always the domain name of the zone the signed records are in.

The final field is the signature field. This is the digital signature of the zone’s private key on the signed records and the right side of the RRSIG record itself, minus this field. Like the key in the DNSKEY record, this signature is encoded in base 64.

The NSEC Record

DNSSEC introduces another new record type: the NSEC record. We’ll explain what it’s for.

What happens if you look up a domain name that doesn’t exist in a signed zone? If the zone weren’t signed, the nameserver would simply respond with the “no such domain name” response code. But how do you sign a response code? If you signed the whole response message, it would be difficult to cache. You need something unique to sign, something that proves that the domain name you looked up doesn’t exist.

The NSEC record solves the problem of signing negative responses. It spans a gap between two consecutive domain names in a zone, telling you which domain name comes next after a given domain name—hence the name of the record: “Next SECure.”

But doesn’t the notion of “consecutive domain names” imply a canonical order to the domain names in a zone? Why, yes, it does.

To order the domain names in a zone, you begin by sorting by the rightmost label in those domain names, then by the next label to the left, and so on. Labels are sorted case-insensitively and lexicographically (by dictionary order), with numbers coming before letters and nonexistent labels before numbers (in other words, movie.edu would come before 0.movie.edu ). So the domain names in movie.edu sort to the following:

movie.edu
carrie.movie.edu
cujo.movie.edu
fx.movie.edu
bladerunner.fx.movie.edu
outland.fx.movie.edu
horror.movie.edu
localhost.movie.edu
mi.movie.edu
misery.movie.edu
monsters-inc.movie.edu
shining.movie.edu
shrek.movie.edu
toys.movie.edu
toystory.movie.edu
wh.movie.edu
wh249.movie.edu
wh253.movie.edu
wormhole.movie.edu

Notice that just as movie.edu comes before carrie.movie.edu , fx.movie.edu precedes bladerunner.fx.movie.edu .

Once the zone is in canonical order, the NSEC records make sense. Here’s one NSEC record (the first, in fact) from movie.edu:

movie.edu.                     NSEC     carrie.movie.edu. NS SOA MX RRSIG NSEC DNSKEY

This record says that the next domain name in the zone after movie.edu is carrie.movie.edu , which we can see from our sorted list of domain names. It also says that movie.edu has NS records, an SOA record, MX records, RRSIG records, an NSEC record, and a DNSKEY record.

The last NSEC record in a zone is special. Since there’s really no next domain name after the last one, the last NSEC record wraps around to the first record in the zone:

wormhole.movie.edu.            NSEC     movie.edu. A RRSIG NSEC

In other words, to indicate that wormhole.movie.edu is the last domain name in the zone, we say that the next domain name is movie.edu, the first domain name in the zone. Call it circular logic.

So how do NSEC records provide authenticated negative responses? Well, if you look up www.movie.edu internally, you get back the wormhole.movie.edu NSEC record, telling you that there’s no www.movie.edu because there are no domain names in the zone after wormhole.movie.edu . Similarly, if you try to look up TXT records for movie.edu, you get the first NSEC record we showed you, which tells you there are no TXT records for movie.edu, just NS, SOA, MX, RRSIG, NSEC, and DNSKEY records.

An RRSIG record covering the NSEC record accompanies it in the response, authenticating the nonexistence of the domain name or type of data you asked for.

It’s important that the NSEC records, in toto, identify specifically what doesn’t exist in the zone. A single catch-all record that simply says “That doesn’t exist” could be sniffed off the wire and replayed to claim falsely that existing domain names or records don’t actually exist.

For those of you worried about the prospects of adding these new records to your zone and keeping them up to date manually—“Uh-oh, now that I’ve added a host, I’ve got to adjust my NSEC records”—take heart: BIND provides a tool to add NSEC and RRSIG records for you automatically.

Some of you may also worry about the information NSEC records reveal about your zone. A hacker could, for example, look up the NSEC record attached to the domain name of your zone to find the record types attached to that domain name and the lexicographically next domain name, then repeat the process to learn all the domain names and RRsets in the zone. That, unfortunately, is an unavoidable side effect of signing your zone. Just repeat this mantra: “My zone data is secure, but public.”

The DS Record and the Chain of Trust

There’s one more aspect of DNSSEC theory that we should discuss: the chain of trust. (No, this isn’t some touchy-feely team-building exercise.) So far, each RRset in our signed zone has an RRSIG record associated with it. To let others verify those RRSIG records, our zone advertises its public key to the world in a DNSKEY record. But imagine if someone breaks into our primary nameserver. What’s to keep her from generating her own key pair? Then she could modify our zone data, resign our zone with her newly generated private key, and advertise her newly generated public key in a DNSKEY record.

To combat this problem, our public key is “certified” by a higher authority. This higher authority attests to the fact that the movie.edu public key in our DNSKEY record really belongs to the organization that owns and runs the zone, and not to some random yahoo. Before certifying us, this higher authority demanded some sort of proof that we were who we said we were and that we were the duly authorized administrators of movie.edu.

This higher authority is our parent zone, edu. When we generated our key pair and signed our zone, we also sent our public key to the administrators of edu, along with proof of our identity and of our positions as the Two True Administrators of movie.edu.[*] They indicated their approval of our credentials and of our public key by inserting a DS record to the edu zone, then signing the record with their private key. Here are the resulting records:

movie.edu.              86400   DS      15480 5 1 (
                                        F340F3A05DB4D081B6D3D749F300636DCE3D
                                        6C17 )
                        86400   RRSIG   DS 5 2 86400 20060219234934 (
                                        20060120234934 23912 edu.
                                        Nw4xLOhtFoP0cE6ECIC8GgpJKtGWstzk0uH6
                                        nd2cz28/24j4kz1Ahznr/+g5oU3AADyv86EK
                                        CnWZtyOeqnfhMZ3UW0yyPcF3wy73tYLQ/KjN
                                        gPm1VPQA/Sl3smauJsFW7/YPaoQuxcnREPWf
                                        YWInWvWx12IiPKfkVU3F0EbosBA= )

DS stands for delegation signer. The DS record identifies the public key authorized to sign the movie.edu zone’s data. The first field after the type is a key tag, as in the RRSIG record, that helps identify the DNSKEY record authorized to do the signing. The second field is another algorithm field, as in both the DNSKEY and RRSIG records, also used to help identify the relevant DNSKEY record in case we used multiple cryptographic algorithms. The third field is the digest type field, which tells a verifier which digest mechanism to use to verify the digest, the final field. The only currently supported digest type is 1, for an SHA-1 digest. The digest is a 20-byte, hexadecimal-encoded, one-way hash of the movie.edu DNSKEY record.[*]

Accompanying the DS record is an RRSIG record, showing that the administrators of the edu zone signed the movie.edu DS record, thereby vouching for it.

When following a referral from the edu nameservers to the movie.edu servers and verifying the movie.edu DNSKEY record, a nameserver first verifies the RRSIG record covering the DS record. Assuming the RRSIG verified, the nameserver looks up DNSKEY records attached to movie.edu and looks for one matching the key tag and algorithm listed in the DS record. Once the correct DNSKEY record was identified, the nameserver runs the record through the one-way hash algorithm and checks whether the digest matches the digest from the DS record. If it does, the DNSKEY record is authentic, and the nameserver can use it to verify the RRSIG record covering the DNSKEY RRset or other RRsets signed by the corresponding private key.

What if someone breaks into the edu zone’s primary nameserver? The edu zone’s DNSKEY record is certified by a DS record in the root zone, so they can’t simply replace it or any data signed by it. And the root zone? Well, the root zone’s public key is very widely known and configured on every nameserver that supports DNSSEC.[]

That is, the root zone’s public key will be configured on every nameserver once DNSSEC is widely implemented. Right now, neither the root zone nor the edu zone is signed, and neither has a key pair. Until DNSSEC is widely implemented, though, it’s possible to use DNSSEC piecemeal.

Islands of security

Let’s say we want to begin using DNSSEC at Movie U. to improve the security of our zone data. We’ve signed the movie.edu zone but can’t have edu certify our DNSKEY record because they haven’t signed their zone yet and don’t have a key pair. How can other nameservers on the Internet verify our zone data? How can our own nameservers verify our zone data, for that matter?

BIND 9 nameservers provide a mechanism for specifying the public key that corresponds to a particular zone in the named.conf file: the trusted-keys statement. Here’s the trusted-keys statement for movie.edu:

trusted-keys {
    movie.edu. 257 3 5 "AQPWA4BRyjB3eqYNy/oykeGcSXjl+HQK9CciAxJfMcS1vEuwz9c
+QG7s EJnQuH5B9i5o/ja+DVitY3jpXNa12mEn";
};

It’s basically the DNSKEY record without the class and type fields and with the key itself quoted. The domain name of the zone may be quoted, but it’s not necessary. If movie.edu had more than one public key—say a DSA key—we could include it, too:

trusted-keys {
    movie.edu. 257 3 5 "AQPWA4BRyjB3eqYNy/oykeGcSXjl+HQK9CciAxJfMcS1vEuwz9c
+QG7s EJnQuH5B9i5o/ja+DVitY3jpXNa12mEn";
    movie.edu. 257 3 3 "AMnD8GXACuJ5GVnfCJWmRydg2A6JptSm6tjH7QoL81SfBY/kcz1Nbe
    Hh z4l9AT1GG2kAZjGLjH07BZHY+joz6iYMPRCDaPOIt9LO+SRfBNZg62P4 aSPT5zVQPahDIMZmTIvv
    O7FV6IaTV+cQiKQl6noro8uTk4asCADrAHw0 iVjzjaYpoFF5AsB0cJU18fzDiCNBUb0VqE1mKFuRA/K
    1KyxM2vJ3U7IS to0IgACiCfHkYK5r3qFbMvF1GrjyVwfwCC4NcMsqEXIT8IEI/YYIgFt4 Ennh";
};

This trusted-keys statement enables a BIND 9 nameserver to verify any records in the movie.edu zone. The nameserver can also verify any records in child zones such as fx.movie.edu, assuming their DNSKEY records are certified by a DS record and accompanying RRSIG record in movie.edu. In other words, movie.edu becomes a trust anchor, below which our nameserver can verify any signed zone data.

Delegating to unsigned zones

A DS record indicates that a particular delegated subdomain is signed and authorizes a particular DNSKEY record to verify signed data. But what if a subdomain isn’t signed?

Unsigned subdomains won’t have DS records in the parent zone. They also won’t have RRSIG records covering their DS records, of course. The NS records that implement the delegation will have one or more associated NSEC records, though, and the NSEC records will be covered with RRSIG records.

If there are any glue address records, they won’t have NSEC records or RRSIG records because these records really belong to the subdomain.

What happens to name resolution when a nameserver follows delegation from a signed zone to an unsigned zone depends on the security policy of the querying nameserver. The nameserver might accept responses from the unsigned zone or insist that those responses be signed.

DO, AD, and CD

You’ve now seen examples of the four new DNSSEC record types, so you know how long they can be. But the classical limit on the length of a UDP-based DNS message is just 512 bytes. Including all those RRSIGs would cause a lot of truncated responses.

To cope with this, DNSSEC requires support for EDNS0, which we introduced in Chapter 10. EDNS0 allows the use of UDP-based DNS messages as long as 4,096 bytes. DNSSEC also uses a new EDNS0 flag, called the DO flag, for DNSSEC OK, as an indication that a querier supports DNSSEC and wants DNSSEC-related records in the response. Through this use of the DO flag, nameservers don’t needlessly include a bunch of useless records in responses to queriers that don’t support DNSSEC.

DNSSEC uses two other flags in queries: AD and CD. Both are part of the standard DNS query header; they were allocated from previously unused space.[*]

AD stands for Authenticated Data. It’s set by DNSSEC-capable nameservers in responses only if they’ve verified all the DNSSEC-related records included in the message. A nameserver returning any records that failed to verify, or simply weren’t from a signed zone, would clear the AD bit.

The AD bit is designed to allow resolvers that query a nameserver that supports DNSSEC but can’t themselves verify DNSSEC records to determine whether a response has been validated. However, these resolvers should only trust the setting of the AD bit if their communications channel to the nameserver is secure—using IPSEC or TSIG, for example.

The CD bit, on the other hand, is meant for use by resolvers that can verify DNSSEC records. CD, which is an abbreviation for Checking Disabled, tells the nameserver not to bother verifying DNSSEC records on the resolver’s behalf because it can handle the job itself.

How the Records Are Used

Let’s go through what a DNSSEC-capable nameserver does to verify a record in movie.edu. In particular, let’s see what happens when it looks up the address of wormhole.movie.edu . We’ll use dig, since we can’t set the DO bit with nslookup.

First, of course, the nameserver sends a query for the address:

%dig +dnssec +norec wormhole.movie.edu.

; <<>> DiG 9.3.2 <<>> +dnssec +norec wormhole.movie.edu.
; (1 server found)
;; global options:  printcmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 32579
;; flags: qr aa ra; QUERY: 1, ANSWER: 3, AUTHORITY: 4, ADDITIONAL: 3

;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags: do; udp: 4096
;; QUESTION SECTION:
;wormhole.movie.edu.            IN      A

;; ANSWER SECTION:
wormhole.movie.edu.     86400   IN      A       192.253.253.1
wormhole.movie.edu.     86400   IN      A       192.249.249.1
wormhole.movie.edu.     86400   IN      RRSIG   A 5 3 86400
20060219233605 20060120233605 3674 movie.edu. ZZP9AV28r824SZJqyIT+
3WKkMQgcu1YTuFzpLgU3EN4USgpJhLZbYBqT HL77mipET5aJr8OdRxZvfFHHYV6UGw==

;; AUTHORITY SECTION:
movie.edu.              86400   IN      NS      outland.fx.movie.edu.
movie.edu.              86400   IN      NS      wormhole.movie.edu.
movie.edu.              86400   IN      NS      toystory.movie.edu.
movie.edu.              86400   IN      RRSIG   NS 5 2 86400
20060219233605 20060120233605 3674 movie.edu. bwiM/R56VVV0pHrzIERVADLat7BoTR+eeFuCfgYc/
GMXecdTxnUahLig RKsbNSsY+Uz8RVkcewFSiExExFoqwA==

;; ADDITIONAL SECTION:
toystory.movie.edu.     86400   IN      A       192.249.249.3
toystory.movie.edu.   86400   IN      RRSIG   A 5 3 86400 20060219233605
20060120233605 3674 movie.edu. hlz+W41UlcfIaCMdzoKVAuTPjnyqZhxY3TKOOm/
2i7FPAkfnVyWMyTwG iBns7Z1ws6QVj7+ZedDFx7xs+V0Iyw==

;; Query time: 13 msec
;; SERVER: 127.0.0.1#53(127.0.0.1)
;; WHEN: Fri Jan 20 16:52:54 2006
;; MSG SIZE  rcvd: 474

Notice that we had to specify +dnssec on the command line. That sets the DO flag we just described, telling the nameserver to include DNSSEC records in the response. You can see that the DO flag is set in dig’s output: look for the line that begins with ; EDNS:. The flags show that DO was set, and that the maximum UDP message size was negotiated to a full 4,096 bytes.

Also notice that the response includes three RRSIG records: one covering the records in the answer section, one covering the records in the authority section, and one covering toystory.movie.edu ’s address record in the additional section.

To verify the RRSIG records, the nameserver must look up movie.edu’s DNSKEY record. But before using the key, it must verify the key—unless, of course, the nameserver has previously verified it or knows the movie.edu public key from a trusted-keys statement. Verifying the key may require additional queries: one to an edu nameserver for the movie.edu DS record and the RRSIG records covering it, and possibly a query to a root nameserver for the edu DS record and its associated RRSIG records.

DNSSEC and Performance

It should be evident from this dig output that DNSSEC increases the average size of a DNS message; that it requires substantially more computational horsepower from nameservers verifying zone data; that verification can entail several successive queries, each of which may result in additional data that requires verifying; and that signing a zone increases its size substantially—current estimates are that signing multiplies the size of a zone by a factor of three to four. Each effect has its consequences:

  • Verifying zone data involves decryption and consumes computational resources.

  • The longer the chain of trust, the longer verification takes.

  • The longer the chain of trust, the greater the chance of misconfiguration.

  • Larger, signed zones mean larger named processes, which consume more memory and take longer to start.

In fact, DNSSEC’s complexity meant that BIND 8’s architecture couldn’t support DNSSEC completely. DNSSEC also provided part of the impetus for developing BIND 9 and for ensuring it supported multiprocessor hosts. If you’re planning on signing your zones, make sure your authoritative nameservers have enough memory to load the new, larger zones. If your nameservers are resolving more records in signed zones, make sure they have enough processor power to verify all those digital signatures.

Zone-Signing Keys and Key-Signing Keys

In practice, administrators are expected to use two types of keys per zone: zone-signing keys (ZSKs) and key-signing keys (KSKs). An administrator signs his zone data with the zone-signing key (duh) and publishes the corresponding public key in a DNSKEY record. The key-signing key also appears in the DNSKEY records, and the administrator uses the private key-signing key to sign just the DNSKEY records.

The SPE flag in the DNSKEY record serves as a hint to software to determine which of a zone’s DNSKEY records corresponds to the key-signing key (the one with the SEP flag set). When we generate our key pair, we’ll specify which one is the key-signing key.

Why bother with two keys for a zone? Cryptography wonks know that the more data encrypted using a cryptographic key, the greater the danger that someone will crack it. In the case of public-key cryptography, that means determining the corresponding private key. Zone-signing keys are used all the time: every time you modify your zone, you re-sign it. With a large zone, there’s lots of available encrypted data subject to cryptanalysis. Consequently, you must generate new zone-signing keys frequently. If that entails resubmitting your DNSKEY record to your parent zone’s administrators, having them replace your zone’s DS record and re-signing it, that’ll take a lot of time and effort. Using separate zone-signing and key-signing keys allows you to re-sign your zone data without involving your parent zone’s administrators. You’ll only need to contact them if you rotate your key-signing key, which doesn’t need to be done as often because it isn’t used to encrypt much data (just enough to produce an RRSIG for the DNSSEC RRset).

Signing a Zone

Okay, now you have the theoretical background you need to actually sign your zone. We’ll show you how we signed movie.edu. Remember, we used the BIND 9.3.2 tools, which support the newest version of DNSSEC.

Generating your key pairs

First, we generated a KSK key pair for movie.edu:[*]

#cd /var/named
# dnssec-keygen -f KSK -a RSASHA1 -b 512 -n ZONE movie.edu.
Kmovie.edu.+005+15480

Next, we generated a ZSK key pair (we don’t need to specify a -f option because this is the default):

#dnssec-keygen -a RSASHA1 -b 512 -n ZONE movie.edu.
Kmovie.edu.+005+03674

We ran dnssec-keygen in our nameserver’s working directory. That’s mostly for convenience: the zone datafiles are in this directory, so we won’t need to use full pathnames as arguments. If we want to use dynamic update with DNSSEC, however, the keys must be in the nameserver’s working directory.

The -f KSK option sets the SEP flag in the DNSKEY record. To leave the flag clear, omit the option.

Recall dnssec-keygen’s other options from the TSIG section of this chapter (oh, so long ago):

-a

The cryptographic algorithm to use, in this case RSA/SHA-1. We could also have used DSA, but RSA/SHA-1 is mandatory.

-b

The length of the keys to generate, in bits. RSA/SHA-1 keys can be anywhere from 512 to 4,096 bits long. DSA keys can be 512 to 1,024 bits long, as long as the length is divisible by 64.

-n

The type of key. DNSSEC keys are always zone keys.

The only nonoption argument is the domain name of the zone, movie.edu. The dnssec-keygen program prints the basename of the files it’s written the keys to. The numbers at the end of the basename (005 and 15494), as we explained in the “TSIG” section, are the key’s DNSSEC algorithm number as used in the DNSKEY record (005 is RSA/SHA-1), and the key’s fingerprint, used to distinguish one key from another when multiple keys are associated with the same zone.

The public key is written to the file basename.key (e.g., Kmovie.edu.+005+15480.key). The private key is written to the file basename.private (e.g., Kmovie.edu.+005+15480.private). Remember to protect the private key; anyone who knows the private key can forge signed zone data. dnssec-keygen does what it can to help you: it makes the .private file readable and writable only by the user who ran the program.

Signing your zone

Before signing our zone, we had to add the DNSKEY records to our plain-Jane zone datafile:

# echo "$INCLUDE Kmovie.edu.+005+15480.key" >> db.movie.edu
# echo "$INCLUDE Kmovie.edu.+005+03674.key" >> db.movie.edu

Then, we signed the zone with dnssec-signzone:

#dnssec-signzone -o movie.edu. db.movie.edu
db.movie.edu.signed

We used the -o option to specify the origin in the zone datafile, because dnssec-signzone doesn’t read named.conf to determine which zone the file describes. The only nonoption argument is the name of the zone datafile. If the name of our zone datafile had been the same as the domain name of the zone, we could have omitted the -o option.

dnssec-signzone is smart enough to look at the SEP field in the DNSKEY records to determine which key to sign which records with. It’ll sign the whole zone with the ZSK and just the DNSKEY records with both the ZSK and the KSK.

This produces a new zone datafile, db.movie.edu.signed, which begins like this:

; File written on Fri Jan 20 16:36:05 2006
; dnssec_signzone version 9.3.2
movie.edu.              86400   IN SOA  toystory.movie.edu. al.movie.edu. (
                                        2006011700 ; serial
                                        10800      ; refresh (3 hours)
                                        3600       ; retry (1 hour)
                                        604800     ; expire (1 week)
                                        3600       ; minimum (1 hour)
                                        )
                        86400   RRSIG   SOA 5 2 86400 20060219233605 (
                                        20060120233605 3674 movie.edu.
                                        joujDnvBovW1h+GJ2ZEhvmXQTGqVL4cZBCHM
                                        ByFitPRLINe/dKj8VCZg87ZUHQ/eAZSSGDuw
                                        XVIlT46ByG5AOg== )
                        86400   NS      outland.fx.movie.edu.
                        86400   NS      wormhole.movie.edu.
                        86400   NS      toystory.movie.edu.
                        86400   RRSIG   NS 5 2 86400 20060219233605 (
                                        20060120233605 3674 movie.edu.
                                        bwiM/R56VVV0pHrzIERVADLat7BoTR+eeFuC
                                        fgYc/GMXecdTxnUahLigRKsbNSsY+Uz8RVkc
                                        ewFSiExExFoqwA== )
                        86400   MX      10 postmanrings2x.movie.edu.
                        86400   RRSIG   MX 5 2 86400 20060219233605 (
                                        20060120233605 3674 movie.edu.
                                        rm7R0Ib451iK49+bRhch4pIP11F4xZMWtqll
                                        8rQ9tKIOg+jTunNXxix5XnyVKoMQwoa8C5Tu
                                        ZFeDcbHN0UB5ow== )
                        3600    NSEC    misery.movie.edu. NS SOA MX RRSIG NSEC DNSKEY
                        3600    RRSIG   NSEC 5 2 3600 20060219233605 (
                                        20060120233605 3674 movie.edu.
                                        V4ipZI5SHGdFNOVEFn43gsRdYffUH6COrPxn
                                        RNfUMv6gfgwkythXXr5rx0NTOSfa+Dp4CZrC
                                        qwn+CLryUN8vZg== )
                        86400   DNSKEY  256 3 5 (
                                        AQO/T4DRCAbi1diCB+UT4fDOeCvsa+1NKkO8
                                        UJMF5TlfRvokChybhHaDG5U98xw4XgA01/4R
                                        gSlAcSDvhQeKu9n9
                                        ) ; key id = 3674
                        86400   DNSKEY  257 3 5 (
                                        AQPWA4BRyjB3eqYNy/oykeGcSXjl+HQK9Cci
                                        AxJfMcS1vEuwz9c+QG7sEJnQuH5B9i5o/ja+
                                        DVitY3jpXNa12mEn
                                        ) ; key id = 15480
                        86400   RRSIG   DNSKEY 5 2 86400 20060219233605 (
                                        20060120233605 3674 movie.edu.
                                        b35F2azzAY6QDghak0RqJzPacmAhcsw3lDoA
                                        zKCFPQRnqVpwl4l7tAgKw2T1Cy9GPmdHMTBx
                                        fo0DB2smQQJjog== )
                        86400   RRSIG   DNSKEY 5 2 86400 20060219233605 (
                                        20060120233605 15480 movie.edu.
                                        J267HbxKdzGq6iIKywZT6xOFQY7Ev1JWYWEc
                                        PKRyZLY2WQ9S3ro0rIUGJRIhHS5oBtzN1g0K
                                        3DL2edi1Hgy+0A== )

Believe it or not, those are just the records attached to the domain name movie.edu. The zone datafile as a whole more than quintupled in length and quadrupled in size. Oy!

Finally, we turned on DNSSEC support on our nameserver[*] and changed the zone statement in named.conf so that named would load the new zone datafile:

options 
 {
    directory "/var/named";
    dnssec-enable yes;
};

zone "movie.edu" {
    type master;
    file "db.movie.edu.signed";
};

Then we reloaded the zone and checked syslog.

dnssec-signzone does take some options that we didn’t use:

-s, -e

These options specify the signature inception and expiration times to use in RRSIG records. The signature inception and expiration fields default to “now” and “30 days from now,” respectively. Both options accept either an absolute time as an argument, in the form YYYYMMDDHHMMSS, or an offset. For -s, the offset is calculated from the current time. For -e, the offset is calculated from the start time.

-i

Specifies as an option argument the cycle period for resigning records (which we’ll cover in a minute). This was the -c option before BIND 9.1.0.

-f

Specifies as an option argument the name of the file to write the signed zone to. The default is the name of the zone datafile with .signed concatenated.

-k

Specifies the key to be used as the key-signing key. The default is to use any private keys corresponding to DNSKEY records with the SEP flag set.

You can also specify, as a second nonoption argument, which private key to use to sign the zone. By default, dnssec-signzone signs the zone with each of the zone’s private keys in the directory. If you specify the name of one or more files that contain the zone’s private keys as arguments, it will sign using only those keys.

Remember, you’ll need to re-sign the zone each time you change the zone data, though you certainly don’t need to generate a new key pair each time. You can re-sign the zone by running dnssec-signzone on the signed zone data:

#dnssec-signzone -o movie.edu -f db.movie.edu.signed.new db.movie.edu.signed
# mv db.movie.edu.signed db.movie.edu.signed.bak
# mv db.movie.edu.signed.new db.movie.edu.signed
# rndc reload movie.edu

The program is smart enough to recalculate NSEC records, sign new records, and re-sign records whose signature expiration times are approaching. By default, dnssec-signzone resigns records whose signatures expire within 7.5 days (a quarter of the difference between the default signature inception and expiration times). If you specify different inception and expiration times, dnssec-signzone adjusts the re-signing cycle time accordingly. Or you can simply specify a cycle time with the -i (formerly the -c) option.

Sending your keys to be signed

Next, we sent our KSK to the administrator of our parent zone to sign. Conventiently, dnssec-signzone created a keyset file for us when we ran it. This is a small file, called keyset-movie.edu, which contains all of the DNSKEY records in our zone. The contents look like this:

$ORIGIN .
movie.edu               3600    IN DNSKEY 257 3 5 (
                                        AQPWA4BRyjB3eqYNy/oykeGcSXjl+HQK9Cci
                                        AxJfMcS1vEuwz9c+QG7sEJnQuH5B9i5o/ja+
                                        DVitY3jpXNa12mEn
                                        ) ; key id = 15480

dnssec-signzone even creates a DS record for the edu administrators to insert into the edu zone and writes it to the file dsset-movie.edu.[*] The dsset file contains:

movie.edu.              IN DS 15480 5 1 F340F3A05DB4D081B6D3D749F300636DCE3D6C17

Then, we sent our keyset file off to our parent zone’s administrators to sign. Since the message included proof of our identity,[] they added it to the edu zone and re-signed the zone. The resulting records in the edu zone datafile look like this:

movie.edu.              86400   IN NS   outland.fx.movie.edu.
                        86400   IN NS   wormhole.movie.edu.
                        86400   IN NS   toystory.movie.edu.
                        86400   DS      15480 5 1 (
                                        F340F3A05DB4D081B6D3D749F300636DCE3D
                                        6C17 )
                        86400   RRSIG   DS 5 2 86400 20060219234934 (
                                        20060120234934 23912 edu.
                                        Nw4xLOhtFoP0cE6ECIC8GgpJKtGWstzk0uH6
                                        nd2cz28/24j4kz1Ahznr/+g5oU3AADyv86EK
                                        CnWZtyOeqnfhMZ3UW0yyPcF3wy73tYLQ/KjN
                                        gPm1VPQA/Sl3smauJsFW7/YPaoQuxcnREPWf
                                        YWInWvWx12IiPKfkVU3F0EbosBA= )
                        86400   NSEC    edu. NS DS RRSIG NSEC
                        86400   RRSIG   NSEC 5 2 86400 20060219234934 (
                                        20060120234934 23912 edu.
                                        LpOmh/SZMonQUBUil5MYfIrxld5g6pVeyTxl
                                        deDvJ7OIMdI+X0vXmRI3RgmKaRJKYBr4BcNO
                                        jrNU8fQo5Ox5WvEeKn1St1NvdB62/Nqjfz6F
                                        I+LNXe6diq1uDZZUB3hx5PF+Flp28D75KHnZ
                                        5YE9+vVJryOHHsGawklSrUAJAUg= )

Note the RRSIG record covering the DS record. This indicates the edu zone’s certification of our DS record, and thus our KSK’s DNSKEY record.

If we didn’t care about getting our DNSKEY record signed, we could have skipped this step. However, then only nameservers with a trusted-keys entry for movie.edu could verify our data.

Signing a parent zone

Signing a zone that’s a parent to one or more subzones is straightforward. If the subzones aren’t signed, there’s really nothing different to do: run dnssec-signzone to sign the parent zone, just as you normally would. The records that make up delegation to unsigned subzones won’t be changed. For example, here’s what the delegation to the unsigned fx.movie.edu looked like after we signed movie.edu:

fx.movie.edu.           86400   IN NS   alien.fx.movie.edu.
                        86400   IN NS   outland.fx.movie.edu.
                        86400   IN NS   bladerunner.fx.movie.edu.
                        3600    NSEC    misery.movie.edu. NS RRSIG NSEC
                        3600    RRSIG   NSEC 5 3 3600 20060220215231 (
                                        20060121215231 3674 movie.edu.
                                        maFMyIVEdjg5BUTKMUyCZvBu6ZrtrQwJyJRo
                                        9A9PDO3bTpWcpCAp4Q0cQ5FwQcveIq15LMit
                                        CWyOwN745dJ86Q== )
alien.fx.movie.edu.     86400   IN A    192.254.20.3
bladerunner.fx.movie.edu. 86400 IN A    192.253.254.2
outland.fx.movie.edu.   86400   IN A    192.253.254.3

Note the NSEC record attached to fx.movie.edu: the domain name “counts” as far as NSEC records are concerned, but neither the NS records nor the glue A records are signed. Only the NSEC record itself is signed.

If the fx.movie.edu administrators sign their zone, they need to submit only their keyset or dsset file to us (in some sufficiently secure fashion), just as we submitted ours to the edu administrators. If the keyset file is present in the working directory when we sign movie.edu, we can use the -g option to tell dnssec-signzone to create an fx.movie.edu DS record automatically. Otherwise, we can add the DS record from the dsset file manually and re-sign movie.edu. Here’s how the signed delegation ends up looking:

fx.movie.edu.           86400   IN NS   alien.fx.movie.edu.
                        86400   IN NS   outland.fx.movie.edu.
                        86400   IN NS   bladerunner.fx.movie.edu.
                        86400   DS      2847 5 1 (
                                        F495606120C4927FB4BEB04D0C354BBE5ED8
                                        CA31 )
                        86400   RRSIG   DS 5 3 86400 20060220230640 (
                                        20060121230640 3674 movie.edu.
                                        OuZCLrqLZlaEgePAxzhUCneV6FyOq6hQwRWF
                                        4bsHPrvIrLMIuftxfB8M3mmgkKlpOlJIJFvH
                                        Qc4RUfYOGkMkdg== )
                        3600    NSEC    misery.movie.edu. NS DS RRSIG NSEC
                        3600    RRSIG   NSEC 5 3 3600 20060220230640 (
                                        20060121230640 3674 movie.edu.
                                        TUTCnZFvr0YqCD7H0OMTxRs3kAb5OkR74YP3
                                        ZxaBN9S0XxokkeUwHIlWq4JxFJrlZJjMaamp
                                        uKf+WSgdF+v3iA== )

Notice that the NS records still aren’t signed (because technically they belong to the child zone), but the DS record is.

DNSSEC and Dynamic Update

dnssec-signzone isn’t the only way to sign zone data. The BIND 9 nameserver is capable of signing dynamically updated records on the fly.[*] Color us impressed!

As long as the private key for a secure zone is available in the nameserver’s working directory (in the correctly named .private file), a BIND 9 nameserver signs any records that are added via dynamic update. If any records are added to or deleted from the zone, the nameserver adjusts (and re-signs) the neighboring NSEC records, too.

Let’s show you this in action. First, we’ll look up a domain name that doesn’t yet exist in movie.edu:

%dig +dnssec perfectstorm.movie.edu.

; <<>> DiG 9.3.2 <<>> +dnssec perfectstorm.movie.edu.
; (1 server found)
;; global options:  printcmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NXDOMAIN, id: 47491
;; flags: qr aa rd ra; QUERY: 1, ANSWER: 0, AUTHORITY: 6, ADDITIONAL: 1

;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags: do; udp: 4096
;; QUESTION SECTION:
;perfectstorm.movie.edu.                IN      A

;; AUTHORITY SECTION:
movie.edu.              3600    IN      SOA     toystory.movie.edu.
al.movie.edu. 2006011700 10800 3600 604800 3600
movie.edu.              3600    IN      RRSIG   SOA 5 2 86400 20060219233605
20060120233605 3674 movie.edu. joujDnvBovW1h+GJ2ZEhvmXQTGqVL4cZBCHMByFitPRLINe/
dKj8VCZg 87ZUHQ/eAZSSGDuwXVIlT46ByG5AOg==
movie.edu.              3600    IN      NSEC    misery.movie.edu. NS SOA MX
RRSIG NSEC DNSKEY
movie.edu.              3600    IN      RRSIG   NSEC 5 2 3600
20060219233605 20060120233605 3674 movie.edu.
V4ipZI5SHGdFNOVEFn43gsRdYffUH6COrPxnRNfUMv6gfgwkythXXr5r
x0NTOSfa+Dp4CZrCqwn+CLryUN8vZg==
misery.movie.edu.       3600    IN      NSEC    monsters-inc.movie.edu. A RRSIG NSEC
misery.movie.edu.       3600    IN      RRSIG   NSEC 5 3 3600
20060219233605 20060120233605 3674 movie.edu.
AFTF8DBjDtIzM/QkEajY4lUkbuEyDM5yt/Kpe++Jrp1K1kArUSdGPuxj
xDZUXujbRzPY6JoAOgBO4bU8UDx2tA==

;; Query time: 16 msec
;; SERVER: 127.0.0.1#53(127.0.0.1)
;; WHEN: Fri Jan 20 17:02:51 2006
;; MSG SIZE  rcvd: 502

Notice misery.movie.edu’s NSEC record, indicating that the domain name doesn’t exist. Now we’ll use nsupdate to add an address record for perfectstorm.movie.edu:

%nsupdate
> update add perfectstorm.movie.edu. 3600 IN A 192.249.249.91
> send

Now let’s look up perfectstorm.movie.edu again:

%dig +dnssec perfectstorm.movie.edu.

; <<>> DiG 9.3.2 <<>> +dnssec perfectstorm.movie.edu.
; (1 server found)
;; global options:  printcmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 52846
;; flags: qr aa rd ra; QUERY: 1, ANSWER: 3, AUTHORITY: 4, ADDITIONAL: 6

;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags: do; udp: 4096
;; QUESTION SECTION:
;perfectstorm.movie.edu.        IN      A

;; ANSWER SECTION:
perfectstorm.movie.edu. 3600    IN      A       192.249.249.91
perfectstorm.movie.edu. 3600    IN      RRSIG   A 5 3 3600
20060220010558 20060121000558 3674 movie.edu.
Fdp9EwdP6ze2siolli7wtYRgZdts+A+HTt5g8uqsgBavMml3TKFe+ba3
ppXvFosGHD7j3i6r1rfYUBF+aupEnQ==
perfectstorm.movie.edu. 3600    IN      RRSIG   A 5 3 3600 20060220010558
20060121000558 15480 movie.edu.
o46m/V762W90HqZ1R5mCTFSBYagjCqgpuIwflg/06QvX9Ce67WSoHD3/
YjSh5oag5eSmAAn2iozZYVCLSoIzjA==

;; AUTHORITY SECTION:
movie.edu.              86400   IN      NS      outland.fx.movie.edu.
movie.edu.              86400   IN      NS      wormhole.movie.edu.
movie.edu.              86400   IN      NS      toystory.movie.edu.
movie.edu.              86400   IN      RRSIG   NS 5 2 86400
20060219233605 20060120233605 3674 movie.edu.
bwiM/R56VVV0pHrzIERVADLat7BoTR+eeFuCfgYc/GMXecdTxnUahLig RKsbNSsY+Uz8RVkcewFSiExExFoqwA==

;; ADDITIONAL SECTION:
wormhole.movie.edu.     86400   IN      A       192.253.253.1
wormhole.movie.edu.     86400   IN      A       192.249.249.1
toystory.movie.edu.     86400   IN      A       192.249.249.3
wormhole.movie.edu.     86400   IN      RRSIG   A 5 3 86400 20060219233605
20060120233605 3674 movie.edu. ZZP9AV28r824SZJqyIT+
3WKkMQgcu1YTuFzpLgU3EN4USgpJhLZbYBqT HL77mipET5aJr8OdRxZvfFHHYV6UGw==
toystory.movie.edu.   86400     IN      RRSIG   A 5 3 86400 20060219233605
20060120233605 3674 movie.edu. hlz+W41UlcfIaCMdzoKVAuTPjnyqZhxY3TKOOm/
2i7FPAkfnVyWMyTwG iBns7Z1ws6QVj7+ZedDFx7xs+V0Iyw==

;; Query time: 18 msec
;; SERVER: 127.0.0.1#53(127.0.0.1)
;; WHEN: Fri Jan 20 17:06:22 2006
;; MSG SIZE  rcvd: 713

Not only was an address record added, but there is also an RRSIG record generated from movie.edu’s ZSK.[*] The signature expiration is set to 30 days from the update by default, but you can change it with the sig-validity-interval substatement, which takes a number of days as an argument:[]

options {
    sig-validity-interval 7;  // We want RRSIGs on updated records to last a week
};

The signature inception is always set to one hour before the update to allow for verifiers with clocks that may be slightly skewed from ours.

If we look up perfectstorm2.movie.edu (though how there’d be a sequel to that movie I don’t know), we find the following:

%dig +dnssec perfectstorm2.movie.edu.

; <<>> DiG 9.3.2 <<>> +dnssec perfectstorm2.movie.edu.
; (1 server found)
;; global options:  printcmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NXDOMAIN, id: 8402
;; flags: qr aa rd ra; QUERY: 1, ANSWER: 0, AUTHORITY: 8, ADDITIONAL: 1

;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags: do; udp: 4096
;; QUESTION SECTION:
;perfectstorm2.movie.edu.       IN      A

;; AUTHORITY SECTION:
movie.edu.              3600    IN      SOA     toystory.movie.edu.
al.movie.edu. 2006011701 10800 3600 604800 3600
movie.edu.              3600    IN      RRSIG   SOA 5 2 86400 20060220010558
20060121000558 3674 movie.edu. vwiC+
zBzw8VFmrmFnARkNPLLmYEbSJRCiCsqjnvwVc5CMSzXu6kBkatN bWE9Iqd//brLiOA3E9G02BM3j+5Wkg==
movie.edu.              3600    IN      RRSIG   SOA 5 2 86400 20060220010558
20060121000558 15480 movie.edu. HVlniwE8N8Fy+IdRSmTLw3XTVyLae0eOr26C5MAkzNoMr3OzRrDfbZUm
4+N1a6gC9P+EMzUYM1yflVQFs3Cehg==
movie.edu.              3600    IN      NSEC    misery.movie.edu. NS SOA
MX RRSIG NSEC DNSKEY
movie.edu.              3600    IN      RRSIG   NSEC 5 2 3600
20060219233605 20060120233605 3674 movie.edu.
V4ipZI5SHGdFNOVEFn43gsRdYffUH6COrPxnRNfUMv6gfgwkythXXr5r
x0NTOSfa+Dp4CZrCqwn+CLryUN8vZg==
perfectstorm.movie.edu. 3600    IN      NSEC    shining.movie.edu. A RRSIG NSEC
perfectstorm.movie.edu. 3600    IN      RRSIG   NSEC 5 3 3600
20060220010558 20060121000558 3674 movie.edu. EC/HwFtyrDtcf27QYvnSrJTypnAg3LsimFH+
lTO/VbB/dD7Wzj0am1Yy+/SF3u6nrJ1nV2hZBgSqmYB9plpM3Q==
perfectstorm.movie.edu. 3600    IN      RRSIG   NSEC 5 3 3600 20060220010558 200601210
00558 15480 movie.edu. H2XwAMRYkxsv721q0fOQk7g7j1SPPurKNGBDqlEDpeLnRkde8NHtlFOx
VbqWDsWzq15sxoV4NRZyK14cQcbG7Q==

;; Query time: 14 msec
;; SERVER: 127.0.0.1#53(127.0.0.1)
;; WHEN: Fri Jan 20 17:15:58 2006
;; MSG SIZE  rcvd: 726

Notice the second NSEC record: it was added automatically when we added perfectstorm.movie.edu’s address record because perfectstorm.movie.edu was a new domain name in the zone. Sweet!

As impressive as this is, you should be careful when allowing dynamic updates to signed zones. You should make sure that you use strong authentication (e.g., TSIG) to authenticate the updates, or you’ll give a hacker an easy backdoor to use to modify your “secure” zone. And you should ensure you have enough horsepower for the task: normally, dynamic updates don’t take much to process. But dynamic updates to a secure zone require the recalculation of NSEC records and, more significantly, asymmetric encryption (to calculate new RRSIG records), so you should expect your nameserver to take longer and need more resources to process them.

Changing Keys

Though we said you don’t need to generate a new key each time you sign your zone, there are occasions when you’ll need to create a new key, either because you’ve “used up” a private key or, worse, because one of your private keys has been cracked.

After a certain amount of use, it becomes dangerous to continue signing records with a private key. While there’s no simple rule to tell you when a private key’s time is up, here are some guidelines:

  • The longer your key, the harder it is to crack. Long keys don’t need to be changed as often as short keys.

  • The more valuable it would be for a hacker to spoof your zone data, the more time and money he will spend trying to crack one of your private keys. If the integrity of your zone data is particularly crucial, change keys frequently.

Since movie.edu isn’t a high-value target, we change our zone-signing key pair every six months. We’re only a university, after all. If we were more concerned about our zone data, we would use longer keys or change keys more frequently.

Unfortunately, rolling over to a new key isn’t as easy as just generating a new key and replacing the old one with it. If you did that, you’d leave nameservers that had cached your zone’s data with no way to retrieve your zone-signing DNSKEY record and verify that data. So rolling over to a new key is a multistep process:

  1. At least one TTL before the set of RRSIG records signed with your old ZSK expire, generate a new ZSK pair.

  2. Add the new DNSKEY record to your zone data.

  3. Sign your zone data with the new private key and without the old private key, but leave the old DNSKEY record in the zone.

  4. After all records signed with the old private key have expired, remove the old DNSKEY record from the zone and re-sign it with the new private key.

Let’s go through the process. First, we generated a new key pair:

#dnssec-keygen -a RSA -b 512 -n ZONE movie.edu.
Kmovie.edu.+005+15494

Next, we added the new DNSKEY record to the zone data:

#cat Kmovie.edu.+005+15494.key >> db.movie.edu.signed

We had to tell dnssec-signzone the keys to sign to zone with, and specify the KSK:

#dnssec-signzone -o movie.edu -k Kmovie.edu.+005+15480 db.movie.edu.signed
Kmovie.edu.+005.15494

This will sign the zone with the new ZSK and leave the set of RRSIG records signed with the old ZSK in the zone, but won’t regenerate RRSIGs with the old ZSK. Here’s how the resulting file began:

; File written on Tue Feb 21 02:41:09 2006
; dnssec_signzone version 9.3.2
movie.edu.              86400   IN SOA  toystory.movie.edu. al.movie.edu. (
                                        2006022100 ; serial
                                        10800      ; refresh (3 hours)
                                        3600       ; retry (1 hour)
                                        604800     ; expire (1 week)
                                        3600       ; minimum (1 hour)
                                        )
                        86400   RRSIG   SOA 5 2 86400 20060220210704 (
                                        20060121210704 3674 movie.edu.
                                        otYTiIHqJ4K0c6M5JZ9uC8q7AvXO1Gjp5FXJ
                                        5SRO+UL/ilAZXGSfJSCJrUDetb7R0H27NqHe
                                        yKujxcec69FoLw== )
                        86400   RRSIG   SOA 5 2 86400 20060320094111 (
                                        20060221094111 15494 movie.edu.
                                        zD/IGbzgO3sB5sPvYbb3vLmvULRQ05fV21Yz
                                        DO8gq2E+v575ag469h+J2Dzs6XheMxShmIpk
                                        YwjYxgMLcc1SjA== )

Although the zone includes two DNSKEY records, the other records in the zone (such as the SOA record, shown here) were signed only by the new private key, with key tag 15494. The old RRSIG records, generated from the private key with key tag 3674, were still included because they were still valid—but not for much longer. Note the expirations of the two RRSIG records covering the SOA record: key tag 3674’s RRSIG record expires a month earlier because it wasn’t regenerated.

After the old RRSIG records expired, we deleted the old DNSKEY record and the key files (so the signer wouldn’t use them) and re-signed the zone with just the new ZSK and the KSK:

#dnssec-signzone -o movie.edu db.movie.edu.signed
# mv db.movie.edu.signed.signed db.movie.edu.signed

That removed the old, invalid RRSIGs and re-signed the DNSKEY RRset with the KSK.

Changing KSKs is similar, and doesn’t need to be done as often:

  1. At least one TTL before its RRSIG covering the DNSKEY RRset expires, generate a new KSK pair.

  2. Add the new KSK’s DNSKEY record to the zone.

  3. Re-sign the DNSKEY RRset with both KSKs (specifying multiple -k options to dnssec-signzone).

  4. Submit your new KSK to your parent zone’s administrators to certify.

  5. After the TTL of the DS RRset in your parent zone has passed, you can remove the old KSK from your zone and re-sign the zone without it.

We’re guessing that after reading this, you’ll probably decide to use the longest keys available just to avoid ever needing to roll your keys over.

What Was That All About?

We realize that DNSSEC is a bit, er, daunting. (We nearly fainted the first time we saw it.) But it’s designed to do something very important: make DNS spoofing much, much harder. And as people do more and more business over the Internet, knowing you’re really getting where you thought you were going becomes crucial.

That said, we realize that DNSSEC and the other security measures we’ve described in this chapter aren’t for all of you. (Certainly they’re not all for all of you.) You should balance your need for security against the cost of implementing it, in terms of the burden it places both on your infrastructure and on your productivity.



[*] Cryptography wonks may argue that TSIG “signatures” aren’t really signatures in a cryptographic sense because they don’t provide nonrepudiation. Since either holder of the shared key can create a signed message, the recipient of a signed message can’t claim that only the sender could have sent it (the recipient could have forged it himself).

[*] See the Network Time Protocol web site at http://www.ntp.org/ for information on NTP.

[*] We described how to subscribe to bind-users back in Chapter 3. To subscribe to bind-announce, the instructions are the same.

[*] In fact, you can even use an allow-query substatement with a stub zone.

[*] This procedure is based on FreeBSD, so if you use a different operating system, your mileage may vary.

[] The arguments to mknod needed to create dev/null will vary depending on the operating system.

[*] This particular variation of conditional forwarding, however, didn’t work in BIND 9 until 9.2.0 because of a bug.

[*] In particular, BIND 8 can’t follow a chain of trust. It can verify SIG records only in zones it has trusted-keys statements for.

[*] You might sign your zone with two different algorithms’ keys so that people whose software preferred DSA could verify your data while people who supported only RSA/SHA-1 could use RSA/SHA-1.

[*] In fact, only the Swedish top-level zone, se, currently signs its zone and can sign DNSKEY records.

[*] Our sources tell us (OK, one of our technical reviewers, but didn’t “sources” sound cool?) that an upcoming version of BIND will move to SHA-256 to address weaknesses in SHA-1.

[] 12. This reminds us of the tale of the man who asks the priest what holds the Earth up. The priest tells him that the Earth rests on the back of a turtle, which holds it up. The man then asks what the turtle rests on. “On the back of an elephant,” replies the priest. “But what,” the man asks, “does the elephant rest on?” The frustrated priest snaps back, “It’s elephants all the way down!”

[*] Previously unused but precious: there were only three unused bits in the header; AD and CD use two of them.

[*] We’re using relatively short key lengths in these examples to keep the DNSKEY and RRSIG records short. You should use longer keys, at least 1,024 bits.

[*] This assumes our nameserver was compiled with the -with-openssl=yes option. If not, we’d need to rerun configure with that option (see Appendix C) and recompile.

[*] At this point, it’s unclear whether the administrator of a signed zone should submit a keyset file or a dsset file to his parent zone’s administrator. Either will do: the parent zone’s administrator can generate a DS record from a DNSKEY record. For now, we’ll guess that we’d submit a keyset file.

[] Since top-level zones haven’t started signing zones yet, there’s still some question as to how they’ll require us to authenticate ourselves. The use of cryptographically signed email messages is a possibility.

[*] Yet another DNSSEC capability BIND 8 doesn’t have.

[*] As well as one from the KSK. That’s a bug.

[] Before BIND 9.1.0, sig-validity-interval interpreted its argument as seconds, not days.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset