Securing your DNS information with Transaction Signatures (TSIG)
Introduction
The Domain Name System (DNS) is a replicated, distributed, hierarchical database of information that is a core service needed for the modern internet to function. If you're new to the Domain Name System please read Thomas Bridge's article. This article is primarily aimed at those familiar with basic DNS concepts and the operation and configuration of a DNS server.
This article was written for the The Irish Linux Users Group (ILUG). The ILUG copy of this article is on linux.ie.
This article concentrates on BIND, the de-facto standard implementation of DNS. Other implementations can achieve the same results using these directions, however the instructions and examples below are for administrators of a BIND 8.x or BIND 9.x nameserver.
What is TSIG and why do I want it?
The DNS works on a question-answer model. If a client needs information from the DNS it sends a question to a DNS server and the server returns an answer. Until recently it was only possible for a server to examine a question and determine whether or not to answer it based on the IP address the question originated from. This is not ideal. Authentication using source IP address alone is considered insecure. Transaction Signatures, or TSIG for short, add cryptographic signatures as a method of authenticating a DNS conversation. It uses a shared secret to establish trust between the communicating parties.
TSIG is used to ensure that DNS information purporting to be from a certain server is actually from that server. I have mostly put it to use to authenticate zone transfers between master and slave nameservers. I want to be sure that my slave nameserver is never fooled into accepting a copy of my zone from an imposter who spoofs my master nameserver's IP address.
Transactions signatures are defined in RFC 2845.
For the examples below we will presume to be using TSIG to authenticate DNS traffic between two servers; server1 (10.0.0.1) and server2 (10.0.0.2).
Create your secret
TSIG uses a shared secret which is incorporated into an MD5 hash of the information to be signed. BIND comes with a tool to create suitable secrets; dnskeygen. In TSIG parlance secrets are also called keys. dnskeygen takes many options -- run it with no flags to see a list.
$ dnskeygen -H 256 -h -n 2000011501.linuxservers.tsigkey.
Generating 256 bit HMAC-MD5 Key for 2000011501.linuxservers.tsigkey.
Generated 256 bit Key for 2000011501.linuxservers.tsigkey. id=0 alg=157 flags=513
$ ls *tsigkey*
K2000011501.linuxservers.tsigkey.+157+00000.key
K2000011501.linuxservers.tsigkey.+157+00000.private
$ cat K2000011501.linuxservers.tsigkey.+157+00000.private
Private-key-format: v1.2
Algorithm: 157 (HMAC)
Key: HW/WyHCn8q312B7tzjAx3X2XmmZG86AqHQmn+QyB6CA=
-H 256 sets the key size, in the range 1-512. -h requests creation of a host key. -n 2000011501.linuxservers.tsigkey. specifies the name of the key.
The name of each key needs to be unique. i.e. two keys should not share the same name, hence the slightly unusual name I've given it. That said, you should try to give them names that will be meaningful to you -- it will make your life easier. The generated key will be saved into two files both of whose names will begin with the letter K followed by the name of the key and some other text. The file ending in .private is slightly easier to read though they both contain the same secret (in different formats). The key/secret is the sequence of characters after Key: .
Tell your nameserver about the key
To add the new key to your nameserver configuration use a key clause in the nameserver configuration file. The file is called named.conf and is usually located in /etc. Add the following to the named.conf file (changing the key name and secret to match your own):
key 2000011501.linuxservers.tsigkey. {
algorithm "hmac-md5";
secret "HW/WyHCn8q312B7tzjAx3X2XmmZG86AqHQmn+QyB6CA=";
};
The key clause should be included in the configuration file of the nameservers that will use this key to authenticate. We want server1 and server2 to use this secret so the above clause should be included on both machines.
Tell your nameserver when to use the key
The nameserver must be told when it should use the key. A server clause does this. Using this clause we can direct the nameserver to use a certain key when communicating with a given IP address. On each server add a server clause specifying the IP address of the other machine and the name of the key to use.
On server1 use:
server 10.0.0.2 { # 10.0.0.2 is the IP address of server2
keys {
"2000011501.linuxservers.tsigkey.";
};
};
and on server2 use:
server 10.0.0.1 { # 10.0.0.1 is the IP address of server1
keys {
"2000011501.linuxservers.tsigkey.";
};
};
Use ndc reconfig to get each nameserver to read its configuration file. It should now be aware of the secrets and of the servers for which to use them. Watch the nameserver's log files to see if it logs any warnings or errors.
You're done! To test it, update a zone and see if your slave nameserver will transfer it. Alternatively, change a character of the secret on the master nameserver, reload the configuration and try to get the slave to transfer the zone. It should log messages about failed verifications.
Other important points
Your secret is just that; a secret. You need to place it onto the two servers in a secure fashion. You need to set appropriate modes on named.conf so that it can't be read from named.conf by unauthorised local users.
Use NTP or some other system to keep good time on your nameservers. If time on the machines sharing a secret gets too far out of whack signature verification will fail. Make sure you add the elements above to the named.conf in the order above. Specifically make sure a key clause appears before any server clause that references it in named.conf.
Verifying a TSIG requires writing a temporary file. Make sure that named can write to its default directory.
Microsoft's implementation of TSIG doesn't use the algorithim from
RFC 2845 (HMAC-MD5) *sigh*
Microsoft GSS-TSIG is non-standard and will not inter-operate with
BIND.
(c) James Raftery
17th January 2001.
This article has also appeared on http://www.start-linux.com/