-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA256

Use Bind inline signing and auto maintain features

For those that don’t know it, I do work for an internet registrar. They currently plan to provide their customers the possibility to benefit from DNSSEC features. So, I was asked to test the whole thing and I decided to go for the latest features that Bind provides : inline signing and auto maintain.

Foreword

Well, I do really need to warn you, I am new with DNSSEC concepts and do not own the capabilities and the knowledge needed to explain you what DNSSEC is and how it works in details. Therefore, if you see that what I say is non-sensed, please don’t hesitate to use the comments section below to scream after me.

Purpose and setup

What I really was asked to, is to sign a zone, upload the DS records to the registry, verify that the signature is valid and then initiate a key rollover to see what happens. I therefore planned to create a hidden zone signing master server and use the three authoritative nameservers that I currently run for another project and use them to respond to DNSSEC queries.

Targeted infrastructure

Bind DNS daily statistics

Hidden master

Using inline signing requires that you run a version of bind higher than 9.9 (the stable version at time of writing is 9.9.2-P1), which I happily can provide you for CentOS 6. So, quickly done, let’s make run our authoritative server serve our demonstration zone (africadns.de)

# Install the repository for my bind RPMs
cat > /etc/yum.repos.d/bkraft.repo << EOF
[bkraft]
name=bkraft - $basearch
baseurl=http://bkraft.fr/files/RPM%20stuff/
failovermethod=priority
enabled=1
gpgcheck=1
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-benjaminkraft
EOF

# Download my key
curl http://bkraft.fr/files/RPM%20stuff/RPM-GPG-KEY-benjaminkraft > /etc/pki/rpm-gpg/RPM-GPG-KEY-benjaminkraft

# Proceed with opening iptables tcp/udp 53

# And install the latest bind version
yum install -y bind bind-utils

# Create the directory where we'll store the zone keys later on
mkdir /var/named/keys
chown named:named /var/named/keys

Now I’ll create the zone that I want to serve, and first it will be unsigned. You can note that the SOA record that I specify is one of the public authoritative servers, and that the NS records contain all three servers. This is how you build a hidden master server.

# Create a simple zone

cat >> /var/named/data/africadns.de.zone << EOF
; zone file for africadns.de
$ORIGIN africadns.de.
$TTL 3600
@    86400    IN SOA apollo.dotnul.org. benj.dotnul.com. (
          2013012930 ; serial
          86400 ; refresh
          7200 ; retry
          604800 ; expire
          86400 ; minimum
          )
@    86400    IN NS    pan.dotnul.org.
@    86400    IN NS    apollo.dotnul.org.
@    86400    IN NS    eros.dotnul.org.
; Mail Exchanger definition
@        IN MX    10 aspmx.l.google.com.
; IPv4 Address definition
*        IN A    88.190.215.226
@        IN A    88.190.215.226
localhost    86400    IN A    127.0.0.1
; IPv6 Address definition
*        IN AAAA    2a01:e0b:1000:31:250:56ff:fe00:4f7
@        IN AAAA    2a01:e0b:1000:31:250:56ff:fe00:4f7
EOF

We need now to create the named.conf file :

options {
        listen-on port 53 { any; };
        listen-on-v6 port 53 { any; };
        directory       "/var/named";
        dump-file       "/var/named/data/cache_dump.db";
        statistics-file "/var/named/data/named_stats.txt";
        memstatistics-file "/var/named/data/named_mem_stats.txt";
        allow-query     { any; };
        recursion no;
// Enable DNSSEC
        dnssec-enable yes;
        bindkeys-file "/etc/named.iscdlv.key";
        managed-keys-directory "/var/named/dynamic";
};
logging {
        channel default_debug {
                file "data/named.run";
                severity dynamic;
        };
};
// Define our public nameservers
acl pan { 164.138.26.209; };
acl apollo { 88.191.233.137; };
acl eros { 80.92.90.248; };
zone "." IN {
        type hint;
        file "named.ca";
};
include "/etc/named.rfc1912.zones";
include "/etc/named.root.key";
zone "africadns.de" IN {
        type master;
        file "data/africadns.de.zone";
// We need to authorize the public nameservers to transfer the zone
        allow-transfer { pan; apollo; eros; };
// By default, bind notifies all servers of the NS type
// but the server that is defined as SOA, we need to force the notification
        also-notify { 88.191.233.137; };
        key-directory "keys";
        inline-signing yes;
        auto-dnssec maintain;
};
EOF

