You know the drill: you provision a server with a master zone, and then you have to hop over to all secondary servers and add the slave zone to their configuration. You probably do that with some form of automation, or you use something slightly convoluted like what we've discussed previously in automatic provisioning of slave DNS servers. If your master and slave servers are BIND, you're in luck: catalog zones will automate this for you within the BIND code itself: there'll no longer be a need for "hacking" this to accomplish automatic provisioning of slave BIND servers.

Catalog zones are scheduled for release in BIND 9.11, but Evan Hunt graciously let me have a peek at a preview of the code, and I must warn you: first, this is a work in progres and hasn't been released yet, and second (and more importantly) what I'm going to show you is the little I know of catalog zones. Be warned on both accounts! Update: Catalog zones are now in BIND 9.11.0a3.

Catalog zones are based on an Internet-Draft called draft-muks-dnsop-dns-catalog-zones-01 which describes a method for automatic synchronization of zones among primary and secondary servers. The way this is works is that a zone contains the names (and optional metadata) describing which zones are to be used on slave (secondary) servers; these zone names in a catalog are called member zones. The secondary server obtains a copy of this catalog (via zone transfer (AXFR/IXFR)) and uses it to update the internal catalog of zones it ought to have; once it detects a change, it adds and slaves the member zone or deletes it, depending on whether the member zone was added or removed.

More concisely: we add one or more member zones to the catalog zone which is transferred to its slaves where it triggers the creation (or removal) of the member zones.

Catalog zones

Let's see how this works in practice with a preliminary copy of BIND which supports this.

Primary and secondary servers

On my primary test server, I add the following to named.conf:

options {
        directory "/etc/namedb";
        ...
        server-id "authoritative";
        allow-new-zones yes;
};

zone "catalog.example.com" {
        type master;
        file "catalog.example.com.db";
        also-notify { 192.168.1.189; };
        notify explicit;
};

Pay attention to the allow-new-zones directive. The catalog zone proper is mostly empty: mname, rname and NS are irrelevant, and the relative version label specifies the catalog zone format version:

@ 3600 SOA . . 1 86400 3600 86400 3600
@ 3600 IN NS nop.
version IN TXT "1"

On a secondary (192.168.1.189) I have the following configuration:

options {
        directory "/etc/namedb";
        ...
        masterfile-format text;
        zone-statistics yes;
        server-id "slave";

        allow-new-zones yes;
        catalog-zones {
                zone "catalog.example.com"
                      zone-directory "cat-zones"
                      in-memory no
                      default-masters { 192.168.1.188; };
        };
};

zone "catalog.example.com" {
        type slave;
        file "catalog.example.com.db";
        masters { 192.168.1.188; };
};

Here we also add allow-new-zones so that the secondary can create member zones on the fly, and we use the new catalog-zones stanza to define the primary server which holds our catalog. The default-masters statement in the catalog-zones stanza defines the default masters for its member zones.

The optional zone-directory in "catalog-zones" allows master files for slaves provisioned by catalog zones to be stored in a directory other than the server's working directory.

If in-memory is set to yes, local copies of master files on slaves will be store in memory only (not on the file system).

Adding a new member zone

On the primary server I add a new zone, either dynamically with rndc addzone or manually; I'll use the former:

$ rndc addzone example.org '{type master; file "example.org";};'
$ dig +short @localhost example.org soa
localhost. root.localhost. 22 10800 3600 604800 3600

From this point onwards, my primary server is ready to serve this master zone, but I want the secondary to serve the zone as well. Here's what I do:

  1. I create a hash of a value. Basically any value should do, but it must currently be a valid BIND "nzf" hash. (The pre-alpha code I have does a little oops if it isn't -- I'm reporting that as we speak.) ISC is considering loosening this rule to allow me to use any label I wish to, but for interoperability with possible future implementations which comply with the draft, the hash is preferable.
  2. I then add a record to the catalog zone in which I name the member zone, bump its serial and reload the zone.
#!/usr/bin/env python

import dns.name
import hashlib
import sys

print hashlib.sha1(dns.name.from_text(sys.argv[1]).to_wire()).hexdigest()

I run the above (thanks Witold!) to create the hash:

$ ./nzf.py example.org
47ac1a4d93b61fffdb4762c18c9e7d1a6b046d33

Another way of creating the hash (thanks, Peter) is:

$ printf '\7example\3org\0' | openssl sha1
47ac1a4d93b61fffdb4762c18c9e7d1a6b046d33

I now use that hash for step 2 and add a record containing the member zone:

@ 3600 SOA . . 2 86400 3600 86400 3600
@ 3600 IN NS nop.

47ac1a4d93b61fffdb4762c18c9e7d1a6b046d33.zones           PTR example.org.

When I reload named on the primary (rndc reload), I watch the transfer logs; they look very promising:

xfer-out: info: client 192.168.1.189#33213 (catalog.example.com): transfer of 'catalog.example.com/IN': AXFR-style IXFR started (serial 2)
xfer-out: info: client 192.168.1.189#33213 (catalog.example.com): transfer of 'catalog.example.com/IN': AXFR-style IXFR ended
xfer-out: info: client 192.168.1.189#45095 (example.org): transfer of 'example.org/IN': AXFR started (serial 22)
xfer-out: info: client 192.168.1.189#45095 (example.org): transfer of 'example.org/IN': AXFR ended

Note how first the catalog zone was transferred, and then our new example.org zone.

So, what's on the secondary?

$ ls -l /etc/namedb/cat-zones
-rw-r--r-- 1 root root  316 Jun  2 13:33 __catz__catalog.example.com_example.org.db

The __catz__* file contains a copy of the slaved zone.

If I delete a member zone record from the catalog the process is reversed, and the secondaries remove the zone completely:

catz: updating catalog zone 'catalog.example.com' with serial 3
catz: deleting zone 'example.org' from catalog 'catalog.example.com' - success
catz: catz_delzone_taskaction: zone 'example.org' deleted

Metadata

BIND can use metadata on a zone which is transferred with the catalog: for example different master servers for a particular zone. This allows us to add a member zone to the catalog, which is configured with different master servers. So, on my primary server, I can add the following to the catalog: the first record specifies a member zone, and the second record the master(s) for that zone.

45414dc99ae20a84507692de578c0dd9d2522134.zones           IN PTR ww.mens.de.
masters.45414dc99ae20a84507692de578c0dd9d2522134.zones   IN A 192.168.1.130

When the secondaries get the catalog, this member zone is created and configured to obtain a copy of its data from the specified master server.

Another interesting feature is the possibility of setting ACLs on particular member zones within the catalog. This is done using Address Prefix Lists (RFC 3123):

allow-transfer.45414dc99ae20a84507692de578c0dd9d2522134.zones   IN APL  1:192.168.1.189/32 1:192.168.1.206/32

The above example would allow transfers from the two addresses only.

Catalog zones may also carry TSIG signatures for member zones; this is described in the BIND ARM.

Closing

It goes without saying (so why am I?) that the catalog zone can be dynamically updated of course; this makes provisioning easy and ensures the SOA serial number is bumped.

We should probably all wish for other Open Source DNS server implementations to embrace catalog zones and add support for them in order to increase interoperability between DNS server software brands.

Updates:

Flattr this
BIND and DNS :: 24 May 2016 :: e-mail

Comments

blog comments powered by Disqus