NSD and Unbound install + configure – Part II

In my quest to get DNSSEC set up for my DNS infrastructure I have a series of tasks that need to be completed:

1. Upgrade my secondary DNS server (quasar) to OpenBSD 4.8 – done
2. Upgrade my stealth secondary (cake) to OpenBSD 4.8 – done
3. Install NSD + Unbound on both – done
4. Configure NSD + Unbound on both – done
5. Set up TSIG to secure zone transfers between all of my DNS servers – done
6. Set up DNSSEC on my primary DNS (pulsar) for my main zone
7. Reap the benefits, including SSHFP records etc.

This post covers the second half of OpenBSD setup, with a quick review of the different configuration needed for a stealth resolver.

Overview

See the previous post on this subject for more.

This mostly covers the configuration for cake, which is my home router/firewall. This machine runs OpenBSD and also serves as DNS server for my home network. Here as on Quasar I’ll be running both NSD and Unbound, but with a slightly different setup.

Cake has two network interfaces (three if you count localhost), one faces internally and binds to the internal subnets (a block in the 172.16.0.0/12 RFC1918 range for NAT clients, and a /28 block of globally routeable IPs as well as a /64 IPv6 allocation) the other binds to Internet-facing addresses (v4 and v6).

Unbound will listen on localhost:53 and internal:53, it will query NSD for some zones on localhost:5353.

NSD will listen on localhost:5353 and external:5353, it will receive queries from Unbound on localhost:5353 and receive zone updates/transfers from Quasar and Pulsar on external:5353.

Installation

This was identical to installation on Quasar, see the previous post.

Unbound configuration

Unbound on Quasar is used only by the local server to provide recursive DNS services to that single host. Cake provides similar services to an entire LAN. Other than this small difference the configuration is fairly similar.

server:
# Allow access from all internal interfaces
access-control: ::1 allow
access-control: 127.0.0.1/8 allow
access-control: 81.187.132.48/28 allow
access-control: 2001:8b0:ffe4:1::/64 allow
access-control: 172.25.25.0/24 allow
access-control: 192.168.1.0/24 allow
verbosity: 1
auto-trust-anchor-file: "/var/unbound/etc/root.key"
# Listen on all internal interfaces
interface: ::1
interface: 127.0.0.1
interface: 2001:8b0:ffe4:1::1
interface: 81.187.132.49
interface: 192.168.1.254
interface: 172.25.25.254
do-not-query-localhost: no

remote-control:
control-enable: yes
control-port: 853

stub-zone:
name: "entropy.me.uk"
stub-addr: ::1@5353
stub-addr: 127.0.0.1@5353

# Include stub-zone entries for reverse DNS
include: "/var/unbound/etc/unbound.conf.XXX.132.187.81.in-addr.arpa"

stub-zone:
name: "161.94.187.81.in-addr.arpa"
stub-addr: ::1@5353
stub-addr: 127.0.0.1@5353

stub-zone:
name: "4.e.f.f.0.b.8.0.1.0.0.2.ip6.arpa"
stub-addr: ::1@5353
stub-addr: 127.0.0.1@5353

The access-control lines specify the subnets which can access the recursive resolver (including the NAT subnet we allow guests to use). The interface lines similarly instruct Unbound to only listen on the internal IP addresses. There’s no need for Unbound to listen on the Internet-facing addresses (that’s what NSD is for afterall).

The do-not-query-localhost line is quite important. Without it none of the stub-zone lines work properly. This is because the default is set to prevent Unbound from querying other DNS servers running on localhost. It’ll need to do this in this setup (NSD will be running on port 5353 on localhost).

The stub-zone lines point to NSD running on the same machine to provide authoritative answers for queries about those zones. This is important for the occasions where our Internet connection fails, since I use these zones for infrastructure purposes there needs to be a local authoritative server for them to ensure that they will always be resolveable by local clients.