Now, when we start bind, we will be able to see that the unsigned zone is loaded with the serial that has been set on the initial zone file.

named[1397]: starting BIND 9.9.2-RedHat-9.9.2-0.el6 -u named
named[1397]: built with '--build=x86_64-unknown-linux-gnu' '--host=x86_64-unknown-linux-gnu' '--
target=x86_64-redhat-linux-gnu' '--program-prefix=' '--prefix=/usr' '--exec-prefix=/usr' '--bindir=/usr/bin' '--sbindir
=/usr/sbin' '--sysconfdir=/etc' '--datadir=/usr/share' '--includedir=/usr/include' '--libdir=/usr/lib64' '--libexecdir=
/usr/libexec' '--sharedstatedir=/var/lib' '--mandir=/usr/share/man' '--infodir=/usr/share/info' '--with-libtool' '--loc
alstatedir=/var' '--enable-threads' '--enable-ipv6' '--with-pic' '--disable-static' '--disable-openssl-version-check' '
- --enable-exportlib' '--with-export-libdir=/usr/lib64' '--with-export-includedir=/usr/include' '--includedir=/usr/includ
e/bind9' '--with-pkcs11=/usr/lib64/pkcs11/PKCS11_API.so' '--with-dlz-ldap=yes' '--with-dlz-postgres=yes' '--with-dlz-my
sql=yes' '--with-dlz-filesystem=yes' '--with-gssapi=yes' '--disable-isc-spnego' 'build_alias=x86_64-unknown-linux-gnu' 'host_alias=x86_64-unknown-linux-gnu' 'target_alias=x86_64-redhat-linux-gnu' 'CFLAGS= -O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector --param=ssp-buffer-size=4 -m64 -mtune=generic' 'LDFLAGS=-L/usr/lib64/mysql' 'CPPFLAGS= -DDIG_SIGCHASE'
named[1397]: ----------------------------------------------------
named[1397]: BIND 9 is maintained by Internet Systems Consortium,
named[1397]: Inc. (ISC), a non-profit 501(c)(3) public-benefit 
named[1397]: corporation.  Support and training for BIND 9 are 
named[1397]: available at https://www.isc.org/support
named[1397]: ----------------------------------------------------
named[1397]: adjusted limit on open files from 4096 to 1048576
named[1397]: found 2 CPUs, using 2 worker threads
named[1397]: using 2 UDP listeners per interface
named[1397]: using up to 4096 sockets
named[1397]: loading configuration from '/etc/named.conf'
named[1397]: reading built-in trusted keys from file '/etc/named.iscdlv.key'
named[1397]: using default UDP/IPv4 port range: [1024, 65535]
named[1397]: using default UDP/IPv6 port range: [1024, 65535]
named[1397]: no IPv6 interfaces found
named[1397]: listening on IPv4 interface eth0, 88.190.218.238#53
named[1397]: listening on IPv4 interface tun0, 172.30.90.1#53
named[1397]: generating session key for dynamic DNS
named[1397]: sizing zone task pool based on 7 zones
named[1397]: set up managed keys zone for view _default, file '/var/named/dynamic/managed-keys.bind'
named[1397]: command channel listening on 127.0.0.1#953
named[1397]: managed-keys-zone: loaded serial 0
named[1397]: zone 0.in-addr.arpa/IN: loaded serial 0
named[1397]: zone 1.0.0.127.in-addr.arpa/IN: loaded serial 0
named[1397]: zone localhost.localdomain/IN: loaded serial 0
named[1397]: zone 1.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.ip6.arpa/IN: loaded serial 0
named[1397]: zone africadns.de/IN (unsigned): loaded serial 2013012930
named[1397]: zone localhost/IN: loaded serial 0
named[1397]: all zones loaded
named[1397]: running
named[1397]: zone africadns.de/IN (signed): loaded serial 2013012930
named[1397]: zone africadns.de/IN (signed): receive_secure_serial: unchanged
named[1397]: zone africadns.de/IN (signed): reconfiguring zone keys
named[1397]: zone africadns.de/IN (signed): next key event: 10-Feb-2013 15:35:25.763
named[1397]: zone africadns.de/IN (signed): sending notifies (serial 2013012930)

