How to update a zone with auto-dnssec: maintain

I am running an authoritative BIND 9.9.5-9+deb8u8-Debian on Debian Jessie. I have a working zone for robin.info that works properly (various tests report success, such as the one on pingdom.com's DNS check tool)

I am trying to secure it with dnssec. I am following the instructions given in the BIND DNSSEC Guide, chapter 4 with easy start. I generated a ZSK and KSK successfully, and updated my zone adding the lines in bold:

zone "robin.info" {
        type master;
        file "/etc/bind/zones/robin.info";
        include "/etc/bind/include-zones/acls";
        key-directory "/etc/bind/dnssec/robin.info/2016";
        inline-signing yes;
        auto-dnssec maintain;
};

I made sure that no .jnl, .jbk, .signed and .signed.jnl files were present with the zone file, then restarted bind with rndc reload and confirmed that the zone was loaded and had DNSKEY entries, although I had a few errors in the log:

11-Dec-2016 13:54:20.742 zone robin.info/IN/internal (signed): loaded serial 2016121111
11-Dec-2016 13:54:20.742 zone robin.info/IN/external (signed): loaded serial 2016121111
11-Dec-2016 13:54:20.750 zone robin.info/IN/external (signed): receive_secure_serial: unchanged
11-Dec-2016 13:54:20.750 zone robin.info/IN/external (signed): reconfiguring zone keys
11-Dec-2016 13:54:20.766 zone robin.info/IN/external (signed): next key event: 11-Dec-2016 14:54:20.750
11-Dec-2016 13:54:20.796 zone robin.info/IN/internal (signed): receive_secure_serial: unchanged
11-Dec-2016 13:54:20.796 zone robin.info/IN/internal (signed): reconfiguring zone keys
11-Dec-2016 13:54:20.805 malformed transaction: /etc/bind/zones/robin.info.signed.jnl last serial 2016121113 != transaction first serial 2016121111
11-Dec-2016 13:54:20.805 zone robin.info/IN/internal (signed): zone_rekey:dns_journal_write_transaction -> unexpected error

These serial errors seem to cause problem down the line when I want to update my zone. I make changes in the unsigned zone /etc/bind/zones/robin.info, and increase my the serial to 2016121121

11-Dec-2016 13:57:58.658 zone robin.info/IN/internal (signed): serial 2016121121 (unsigned 2016121121)
11-Dec-2016 13:57:58.658 zone robin.info/IN/internal (signed): could not get zone keys for secure dynamic update
11-Dec-2016 13:57:58.658 zone robin.info/IN/internal (signed): receive_secure_serial: not found
11-Dec-2016 13:57:58.659 malformed transaction: /etc/bind/zones/robin.info.jnl last serial 2016121121 != transaction first serial 2016121111
11-Dec-2016 13:57:58.659 zone robin.info/IN/external (unsigned): not loaded due to errors.
11-Dec-2016 13:57:58.659 all zones loaded
11-Dec-2016 13:57:58.659 running
11-Dec-2016 13:57:58.661 zone robin.info/IN/internal (signed): reconfiguring zone keys
11-Dec-2016 13:57:58.670 malformed transaction: /etc/bind/zones/robin.info.signed.jnl last serial 2016121115 != transaction first serial 2016121111
11-Dec-2016 13:57:58.670 zone robin.info/IN/internal (signed): zone_rekey:dns_journal_write_transaction -> unexpected error
11-Dec-2016 13:57:58.670 zone robin.info/IN/external (signed): reconfiguring zone keys
11-Dec-2016 13:57:58.671 zone robin.info/IN/external (signed): next key event: 11-Dec-2016 14:57:58.670

I can confirm with dig that my old zone is still loaded (from SOA and changes that aren't visible).

There are several error messages here:

1) Suggesting that I am having trouble with the keys ("could not get zone keys for secure dynamic update"). However bind had no trouble with that on the first load, and my key files are readable by bind (named is run as user bind which is member of group bind):

xavier@dent:/etc/bind/zones$ ls -l /etc/bind/dnssec/robin.info/2016
total 17k
-rw-r--r-- 1 root bind  603 Dec 10 17:23 Krobin.info.+008+43324.key
-rw-r----- 1 root bind 1.8k Dec 10 17:23 Krobin.info.+008+43324.private
-rw-r--r-- 1 root bind  604 Dec 10 17:22 Krobin.info.+008+44679.key
-rw-r----- 1 root bind 1.8k Dec 10 17:22 Krobin.info.+008+44679.private

2) Suggesting an error with the serials (the inital error was last serial 2016121113 != transaction first serial 2016121111). However I thought I didn't have to worry about too much about the serials, since in ISC's KB I can read that:

Note that the serial number in this response is not the same as the one in the file example.com.db. Named keeps track of the serial number of the signed version of the zone independently of the unsigned version. If the unsigned zone is updated with a new serial number that's higher than the one in the signed copy, then the signed copy will be increased to match it, but otherwise the two are kept separate.[1]

So far the only way I found to update the zone is to stop bind, delete the .jnl, .jbk, .signed and .signed.jnl files and start bind again. This seems wrong, and I need to make sure I increase the serial enough to activate the new zone. What am I doing wrong and how can I fix my dnssec?


Solution 1:

I think I finally found the root cause of my problem. I have two views, that were configured to include the same master zone file twice.

You cannot use the same file for two zones. So this is invalid and caused my problem:

view "internal" {
    match-clients ...;
    zone "example.com" {
        type master;
        file "/etc/bind/zones/example.net";
    };
};
view "external" {
    match-clients ...;
    zone "example.com" {
        type master;
        file "/etc/bind/zones/example.net";
    };
};

The proper way to share a zone is described in chapter 4 of the " Understanding views in BIND 9, by example" guide. Basically, only one of the zone must be the master zone, and the other one must be a slave. After adding a few acls, keys and also-notify for localhost in the right places, I got rid of those errors.

In the end this is my final configuration:

key "internal" {
    // TSIG Key generated with dnssec-keygen -a HMAC-MD5 -b 512 -n USER internal
    algorithm hmac-md5;
    secret "XXXX";
};

view "internal" {
    match-clients { key internal; ...IPs...; }; // our network
    zone "robin.info" {
        type slave;
        file "/etc/bind/slave-zones/robin.info"; // Not the same file as external view!
        masters { 127.0.0.1; };
    };
};

view "external" {
    match-clients { !key internal; "any"; }; // everyone else
    server 127.0.0.1 {
        /* Deliver notify messages to internal view with internal key. */
        keys { internal; };
    };
    zone "robin.info" {
        type master;
        file "/etc/bind/zones/robin.info";
        // ACL file with allow-transfer and also-notify
        // including secondary DNS servers and 127.0.0.1
        include "/etc/bind/acls"; 
        key-directory "/etc/bind/dnssec/robin.info/2017";
        inline-signing yes;
        auto-dnssec maintain;
    };
};

Solution 2:

The core seems to be the could not get zone keys for secure dynamic update error message, so falling back to unsigned; and since it's not going through the signing path which auto-bumps the SOA for signing, it complains that the SOA is out-of-date.

I got the same error message when adding signing to three zones and scratched my head, then sighed and just restarted named entirely. That solved it for me. Bind 9.11.0P3.

I don't recall seeing this problem in the past when adding signing, but all other zones were signed ages ago with the transition under an earlier version of Bind. Also, these three zones are reverse DNS files, so slightly unusual in filename. That's about all I have to explain it.

So: bind bug, restart named entirely, let it find the keyfiles for real and then sign.