When talking about performing dynamic DNS updates on your DNS servers the other day, I concentrated on using TSIG keys, but there are some disadvantages in using those:
- A TSIG key is a symmetric key (or a shared key) that both parties (i.e. client and server) must know.
- TSIG keys have to be configured in
named.conf
, which means that whenever the key is changed, you have to update your server’s configuration. - Most importantly perhaps, a client cannot change its key at will because of the first two reasons: she needs the cooperation of the server’s administrator to change the shared key.
SIG(0) keys are asymmetric key-pairs; there is a private key which must be
known to the client, and a public key. Together, these form a SIG(0) key-pair.
They can be of any of the asymmetric key algorithms (RSAMD5, RSASHA1, ECSDA, etc.).
To create a SIG(0) key pair, I use the dnssec-keygen
utility supplied as
part of a BIND distribution. Note how I use the -C
option to generate
what is called a backward-compatible key; this omits all dates in the private
key, and I can use the key file with Net::DNS, as I’ll show you in a
moment.
dnssec-keygen -C -a 13 -n HOST -T KEY jp.example
Generating key pair.
Kjp.example.+013+64258
Here again we see the filename prefix (Kjp.example.+013+64258
)
dnssec-keygen
has created a .private
and a .key
file. The content of the
.key
file is a DNS resource record that goes in to the zone to be
protected:
jp.example. IN KEY 512 3 13 cfBQzVgQHb8/DDaHL ... ULirdfNFvfZpYA==
When I’ve done that, I can configure my BIND name server as we discussed recently:
zone "example" IN {
type primary;
file "example";
allow-update {
key "jp.example.";
};
};
Update 2021: nowadays I’d go with the much more granular update-policy
which allows me to finely tune which key may update which records. For example, the key jp.example
might be permitted to update TXT, A, and AAAA records in the hosts.example
subdomain and update itself:
zone "example" {
update-policy {
grant "jp.example." subdomain hosts.example. TXT A AAAA;
grant "jp.example." name jp.example. KEY;
};
};
Note how the key name in the allow-update
clause specifies the
domain name I supplied during key generation. Also take note that the key
itself isn’t in named.conf
; it is in the zone. The client uses the private
key (contained in the .private
file) to sign update requests. I can use the
nsupdate
utility for performing dynamic updates, but I can also use Perl’s
Net::DNS modules:
#!/usr/bin/perl
use strict;
use Net::DNS;
use Net::DNS::Update;
use Net::DNS::SEC;
my $zone = "example";
# Create the update packet.
my $update = Net::DNS::Update->new($zone);
# Add an A record for the name.
$update->push(update => rr_add("aa.$zone. 120 A 127.0.0.8"));
# Sign the update packet
$update->sign_sig0("Kjp.example.+013+64258.private");
# Send the update to the zone's primary.
my $res = Net::DNS::Resolver->new;
$res->nameservers('127.0.0.1');
my $reply = $res->send($update);
# Did it work?
if ($reply) {
if ($reply->header->rcode eq 'NOERROR') {
print "Update succeeded\n";
} else {
print 'Update failed: ', $reply->header->rcode, "\n";
}
} else {
print 'Update failed: ', $res->errorstring, "\n";
}
An important thing to remember is to not rename the K*
files
generated by dnssec-keygen
; Net::DNS needs the filename to determine the
algorithm and the key tag. So what do we now have? We have a BIND zone that
can be remotely updated, but we have something else: the client (i.e. the
owner of the private key) can generate a new key pair and update (i.e.
replace) the key in the dynamic zone whenever she feels like it. (And, of
course, if the update-policy on the server allows her to do that.) Compared
with TSIG, SIG(0) offers the following advantages:
- Only the client has to know the private key. The client can send the public key (in the DNS RR) to the server operator for first-time inclusion into the zone.
- Divulging the key in the zone is not a problem because it is the public portion only.
- Clients can dynamically update their keys because the public key is in the zone.
There is one disadvantage, though: SIG(0) is probably not as widely implemented as TSIG. In fact IIRC, ISC’s dhcpd server doesn’t support it.