Don’t rejoy yourself too fast, the zone is not yet signed. You can see this by running the following :

rndc signing -list africadns.de
	No signing records found

So, now create the necessary keys. There’s several ways of using keys to achive zone signing, but here I will stick with the KSK and ZSK scheme.

Info Small detail, if you want those keys to sign your zone, you’ll have to name them exactly after the name of the zone you want to sign itself.

# go to the correct directory
cd /var/named/keys/

# Create a ZSK
dnssec-keygen -a RSASHA256 -b 2048 -3 -r /dev/urandom africadns.de
Generating key pair.....................................................................................................................................................+++ ............................+++ 
Kafricadns.de.+008+38349

# Create a KSK
dnssec-keygen -a RSASHA256 -b 2048 -3 -fk -r /dev/urandom africadns.de
Generating key pair......................+++ ...............................................................................................................+++ 
Kafricadns.de.+008+17491

# Let's have a look on what has been created now
total 32
- -rw-r--r-- 1 root  root   603 Feb 10 15:23 Kafricadns.de.+008+17491.key
- -rw------- 1 root  root  1776 Feb 10 15:23 Kafricadns.de.+008+17491.private
- -rw-r--r-- 1 root  root   604 Feb 10 15:23 Kafricadns.de.+008+38349.key
- -rw------- 1 root  root  1776 Feb 10 15:23 Kafricadns.de.+008+38349.private

# Make those files available for the daemon
chown named:named *

Even if the keys have been created, the zone is still not signed :

dig @127.0.0.1 africadns.de any

; <<>> DiG 9.9.2-RedHat-9.9.2-0.el6 <<>> @127.0.0.1 africadns.de any
; (1 server found)
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 22883
;; flags: qr aa rd; QUERY: 1, ANSWER: 7, AUTHORITY: 0, ADDITIONAL: 1
;; WARNING: recursion requested but not available

;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 4096
;; QUESTION SECTION:
;africadns.de.			IN	ANY

;; ANSWER SECTION:
africadns.de.		3600	IN	MX	10 aspmx.l.google.com.
africadns.de.		86400	IN	NS	eros.dotnul.org.
africadns.de.		86400	IN	NS	pan.dotnul.org.
africadns.de.		86400	IN	NS	apollo.dotnul.org.
africadns.de.		86400	IN	SOA	apollo.dotnul.org. benj.dotnul.com. 2013012930 86400 7200 604800 86400
africadns.de.		3600	IN	A	88.190.215.226
africadns.de.		3600	IN	AAAA	2a01:e0b:1000:31:250:56ff:fe00:4f7

;; Query time: 2 msec
;; SERVER: 127.0.0.1#53(127.0.0.1)
;; WHEN: Sun Feb 10 14:49:13 2013
;; MSG SIZE  rcvd: 233

Now, let’s tell bind to load the keys for the zone and let’s see the magic happen:

rndc loadkeys africadns.de
Feb 10 14:50:57 pontos named[1397]: received control channel command 'loadkeys africadns.de'
Feb 10 14:50:57 pontos named[1397]: zone africadns.de/IN (signed): reconfiguring zone keys
Feb 10 14:50:57 pontos named[1397]: zone africadns.de/IN (signed): next key event: 10-Feb-2013 15:50:57.386