The “include:” directive simply points to another file containing more stub-zones. This file is automatically generated by a little python script (and contains stub-zone declarations for the 16 in-addr.arpa zones for each of the reverse-dns entries for each IP address in our /28 block. Thank goodness for IPv6 and its ability to delegate every byte!

For everything else in this config see the previous article, it’s identical.

NSD configuration

This is mostly identical to the configuration on Quasar, the main differences are the interfaces and port it listens on and the servers listed as permitting notify/transfers.

# options for the nsd server
server:
# uncomment to specify specific interfaces to bind (default all).
ip-address: ::1
ip-address: 127.0.0.1
ip-address: 2001:8b0:ffe4::1
ip-address: 81.187.94.161

port: 5353

# TSIG key for our DNS zones
key:
name: tsig.entropy.me.uk.
algorithm: hmac-sha1
secret: "aaaabbbbccccddddeeeeffff"

# Slave zones (forward)
zone:
name: "entropy.me.uk"
zonefile: "entropy.me.uk.zone"
allow-notify: 2001:470:1f09:398::1 tsig.entropy.me.uk.
allow-notify: 82.113.152.83 tsig.entropy.me.uk.
request-xfr: 2001:470:1f09:398::1 tsig.entropy.me.uk.
request-xfr: 82.113.152.83 tsig.entropy.me.uk.
allow-notify: 2607:f2f8:680::2 tsig.entropy.me.uk.
allow-notify: 206.125.174.170 tsig.entropy.me.uk.
request-xfr: 2607:f2f8:680::2 tsig.entropy.me.uk.
request-xfr: 206.125.174.170 tsig.entropy.me.uk.


The “ip-address:” directives instruct NSD to listen only on localhost and the external interface. The “port:” directive instructs it to listen on port 5353 (to avoid conflicting with Unbound on localhost).

TSIG key is the same config as described in the previous article.

For each zone two Masters are listed, pulsar and quasar. Again, other than there being two of them this is identical to the previous article.

Additional configuration for Quasar

In order to support this new configuration the config on Quasar needed to change slightly from that described before. This just involved adding directives to instruct it to notify the stealth resolver at home of zone changes, and to provide transfer to it when requested. E.g. the new configuration entry for entropy.me.uk is:

zone:
name: "entropy.me.uk"
zonefile: "entropy.me.uk.zone.signed"
allow-notify: 2001:470:1f09:398::1 tsig.entropy.me.uk.
allow-notify: 82.113.152.83 tsig.entropy.me.uk.
request-xfr: 2001:470:1f09:398::1 tsig.entropy.me.uk.
request-xfr: 82.113.152.83 tsig.entropy.me.uk.
notify: 2001:8b0:ffe4::1@5353 tsig.entropy.me.uk.
notify: 81.187.94.161@5353 tsig.entropy.me.uk.
provide-xfr: 2001:8b0:ffe4::1@5353 tsig.entropy.me.uk.
provide-xfr: 81.187.94.161@5353 tsig.entropy.me.uk.

Conclusion

This stage of configuration gives me a DNSSEC-enabled DNS server for my local LAN. Both of my secondary authoritative DNS servers are now ready for me to sign entropy.me.uk which will be the next step. I’ve also gained immediately from the security afforded by running a DNSSEC-enabled resolver for my network.

Advertisements

NSD and Unbound install + configure, and TSIG config

In my quest to get DNSSEC set up for my DNS infrastructure I have a series of tasks that need to be completed:

1. Upgrade my secondary DNS server (quasar) to OpenBSD 4.8 – done
2. Upgrade my stealth secondary (cake) to OpenBSD 4.8
3. Install NSD + Unbound on both – done on quasar
4. Configure NSD + Unbound on both – done on quasar
5. Set up TSIG to secure zone transfers between all of my DNS servers – done
6. Set up DNSSEC on my primary DNS (pulsar) for my main zone
7. Reap the benefits, including SSHFP records etc.

This post covers the NSD/Unbound install and configuration as well as TSIG configuration for both NSD and BIND9.

Overview

Quasar is my secondary DNS server. It mirrors the zones served by my primary (pulsar), they are also known as ns1.entropy.me.uk and ns2.entropy.me.uk.

Cake is my home network router, it also runs DNS – providing a recursive service for my local network as well as mirroring the entropy.me.uk zone to ensure that this is always available even when our DSL line is down. This is a stealth resolver (meaning it doesn’t have an NS record in the entropy.me.uk zone and thus doesn’t serve as an Authoritative server on the wider Internet).

On quasar I will be using Unbound running on localhost for recursion and NSD running on the external interface for the authoritative function to the wider Internet. On cake I’ll be using Unbound on the local network and localhost interfaces to provide recursive DNS to my home network as well as NSD on the external interface and localhost interface to provide an authoritative stub resolver for my home network in times when the connection to the Internet is down.

NSD & Unbound installation on OpenBSD

This is fairly simple to do. Ensure your PKG_PATH environment variable is set correctly then do:

pkg_add nsd
pkg_add unbound

This will install both packages. For OpenBSD 4.8 the versions are 1.4.5 for Unbound and 3.2.5 for NSD. OpenBSD 4.9 will bump these revisions but the same principle applies.

NSD has its configuration under /etc/nsd/ and Unbound has its under /var/unbound/etc/. Unbound is configured to chroot by default on OpenBSD (NSD isn’t, but it has this capability and I’ll be setting it up that way in a later post).

To have NSD/Unbound automatically start up add these lines to your /etc/rc.local:

if [ -x /usr/local/sbin/unbound ]; then
echo -n ' unbound'; /usr/local/sbin/unbound
fi

if [ -x /usr/local/sbin/nsd ]; then
echo -n ' nsd'; /usr/local/sbin/nsd
fi

Unbound configuration

Unbound is primarily a recursive resolver (and while it does have limited ability to act as an authoritative DNS server this really isn’t what it is suited to). Thus the bulk of this configuration relates to its use in this capacity. The configuration is thus very simple.

server:
access-control: ::1 allow
access-control: 127.0.0.1/8 allow
verbosity: 1
auto-trust-anchor-file: "/var/unbound/etc/root.key"

remote-control:
control-enable: yes
control-port: 853

stub-zone:
name: "entropy.me.uk"
stub-addr: 2607:f2f8:680::2
stub-addr: 206.125.174.170

The server section sets up the server’s behaviour. Here I have specified access controls to permit queries only on the localhost interfaces. These also control the interfaces that Unbound will listen on. Since quasar isn’t providing recursive DNS functionality for anything except itself these settings are fine. When I do the configuration for cake (which is my home network router) the configuration will be quite different since it’ll need to provide recursion for a whole network of machines.

The auto-trust-anchor-file entry provides the name of a file where a copy of the root anchor can be found. This is always available online from the IANA website. This is the root of all trust in DNSSEC. This key will be automatically kept up-to-date by Unbound after it has been initialised. Unbound usually comes with a utility called unbound-anchor which can be used to retrieve this securely however for some reason this isn’t included in the OpenBSD distribution. The format of the file is (initially) a standard DS record containing the root anchor key, e.g. at the time of writing this would be:

. IN DS 19036 8 2 49AAC11D7B6F64---------------------------------CE1CDDE32F24E8FB5

This may well change however and you *really* shouldn’t take my word for it! Either use the unbound-anchor utility or verify this key by visiting the IANA website linked above yourself. This is the root of all your trust in the entire DNSSEC system so you want to be pretty sure it’s correct! (I have overwritten the middle bit to ensure that you go away and verify it yourself).

The remote-control section configures the unbound-control program. This is a bit like rndc in the BIND world in that it lets you control the server. It’ll only listen on localhost by default. Before using it you need to run unbound-control-setup to generate the public/private keypair it uses for authentication. For more details on unbound-control including a list of the available commands see the Unbound website.

Finally the stub-zone entry tells Unbound about the Authoritative server running locally for my domain. This isn’t really needed but will help to ensure that quasar always talks to its local Authoritative nameserver (the NSD one we’ll configure in a moment) for lookups relating to the domain that it is in. Given that NSD will be running only on the externally-facing interface of the machine these are the IP addresses that must be configured for the stub-zone to work. For Unbound a stub-zone is one which should be considered authoritative but you can also have forward-zone(s) which are similar but considered recursive. Your ISP’s recursive DNS servers should be added as forward-zone(s) for example.

There are a great many other options for Unbound but they have sensible defaults. For a complete listing see the Unbound website. OpenBSD’s man pages are typically excellent for Unbound as well.

Unbound can be started by running “unbound-control start”. You’ll need to configure your system to use it by adding:

nameserver ::1

To your /etc/resolv.conf

NSD configuration

NSD operates only as an authoritative DNS server in either primary (master) or secondary (slave) roles. I’m going to be running this server only with slave zones pulled from my primary DNS server running BIND9.

server:
# uncomment to specify specific interfaces to bind (default all).
ip-address: 206.125.174.170
ip-address: 2607:f2f8:680::2

# TSIG key for our DNS zones
key:
name: tsig.entropy.me.uk.
algorithm: hmac-sha1
secret: "aaaabbbbccccddddeeeeffff"

# Slave zones (forward)
zone:
name: "entropy.me.uk"
zonefile: "entropy.me.uk.zone.signed"
allow-notify: 2001:470:1f09:398::1 tsig.entropy.me.uk.
request-xfr: 2001:470:1f09:398::1 tsig.entropy.me.uk.
allow-notify: 82.113.152.83 tsig.entropy.me.uk.
request-xfr: 82.113.152.83 tsig.entropy.me.uk.

Again, fairly simple configuration for the most part. The ip-address: options under the server: section define the interfaces to bind to (external IPs of this machine). The key: section defines the TSIG key to be used for zone transfers from the primary (more on this later). The zone: section(s) simply define the zone in terms of name, file to store the zone in and the servers which act as primaries. The allow-notify lines specify servers from which notifications of changes to zone files should be accepted. The request-xfr lines specify servers we should periodically request transfers from. For both of these a TSIG key (defined in a key: section) can be specified (or NOKEY if you don’t want to use them).

NSD comes with a control program as well, nsdc. This works just like rndc is used to manage BIND9. More information on nsd.conf can be found on the OpenBSD man pages. Similarly see this man page for information on nsdc.

TSIG configuration (on BIND9)

The TSIG configuration for NSD is detailed above, it’s quite simple in that you just need to define a key using a key: section (specifying the name, algorithm and secret) and then use the name to refer to it later. BIND is a little more involved.

There’s a pretty good guide to the process on this website. The basic configuration looks like this:

key "tsig.entropy.me.uk." {
algorithm hmac-sha1;
secret "aaaabbbbccccddddeeeeffff";
};

# Quasar slave configuration
server 206.125.174.170 {
keys {
"tsig.entropy.me.uk.";
};
};
server 2607:f2f8:680::2 {
keys {
"tsig.entropy.me.uk.";
};
};

This goes into a file called tsig.key which is then included into the BIND configuration. The key can then be referred to by the same name to specify which clients can request zone transfers, e.g.:

zone "entropy.me.uk" {
type master;
file "/etc/bind/db.entropy.me.uk";
allow-transfer { key "tsig.entropy.me.uk."; };
notify yes;
};

The key itself is generated using the command line:

dnssec-keygen -a HMAC-SHA1 -b 160 -n HOST mykey

This produces two files, a .key and .private file. They both contain the same hash however which is the part you need. The output file will be called something like Kmykey.+161+44444.key. Copy the long hash (last value on the line) and replace the “aaaabbbbccccddddeeeeffff” in the config snippet above. Keep this secret a secret of course!

Finally reload your BIND configuration. You should see the zone transfers succeeding in the daemon log file. E.g.:

client 206.125.174.170#34197: transfer of 'entropy.me.uk/IN': AXFR-style IXFR started: TSIG tsig.entropy.me.uk
client 206.125.174.170#34197: transfer of 'simutrans.com/IN': AXFR-style IXFR ended

If you see messages saying things like:

bad zone transfer request: 'somedomain.com/IN': non-authoritative zone (NOTAUTH)

Then it’s likely your primary server isn’t configured to be authoritative for the zone your secondary server is trying to transfer. It can also sometimes indicate that you have either a TSIG name mismatch (they must be identical on both systems) or a TSIG hash mismatch. Similarly if you see “zone transfer denied” type messages check the shared secret is consistent across both machines.

Conclusion

I’m now a step closer to DNSSEC deployment. quasar can recursively verify DNSSEC secured DNS records and with NSD installed it’ll be able to serve them as well as soon as they are signed on the primary. Deploying TSIG also adds another layer of security to prevent anyone from tampering with the records while they are being transferred between primary and secondary (or indeed being able to initiate a zone transfer without knowing the secret).