DNS
Security Protocols I: Dynamic Updates
Kerry Thompson
Of all of the many network protocols used in computer networking,
DNS is one of the most fundamental and important. The task of mapping
domain names to IP addresses seems simple, and at first approach
it is. However, issues arise when that protocol becomes extensively
trusted by systems. Packets within the DNS protocol are all sent
as clear text, which means that they can easily be read and modified
while in transit. DNS uses the UDP protocol, which has no handshaking
between clients and servers and is therefore quite susceptible to
spoofing attacks. We no longer have a trusted Internet in which
we can trust insecure services -- there are malicious attackers
that will do their very best to make users go to spoofed banking
sites, to swamp everyone with spam, and to generally wreak havoc.
This article is the first of two in which I will be looking at
the use of cryptographic methods to secure DNS. In this article,
I will cover secure dynamic updates and zone transfers using TSIG
keys; in the second article, I will cover the DNSSEC protocols for
securing zone data.
In my examples, I'm using an installed copy of ISC BIND version
9.3.0rc2 from www.isc.org, which has been set up to serve a test
domain "domain.tld" and a reverse domain "1.168.192.in-addr.arpa".
I won't cover the installation of the BIND software here, but
it is quite straightforward. Note that you will need to add the
"--with-openssl" option to the ./configure command if you want to
use the DNSSEC functionality.
Secure Dynamic Updates
Using dynamic updates is a great way to maintain your DNS zone
data. With some knowledge and a bit of practice, you will probably
find this method easier and less mistake-prone than the old-fashioned
way of editing zone files (don't forget to update that serial number!).
Enabling dynamic updates is easy, but care must be taken to make
sure the setup is secure. Although you can restrict updates by their
originating IP address, this approach is not very secure because
updates use UDP, which is quite easily spoofed. A better method
is to sign the updates with Transaction Signature (TSIG) keys and
permit only updates with authorized keys.
Keys are simply base-64 encoded random data that is shared by
the DNS server and the client system sending updates. To generate
a key for updates, use the dnssec-keygen command:
dnssec-keygen -a HMAC-MD5 -b 512 -n HOST update_key
This generates a 512-bit key with the HMAC-MD5 algorithm and places
the result into two files: Kupdate_key.+157+59571.key and Kupdate_key.+157+59571.private
for the public and private key data. The numbers in the key file name
are for the key algorithm (157 for HMAC-MD5) and a 5-digit random
key identifier (which will be different on your system). Store both
key files in /var/named or wherever you keep DNS zone files on your
DNS server. Next, configure your DNS server to accept updates signed
with this key, edit /etc/named.conf, and add the definition for the
key:
key update_key {
algorithm HMAC-MD5;
secret "fxT7q+Kq8TUmZrN4edxAVeTeOmiX/3A6HQ40HcyI...g==";
};
where the secret string is extracted from the private key file (it
has been truncated in this example). You won't be able to include
the key file directly into the named.conf file (with the "include"
statement) because the key files generated by dnssec-keygen are formatted
to be included into zone files and the syntax is different to what
the configuration file uses. Then, edit /etc/named.conf and configure
a zone to receive updates with this key, edit your zone definition,
and add an allow-update option:
zone "domain.tld" IN {
type master;
file "domain.tld";
allow-update { key update_key; };
};
Don't forget the reverse zone as well:
zone "1.168.192.in-addr.arpa" IN {
type master;
file "1.168.192.in-addr.arpa";
allow-update { key update_key; };
};
You can add a finer level of control with the update-policy option,
for example:
zone "1.168.192.in-addr.arpa" IN {
type master;
file "1.168.192.in-addr.arpa";
update-policy { grant update_key name * A; };
};
This would grant changes to A (Address) records only for requests
signed with the update_key key.
Now, restart your DNS server, check the syslog for any errors,
and test the updates from the command line:
/usr/local/bin/nsupdate -k Kupdate_key.+157+59751.key <<END
; set the server explicitly
server 192.168.1.3
; create a test update
update add testrec.domain.tld 86400 IN A 192.168.1.10
show
send
END
This example sends a single update to add an A record into the domain.tld
zone. You can use either "nslookup", "dig", or the "host" commands
to check that the update has been made. The DNS server will also log
an entry in syslog recording the update.
Naturally, I like to use Perl to get the job done efficiently.
Using the Net::DNS package, you can use Perl to perform updates:
#!/usr/bin/perl -w
use Net::DNS;
use strict;
my $key_name = 'update_key';
my $key = 'fxT7q+Kq8TUmZrN4edxAVeTeOmiX/3A6HQ40HcyI...g==';
# Create the update packet.
my $update = Net::DNS::Update->new('domain.tld');
# Add a TXT record to the domain
$update->push(update => rr_add('testrec.domain.tld 86400 IN TXT \
"A test record"'));
# Send the update to the zone's primary master.
my $res = Net::DNS::Resolver->new;
$res->nameservers('192.168.1.3');
# Sign the update message
$update->sign_tsig($key_name, $key);
my $reply = $res->send($update);
# Check return code
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";
}
This example creates a new TXT record called "testrec.domain.tld".
Note that you can make multiple updates within a single request packet
-- they can even include multiple add and delete operations, but only
if they are all under the same domain. Also note that dynamic updates
simply increment the zone serial number in the SOA record, it doesn't
maintain the YYYYMMDD sort of format often used for serial numbers.
Note that once you start using dynamic updates, you can't really
use manual editing of the zones anymore. The BIND server maintains
journal files that contain a record of dynamic updates, and these
must be taken into account. If you do need to edit a zone manually,
you must shut down the DNS server, remove the zone journal (.jnl)
file, edit the zone, and restart the server.
TSIG-Secured Zone Transfers
It's also very useful to secure the transfers of zone data between
master and slave DNS servers. This is particularly relevant if the
transfers are taking place across untrusted networks such as the
public Internet. As mentioned before, the data being transferred
is all in plain-text and contains no checking mechanism, so there
is a risk of data corruption or malicious interference of the data
being transferred. We can easily use TSIG keys to sign the zone
transfer data.
To begin, generate a key to be used for zone transfers. This should
not be the same as the key you created for dynamic updates. You
could create a separate key for each slave server, but in the examples
that follow I've created a single key for all slaves.
Generate a new key on the master, named "slave_xfers_key":
dnssec-keygen -r /dev/urandom -a HMAC-MD5 -b 128 -n HOST slave_xfers_key
Copy the key data string from the created key file
into /etc/named.conf on the master server:
key slave_xfers_key {
algorithm HMAC-MD5;
secret "mv0NxiVT4ho/TZbvPID+Kg==";
};
Then, permit zone transfers on the master server for clients with
the key by adding allow-transfer statements in /etc/named.conf:
zone "domain.tld" IN {
type master;
file "domain.tld";
allow-update { key update_key; };
allow-transfer { key slave_xfers_key; };
};
zone "1.168.192.in-addr.arpa" IN {
type master;
file "1.168.192.in-addr.arpa";
allow-update { key update_key; };
allow-transfer { key slave_xfers_key; };
};
Restart the master server and make sure there are no errors in the
syslog (it is quite easy to forget those semicolons in named.conf
files).
On the slave server, configure the same key for the zone in /etc/named.conf:
key slave_xfers_key {
algorithm HMAC-MD5;
secret "mv0NxiVT4ho/TZbvPID+Kg==";
};
Then, add a "server" statement specifying the TSIG key that this slave
will use when communicating to the specified server:
server 192.168.1.3 {
keys { slave_xfers_key; };
};
The definitions for the slave zones stay the same; there is no need
to configure the key in them. The slave server will automatically
use the TSIG key when requesting a transfer of any zone from the master
server whose IP address was specified in the server statement.
Now, restart the slave server and check syslog for errors. If
the TSIG-secured zone transfer was successful, you should see the
following syslog messages on the slave server:
named[3733]: zone domain.tld/IN: Transfer started.
named[3733]: transfer of 'domain.tld/IN' from 192.168.1.3#53: \
connected using 192.168.1.2#32835
named[3733]: zone domain.tld/IN: transferred serial 1: \
TSIG 'slave_xfers_key'
named[3733]: transfer of 'domain.tld/IN' from 192.168.1.3#53: \
end of transfer
and similar messages on the master server describing the transfer
of the zone using the slave_xfers_key TSIG key.
DHCP Dynamic Updates
DHCP servers can also send dynamic updates to DNS servers as they
allocate IP addresses to clients, and naturally you will want to
secure these updates with TSIG signatures. This is relatively easy
to configure when using ISC's DHCPD server as follows.
In this scenario, you have a client device (such as a laptop)
that wants to connect to networks and be allocated an IP address
(otherwise known as a DHCP lease). The client would also like to
choose its own host name on the network to be inserted into DNS.
In this example, I'll configure my Linux-based laptop to have the
name "gorgon" allocated to it when it connects to networks with
a DHCP server and dynamic DNS updates that permit client-elected
names.
There are three steps necessary to achieve this, which I will
explain below:
1. Configure the DHCP server and DNS server to use TSIG dynamic
updates.
2. Configure the DHCP server to update the DNS server each time
a lease is let for the subnet.
3. Configure the DHCP client to give the DHCP server a domain
name to insert into DNS.
Step 1. I've already configured the DNS server to permit signed
updates above. So, using the ISC DHCPD server, you can configure
the update_key by adding the following into /etc/dhcpd.conf:
key update_key {
algorithm HMAC-MD5;
secret "fxT7q+Kq8TUmZrN4edxAVeTeOmiX/3A6HQ40HcyI...g==";
}
zone 1.168.192.in-addr.arpa {
key update_key;
primary 192.168.1.3;
}
zone domain.tld {
key update_key;
primary 192.168.1.3;
}
ddns-updates on;
ddns-update-style interim;
allow client-updates;
Step 2. When the DHCP server leases an address for a subnet, instruct
it to also send a DNS update; in /etc/dhcpd.conf, add a couple of
lines to the subnet statement:
subnet 192.168.1.0 netmask 255.255.255.0 {
option domain-name "domain.tld";
option domain-name-servers 192.168.1.3;
option routers 192.168.1.1;
range 192.168.1.20 192.168.1.254;
# Dynamic DNS updates:
ddns-domainname "domain.tld";
ddns-rev-domainname "1.168.192.in-addr.arpa";
}
Step 3. Configure the DHCP-enabled clients to send their names to
the DHCP server. Most Windows clients seem to do this automatically,
but some *nix DHCP clients need configuration. If you are using the
ISC DHCP client software, this is in /etc/dhclient.conf and should
look like the following example:
send host-name "gorgon";
send fqdn.fqdn "gorgon.domain.tld.";
send fqdn.encoded on;
send fqdn.server-update on;
Once the DHCP server has been restarted, and the client requests a
DHCP lease, the server should send a TSIG-signed dynamic DNS update
to the master DNS server to add the name of the client as an A record,
and the reverse PTR record.
There are a number of ways to integrate DHCP and dynamic DNS.
An alternative to the above could be to have the clients call a
script after they get a DHCP lease and use nsupdate to send the
updates themselves. In this case, each client would need a TSIG
key in order to secure the update packets.
Conclusion
In this article, I've shown how to set up and use TSIG-signed
DNS updates, TSIG-secured zone transfers, and TSIG-secured dynamic
updates from a DHCP server. Next month, I will look at DNSSEC-secured
zones in which the actual zone resource records are signed with
cryptographic keys. This method is used to ensure that the queries
from a DNS client are valid and come from the true server for the
domain.
References
Secure Dynamic DNS HOWTO -- http://ops.ietf.org/dns/dynupd/secure-ddns-howto.html
Dynamic DNS updates with isc-dhcpd -- http://tinyurl.com/6lssd
BIND v9 ARM (Administrators Reference Manual) -- http://www.nominum.com/content/documents/bind9arm.pdf
DNSSEC Operations HOWTO -- http://www.ripe.net/disi/Course/TechCourse.pdf
Kerry Thompson is a CISSP-certified security consultant for
Open Systems Specialists in Auckland, New Zealand. He has been working
in Unix systems administration and security for many years and regularly
writes articles on IT security. Contact him at kerry@crypt.gen.nz. |