Annnnd now, you have a working signed zone on the hidden master server.

You could also enable NSEC3:

rndc signing -nsec3param 1 0 10 20081982 africadns.de
	Feb 10 14:53:38 pontos named[1397]: received control channel command 'signing -nsec3param 1 0 10 20081982 africadns.de'
	request queued

Slave servers

So, to have working DNSSEC slaves, you _indeed_ need to enable DNSSEC. Here’s a working configuration :

options {
        listen-on port 53 { any; };
        listen-on-v6 port 53 { any; };
        directory       "/var/named";
        dump-file       "/var/named/data/cache_dump.db";
        statistics-file "/var/named/data/named_stats.txt";
        memstatistics-file "/var/named/data/named_mem_stats.txt";
        allow-query     { any; };
        recursion no;
        dnssec-enable yes;
        dnssec-validation no;
        dnssec-lookaside auto;
        bindkeys-file "/etc/named.iscdlv.key";
        managed-keys-directory "/var/named/dynamic";
};
statistics-channels {
        inet * port 8080;
};
logging {
        channel default_debug {
                file "data/named.run";
                severity dynamic;
        };
};
zone "." IN {
        type hint;
        file "named.ca";
};
include "/etc/named.rfc1912.zones";
include "/etc/named.root.key";
zone "africadns.de" IN {
        type slave;
        file "data/africadns.de.zone";
        masters { ip.of.the.master; };
        allow-transfer { none; };
        notify no;
};

DS records

In order to make the DNSSEC chain work properly, you need to provide either to your registry (that usually goes through you registrar) or to ISC if you use DLV DS records that would be included in the higher level zone. There is several ways or finding them, here’s one of them:

dig @127.0.0.1 dnskey africadns.de | dnssec-dsfromkey -f - africadns.de
	africadns.de. IN DS 20542 8 1 8EC93E76ED3748D77874BEA722D3793EB92C94B0
	africadns.de. IN DS 20542 8 2 A5041614B71E5F77979EBA8970537CE13EDBB9CC007403DF93FC4F12 8EA50A42

Inline signing

The whole thing with inline zone signing is that bind keeps track of both (unsigned and signed) zones to give you the possibility of editing the plain initial zone file like when zone signing is not in use. Once you trigged a zone reload, bind will handle the resigning of the zone. Here’s a little demonstration :

# Before editing the unsigned zone serial is
grep serial /var/named/data/africadns.de.zone
	2013012930 ; serial
# Before editing the signed zone serial is 2013012937
	;; ANSWER SECTION:
	africadns.de.		86400	IN	SOA	apollo.dotnul.org. benj.dotnul.com. 2013012937 86400 7200 604800 86400
	africadns.de.		86400	IN	RRSIG	SOA 8 2 86400 20130320195336 20130218185336 58008 africadns.de. jZtKKdYjH57EaDE9mGV8OccOuGA3x4DnI5kjydcnQZcbxgflnHceckv8 V6GtNJeijwW7lkKPk/BmexlVTVjC2PtmP2dLhPn16r7jSVSzkA4llVgT 47t6pbuz5CTx60hWbZGtdpcCI5xhM1l/0L8Rh05Ky+t5CJv6ThicQqFK ztcz1oQd8hSvlrC043qkk4LOerNnCRrKwu0o83KO3HUPhtVUhnqwqAsR 3Vmlo/9eKZwyOz6nhdIV52TUI3rt1XsgBSgPZPl3qoctZ1hlhxLm4sVW H0pjPUSwCXclOXBUPuNnnKgwsAUaWezmd0ZXLs5XSpza2wKsUKEz13se RpJFdg==

# Now, unsigned zone file has been edited as usual. Let's reload:
Feb 18 21:02:36 pontos named[1707]: zone africadns.de/IN (unsigned): loaded serial 2013012931
Feb 18 21:02:36 pontos named[1707]: zone africadns.de/IN (signed): serial 2013012938 (unsigned 2013012931)
Feb 18 21:02:36 pontos named[1707]: zone africadns.de/IN (signed): sending notifies (serial 2013012938)

