It took me a while to get nsupdate to work. There are lots of resources out there, but as usual it's hard to separate the grain from the chaff. When everything was said and done, the solution was relatively simple. Here it is.
Generate TSIG keys
# dnssec-keygen -r /dev/urandom -a HMAC-MD5 -b 512 -n HOST myzone.com
This generates 2 files of the form:
-rw------- 1 root bind 122 2012-03-21 15:47 Kmyzone.com.+157+02058.key
-rw------- 1 root bind 229 2012-03-21 15:47 Kmyzone.com.+157+02058.private
Note that I specified /dev/urandom as the source of randomness, which may not meet your security requirements. When I didn't specify the -r /dev/urandom parameter, the dnssec-keygen command appeared to hang.
Also note that the type of the key needs to be HOST (specified via -n HOST).
Add key to DNS master server configuration and allow updates
I modified /etc/bind/named.conf.local and added a 'key' section:
key "myzone.com." {
algorithm hmac-md5;
secret "JKlA76FvmGboEQ8R2yoc9AtpFqkIncH5yf2mXY+s8m6a/RRC0thUVGnqrJSO1QKhzlnkbxTjmArap+WuVW9iLQ==";
};
algorithm hmac-md5;
secret "JKlA76FvmGboEQ8R2yoc9AtpFqkIncH5yf2mXY+s8m6a/RRC0thUVGnqrJSO1QKhzlnkbxTjmArap+WuVW9iLQ==";
};
The key name can be anything you want. The secret is the actual key, which can be found in both of the files generated by dnssec-keygen.
I also added an allow-update directive to the zone that I wanted to modify via nsupdate. This is still in /etc/bind/named.conf.local:
zone "myzone.com" {
type master;
file "/var/lib/bind/myzone.com.db";
allow-update { key "myzone.com."; };
};
file "/var/lib/bind/myzone.com.db";
allow-update { key "myzone.com."; };
};
I then restarted bind9 on the master DNS server via 'service bind9 restart'. I checked /var/log/daemon.log to make sure there were no errors during the restart.
Note that you can use a more finely grained control over which operations you allow for the updates. See the 'Allowing Updates' section in this 'Secure DDNS Howto' document.
Use nsupdate to do remote updates
On a remote trusted host of your choice, copy the private file generated by dnssec-keygen, and create a file containing the desired updates to the zone file on the master. This file is of the form:
# cat nsupdate.txt
server master.dns.server.myzone.com
debug yes
zone myzone.com.
update add testnsupdate.myzone.com. 86400 CNAME ns1
show
send
Then run nsupdate and specify the kddey and the file you just created:
# cat nsupdate.txt
server master.dns.server.myzone.com
debug yes
zone myzone.com.
update add testnsupdate.myzone.com. 86400 CNAME ns1
show
send
Then run nsupdate and specify the kddey and the file you just created:
# nsupdate -k Kmyzone.com.+157+02058.private -v nsupdate.txt
If everything goes well, you should see something like this in the debug output of nsupdate (because we specified 'debug yes' in the nsupdate.txt file):
;; UPDATE SECTION:
testnsupdate.myzone.com. 86400 IN CNAME ns1
;; TSIG PSEUDOSECTION:
myzone.com. 0 ANY TSIG hmac-md5.sig-alg.reg.int. 1332788750 300 16 UxiMG7+X2RejWzQ9rkuPaQ== 3305 NOERROR 0
Reply from update query:
;; ->>HEADER<<- opcode: UPDATE, status: NOERROR, id: 3305
;; flags: qr ra ; ZONE: 0, PREREQ: 0, UPDATE: 0, ADDITIONAL: 1
;; TSIG PSEUDOSECTION:
myzone.com. 0 ANY TSIG hmac-md5.sig-alg.reg.int. 1332788857 300 16 KBubhEggwBHnPlbmlQ7iTw== 3305 NOERROR 0
On the master DNS server, you should see something like this in /var/log/daemon.log:
Mar 26 12:07:37 dns01 named[14952]: client 10.0.10.133#58265: signer "myzone.com" approved
Mar 26 12:07:37 dns01 named[14952]: client 10.0.10.133#58265: updating zone 'myzone.com/IN': adding an RR at 'testnsupdate.myzone.com' CNAME
Mar 26 12:07:37 dns01 named[14952]: zone myzone.com/IN: sending notifies (serial 2012032104)
Mar 26 12:07:37 dns01 named[14952]: client 10.0.10.121#50790: transfer of 'myzone.com/IN': IXFR started
Mar 26 12:07:37 dns01 named[14952]: client 10.0.10.121#50790: transfer of 'myzone.com/IN': IXFR ended
One other important note: the modifications made with nsupdate take effect immediately on the DNS master server (and they also get pushed from there to slave servers), but they are not written immediately to the actual DNS zone file on disk on the master server. Instead, a journal file is used, in the same directory as the zone file. The journal entries get applied periodically to the main zone file. If you restart bind9, the journal entries also get applied.
That's about it. If everything went well, you now have an API of sorts into your Bind 9 server. Now go automate all the things!
More resources:
- "DNS Security Part 1: Dynamic Updates" by Kerry Thompson
- "DNS Security Part 2: DNSSEC" by Kerry Thompson
- "A DDNS server using BIND and nsupdate"
- "Running a secure DDNS service with BIND"