Running a key rollover

We initially did set up two keys and later on submitted both (KSK and ZSK) DS records to our registry. It is good practice not to do this, and only submit the KSK to the registry, so that what is supposed to be changed quite often (there’s no good practice -I think- with when it should be done) changes often enough. What we will do is change the current ZSK (this is called a “rey rollover”) and remove the DS key reference on the registry side (well, this won’t be shown, but we will be able to see the effects).

key rollover

As shown in the previous picture, there is four periods involved in the key rollover mechanism:
Before T1:
At this time, the KSK and first created ZSK are present and known by the registry.

Before continuing, lets set what are T1, T2, T3 and T4 on the previous image (from dnssec-settime man page):
T1: Sets the date on which a key is to be published to the zone. After that date, the key will be included in the zone but will not be used to sign it.
T2: Sets the date on which the key is to be activated. After that date, the key will be included in the zone and used to sign it.
T3: Sets the date on which the key is to be retired. After that date, the key will still be included in the zone, but it will not be used to sign it.
T4: Sets the date on which the key is to be deleted. After that date, the key will no longer be included in the zone. (It may remain in the key repository, however.)

Let’s now create a new ZSK, and set dates on the keys:

dnssec-keygen -a RSASHA256 -b 2048 -3 -r /dev/urandom africadns.de
	Generating key pair..........................+++ ...............................................................................................................................................................+++ 
	Kafricadns.de.+008+43728
# Set Prepublish (T1) and Active (T2) on newly created ZSK key
dnssec-settime -P 20130218231500 -A 20130219100000 Kafricadns.de.+008+43728
	./Kafricadns.de.+008+43728.key
	./Kafricadns.de.+008+43728.private	
# Set Inactivity (T3) and Deletion (T4) on the previous ZSK key
dnssec-settime -I 20130219110000 -D 20130219120000 Kafricadns.de.+008+58008
	./Kafricadns.de.+008+58008.key
	./Kafricadns.de.+008+58008.private

At T1, we see (thanks to DNSviz) that the newly created key has been prepublished , but not using for signing anything:

prepublish new key

At T2, we see that the new key has been activated and is used to sign the SOA record. We also see that the registry has no DS record pointing to this new key.

Activate new key
# Here's what's active at this moment:
;; ANSWER SECTION:
africadns.de.		86400 IN DNSKEY	257 3 8 (
				AwEAAebXSvKnHVH+H1zw2JJupB8MvRY4kWY1PZZl/U0z
				gDrqXG5FfokLCUF1xSeBCYEVGnFyyVhtiqm8ljT+B9gE
				RvZ66tz/6LijrP9hlDJ2suv3E6PAwEcUyngvXNR95Qfo
				8YCHAozxe42LTxu0TLVV3MP/4PAfH51waQo0GcaWssAO
				CxnJgRc0hols5Dsgdiyg26A5/YjaC/StjkxOOFK9Tt7H
				V9Epf6Ntf7r3htrW3JjsmyY3UzvNxLujR6tORe6Lb+9G
				s8J36h7GQAPZVPRM65C0zhUTEpcNyCxoDojZqaiUnlAa
				IV5CIZO5/lANDZIiGh+APCo59Un8zX3bu451J9c=
				) ; key id = 20542
africadns.de.		86400 IN DNSKEY	256 3 8 (
				AwEAAcYQIZJFKCRHluOWy8KtsyXULhfiF9PgmiWMASxH
				ElDimB6mZb1o88W13GQRuE2NLM3SWehkVzXWQnHZ75Si
				ShUXFgYdR0XMZeTvasdxgisXil2XH3lK1KtUa93Ii/jz
				A9bAhqd3dMHcAPtq9sIued5DDhanNjh1coxKPR8QQIEP
				biLvy9VqqtC81CD1AGmbKyS/Ss3XfMK8PIZup1fJaIZG
				HGLz0I/gh3zDEPwxs7JAKHMdvvf5Nx8qsxpyFmOWLXva
				dEsKuHqR+yQedUjAMu7o3coWinb22A1Zpgs21kGU2Vaq
				8a6Z35GSL7/+AzLBE1exmbPmvx+m/HxDFHXQGoU=
				) ; key id = 58008
africadns.de.		86400 IN DNSKEY	256 3 8 (
				AwEAAb3WJtMKZXFk0uGDuQNhSH6RO2GtRCgcHDU6GsVz
				YXW+36dyzfNCBowP6xBU/kIeWXXGTBiFoQ2FoYqJYF4B
				DOAJAi92UEvcptWVKWZqO8qV1F6ZAc/SVIaVGDf54Ju7
				jZKrs5/KlNngWJtwWo0mCzv98BJtr5Wi14c9xGkNhwGZ
				lmqyVoGyUfvPMLmERJcxh73gdBgFN7IgqjYBx/NrTJyl
				cYraqAu/K3fk/jZknM0cQGpc1awGxxLq9GHmDnRbDlQe
				bZiyVjpMTsXB4bQ3q3aL4AqUIFH2jr8ofnnK6vfWVCVY
				DkffW+VKqCVDD2tc+FNdyVho/eprtUm01aTylDk=
				) ; key id = 43728

At T3, we see that the old key is still present, but not used for signing and marked as inactive.

Retire old key

Now, we just need to remove the ZSK related DS record at the registry level, and we’ll see it this way :

Delete old key

Rollover done successfully ! What I would recommend is that you don’t bother creating a new ZSK each time the old one is about to expire, because this is an error prone process. I rather recommend you to create several (like 12 of them if you plan to rollover monthly) ZSKs and set correct T1,2,3,4 dates for a year being on each key.

-----BEGIN PGP SIGNATURE-----
Comment: GPGTools - http://gpgtools.org

iQIcBAEBCAAGBQJW5eRJAAoJEBeKS2x6xuR7LSYP/00gmolYUUMuuVnHNNH9O/Mh
yEqk6twKz7fRC//hM+OOYpSyI5jIBagXvtbYP1oAAborcBWBVZHGvzy2dF6ehsp8
vuFJZn5D26Qj9n3MwqW7DIgQEcVQwpY1Mf6ML3fBgGA590kVuz0Fow76QkoAKpYK
3e8ukReyTit+mqDBtLY+IbohrHWuIP+ZRrrlVGpqShslxDee6A5dD6AqrZkKzGeg
GvH8nIyB4+szLBH7vmVMf8rJEVIH97N6TyMzF1FpNPkxFYKyySQ/K3OdNbi0qG6y
u1rAWnPhxoa0oLuqU5CnKI+4qTV+sQhOZ+JAw/vnmhto+Tzd5rK8wUEj3kNX1pWU
Qr0F51x7bVDasc8VXQOogptweWN2cDoRZx8xQKP83iH/6IgCx9H5v6grTPL5RHg+
krvypwO3EDX2qxhxK8CY3ppKCvMnaR7f5wprk0jxqWXCK9GxvmT60y3xA+K04IGd
mBHiDyNTIZt6uSnJ7avsxSDPsa5UF1LyDMq6ISl/sxMGTxuCPGrAHlNXvYdrfgOp
sTk5OxOU9l7a7uvnOP7bhuPea2fLpY6aHP05P7YEok9Uo9QODa1SkIy1JzKS99zz
xqC18fnOrte5eMkp2CM4rhSNVmTv5DfDYrpIdkWYt5FVIVbi195gvPL6caVBU/3m
67Lpjb6NaX9Zgl7HEANk
=pXRS
-----END PGP SIGNATURE-----

Hint: To validate signature, please view page source and copy html code between BEGIN PGP Signed message and END PGP Signature anchors.

Created the 2013-02-27

Share this


Article content

Resources

10 last blog posts

Related to this article

blog comments powered by Disqus