boran.com/security/sp/bind9_20010430.html
boran.com/dns
Sean Boran
This paper walks through compiling, installing and configuring a chroot'ed BIND v9 on Solaris 2.6 and 8. It also presents examples of advanced topics such as TSIGs and dynamic updates. It is specific to version 9 but we aim to help existing BIND 8 administrators realize what is involved in migrating to v9.
Although originally written in 2001, information here may still be relevant to you: I do update now and again due to positive feedback and to document some Solaris servers I still have running productively. If starting from scratch now, I'd probably use Ubuntu LTS as the base OS and use the standard packages and automated updates :-)
Document Changes:
4.Aug.08 Update for Bind 9.5.1 (see also upgrade commands. 31.Mar.08 OpenBSD note correction. v9.5.1/Solaris 8 |
|||
Your Domain Name Service is the road sign to your systems on the Internet. No matter how secure and robust your Web, mail and other servers are, compromised and corrupted DNS systems can prevent customers and legitimate users from ever reaching you.
BIND [1] is the most frequently used DNS server and maintained by the ISC. It is also known as "named", since this is the name of the actual daemon itself. As with many applications exposed to the increasingly hostile Internet environment, security weaknesses have been discovered in BIND. There are three major versions:
This article concentrates on using Bind version 9 securely.
Do we really have to worry about DNS too? Well, a compromised DNS server can pose some interesting risks:
DNS has been become a favorite target of hackers as witnessed by the automated attack tools and worms using a DNS weaknesses that appeared in winter 2001 and summer 2008.
BIND risks may be reduced with several prevention measures:
The procedure in this paper concentrates only on measures 4), 5) and 6), which should help to protect a server against possible future weaknesses in BIND.
This article has been tested on many production systems since 2001 on Solaris 2.6 and on Solaris 8.
Apart from being multi-threaded, and a complete code rewrite - which should provide better stability and security in the long term, there are other differences;
It is assumed that Solaris is up and running and appropriately hardened and that the BIND delivered with Solaris is disabled. If you have not yet hardened Solaris, check out Jass first [7]. This section runs through:
Download the distribution [1], and extract it to a subdirectory and compile. This can be done as a non-root user.
wget ftp://ftp.sunfreeware.com/pub/freeware/sparc/8/grep-2.5.1a-sol8-sparc-local.gz gunzip grep-2.5.1a-sol8-sparc-local.gz pkgadd -d grep-2.5.1a-sol8-sparc-localAfter installing the new grep, ensure 'make' finds it:
export GREP=/usr/local/bin/grep
./configure --disable-threads
./configure
So we can now compile, using GNU make:
/usr/local/bin/make
Now change to the root account, install to a temporary directory, and create a tarball:
NOTES: The strip command is optional, used to remove debugging information and symbols. This reduces the uncompressed distribution from 90MB to around 25MB (for v9.1.0). Compressed, the 9.1.3 binary tarball is 8MB. The deletion of the include files is also optional, its purpose is to save space. |
|||
su - root # allow group, but not world access umask 027 /usr/local/bin/make install DESTDIR=/tmp cd /tmp/usr/local strip bin/* sbin/* lib/* \rm -rf include tar cf - * | compress > bind9_dist.tar.Z
Next, move the bind9_dist.tar.Z
to somewhere safe and remove the /tmp/usr and possibly
the directory where you compiled BIND to clean up.
Documentation:
Included in the distribution, is the Administrators Guide (html format) in doc/arm/Bv9ARM.html. This is worth reading. Man pages are also included but they are very difficult to install on Solaris. The next release, v9.2, should have properly formatted man-pages installed, in the meantime, the man pages are available in text form [9].
The following steps assume use of the C-Shell. We start by setting a variable for the chroot environment (jail) location, and setting umask so that all files copied can be read by both groups and world. These commands are designed to be copied and pasted.
1. Set destination directories for chroot jail, everything will be installed in subdirectories of this tree.
csh
unset noclobber
set jail='/home/dns';
umask 022;
2. Set up empty directories and links for chroot environment:
mkdir $jail;
Create a link from /dns to the jail to make life easier
we'll assume through this article that "/dns" points
to the top of the chroot tree
rm /dns
ln -s $jail /dns
cd /dns;
mkdir -p {dev,opt,usr,var,etc};
mkdir -p var/{run,log,named} usr/lib;
mkdir -p usr/local/etc
mkdir -p usr/share/lib/zoneinfo;
3. Accounts.
Create a user and group account for BIND:
groupadd named;
useradd -d /dns -s /bin/false -g named -c "BIND daemon" -m named
Create an identical user and group account within the chroot:
Aside: We assume that the production BIND
configuration will be changed/managed by root. You may prefer to create a specific user
for this task at this stage, e.g. 'dnsmgr' which belongs to the 'bind' group and has write
access to /dns/etc/named.conf and /dns/var/named.
grep named /etc/passwd >> /dns/etc/passwd
grep named /etc/shadow >> /dns/etc/shadow
grep named /etc/group >> /dns/etc/group
Don't allow the BIND account to use ftp:
echo "named" >> /etc/ftpusers
Add /dns/usr/local/bin to the root PATH in /root/.cshrc or /root/.profile.
4. Install the bind distribution - first change to the directory where the tarball is
located, then:
cp bind9_dist.tar.Z /dns/usr/local;
cd /dns/usr/local;
zcat bind9_dist.tar.Z| tar xvf -
5. Copy system files needed to the chroot environment
cp /etc/{syslog.conf,netconfig,nsswitch.conf,resolv.conf,TIMEZONE} /dns/etc
Use ldd to see what shared object libraries named relies on:
ldd /dns/usr/local/sbin/named
Copy the files listed by ldd, for example on Solaris 8:
cp -p /usr/lib/libnsl.so.1 \
/usr/lib/libsocket.so.1 /usr/lib/libc.so.1 \
/usr/lib/libthread.so.1 /usr/lib/libpthread.so.1 \
/usr/lib/libdl.so.1 /usr/lib/libmp.so.2 \
/usr/lib/ld.so.1 /usr/lib/nss_files.so.1 \
/usr/platform/SUNW,UltraAX-i2/lib/libc_psr.so.1 \
/dns/usr/lib
Solaris 2.6:
cp -p /usr/lib/libnsl.so.1 \
/usr/lib/libsocket.so.1 /usr/lib/libc.so.1 \
/usr/lib/libdl.so.1 /usr/lib/libmp.so.2 /dns/usr/lib
On a Solaris 2.6 UltraSPARC, ldd also listed the following as being necessary
cp /usr/platform/SUNW,Ultra-250/lib/libc_psr.so.1 /dns/usr/lib
Experience has shown the following are also needed:
cp /usr/lib/ld.so.1 /usr/lib/nss_files.so.1 /dns/usr/lib
("Experience" means that first attempts didn't work, but by running BIND with
truss one could see what libraries were being sought after.)
Copy over Timezone files (for example MET, here in Europe):
mkdir -p /dns/usr/share/lib/zoneinfo;
cp -p /usr/share/lib/zoneinfo/MET /dns/usr/share/lib/zoneinfo/MET
Set up devices for communication, console, syslog, etc.
cd /dns/dev
mknod tcp c 11 42
mknod udp c 11 41
mknod log c 21 5
mknod null c 13 2
mknod zero c 13 12
chgrp sys null zero
chmod 666 null
mknod conslog c 21 0
mknod syscon c 0 0
chmod 620 syscon
chgrp tty syscon
chgrp sys conslog
For Bind v9.5.1 create /dev/poll
cd /dns/dev
mknod poll c 138 0
chgrp sys random
chmod 644 random
Optional for local syslog messages:
Create a loop-back for syslog. The following
was suggested by a reader, although I've not found it necessary.
mkdir /dns/etc/.syslog_door
mount -F lofs /etc/.syslog_door /dns/etc/.syslog_door
On Solaris 8/9, provide access to /dev/random,
by
creating a loopback mount for the /dns
jail (which I use for historical reasons...):
mkdir /dns/dev/random
mount -F lofs /dev/random /dns/dev/random
or creating a device within the DNS jail (first check the current
minor/major device number with ls -al
/devices/pseudo/random\@0\:random
):
cd /dns/dev
mknod random c 240 0
chgrp sys random
chmod 644 random
Create a directory for DNS data; we assume it is in /var/named:
mkdir -p /dns/var/named;
cd /dns/etc
touch named.conf
chown root:named named.conf
chmod 640 named.conf
vi named.conf
So what do you put in named.conf? We start off with a simple example to get BIND running: lookups of 'localhost', reverse lookups of 127.0.0.1 and a simple domain test1.com
We'll go into more detail on DNS configuration below, at this stage we concentrate on getting BIND running.
After copying these files, verify the syntax:
Primary + secondary:
chroot/dns /usr/local/sbin/named-checkconf /etc/named.conf
chroot
/dns /usr/local/sbin/named-checkzone local /var/named/localhost.zone
chroot
/dns /usr/local/sbin/named-checkzone local /var/named/localhost.rev
The
localhost.zone
file may complain about a missing SOA and NS records. Ignore these.
Primary:
/dns/usr/local/sbin/named-checkzone test1.com /dns/var/named/test1.com
Next, we set permissions on files, so that root owns files and named can read all files and write some files. Then, disable any SUID/SGID files.
The PID file is put in /var/run and not /usr/local, because we don't want the named user to be able to write to /usr/local/etc (and hence named.conf). The location of the PID file is specified in named.conf.
cd /dns
chgrp -R named *
# remove group write from var, write access to opt and usr
chmod -R g-w var;
chmod -R a-w opt usr;
# For secondaries, allow named to create/change data files:
chown -R root:named /dns/var/named;
chmod 770 /dns/var/named;
# For primaries, allow
named
read-only access, it does not need write access to data files:
chown -R root:named /dns/var/named;
chmod 750 /dns/var/named;
chmod -R go-w /dns/var/named;
# Note: I lied a little bit... if named needs to write a debug file, or dump statistics, it will need write
# access to /dns/var/named. So you choose if you want a very tight, or more relaxed setup:
chmod 770 /dns/var/named;
# Create empty log and pid files:
touch var/log/all.log var/run/named.pid;
chown named:named var/log/all.log var/run/named.pid;
# Allow named user/group to write logs and pid files:
chgrp -R named /dns/var/log /dns/var/run;
chmod 770 /dns/var/run /dns/var/log;
chmod -R o-rwx /dns/var/run /dns/var/log;
# Allow named to access BIND config file:
chgrp named /dns/etc;
chown root:named /dns/etc/named.conf;
chmod 640 /dns/etc/named.conf;
chmod 755 /dns/etc;
# Remove SUID or SGID bits, if any exist:
find . -type f -exec chmod ug-s {} \;
# Remove world access:
chmod -R o-rwx * /dns/usr
See footnote [8] for an example of an "ls -alR" on a production DNS primary.
OK, we have DNS configuration is in /dns/etc/named.conf, zone files in /dns/var/named (where /dns is a link to the top of the chroot tree, e.g. /export/home/dns), let's try and start BIND!
tail -f /var/adm/messages |grep named
&tail -f /var/log/daemonlog |grep named
&/usr/sbin/chroot /dns /usr/local/sbin/named -u named
/dns/usr/local/bin/dig @localhost 127.0.0.1
/dns/usr/local/bin/dig @localhost localhost
/dns/usr/local/bin/dig @localhost localhost mx
/dns/usr/local/bin/dig @localhost localhost ns
/dns/usr/local/bin/dig @localhost www.test1.com
/dns/usr/local/bin/dig @localhost www1.test1.com
/dns/usr/local/bin/dig @localhost test1.com ns
/dns/usr/local/bin/dig @localhost test1.com mx
kill -1 `cat /dns/var/run/named.pid`
Change the /etc/rc2.d/S72inetsvc entries for named to disable Sun's default. Then create a startup file /etc/init.d/dns and setup links:
ln -s /etc/init.d/dns /etc/rc2.d/S50dns
ln -s /etc/init.d/dns /etc/rc2.d/K50dnsMy example startup file /etc/init.d/dns has a few bells and whistles you may like to check out, for example it crates and mounts /dev/random within the /dns chroot environment).
Client:
Use dig or host or nslookup to check server results. Dig is better, as nslookup needs to find a PTR record for the DNS server; otherwise it won't start. You'll also find that many implementations of nslookup don't work with IPv6.
Check /etc/nsswitch.conf and /etc/resolv.conf.
Start nslookup with the "-d2" option to get buckets of debugging info, or start it without any arguments and type "help" at the prompt. There is also a "debug" command from the interactive prompt.
Try killing the nscd daemon.
Server
Send a HUP signal to named, to reread the config file after changes.
kill -HUP `cat /dns/var/run/named.pid`Look at the syslog entries. Typically logs are found in the syslog "daemon" section.
Run a check on the configuration:
chroot /dns /usr/local/sbin/named-checkconf /etc/named.conf
Run a check on a specific zone:
cd /dns/var/named; named-checkzone myzone.com zonefile
Named has a "-d X" option, which switches on debugging (X is a number indicating the debug level), for example:
/usr/sbin/chroot /dns /usr/local/sbin/named -u named -d3
Run named in the foreground and log to stderr (i.e. the screen):
/usr/sbin/chroot /dns /usr/local/sbin/named -u named -g
To get statistics from the name server into /dns/named/named.stats:
rndc stats
If the logs indicate permission problems, check your file permissions against the example of an "ls -alR" on a production DNS primary [8].
If domain transfers are not working on a secondary:
Make sure the named user has write access to /dns/var/named on the secondary
Try manual zone transfers, for example:
/dns/usr/local/bin/dig @SERVER DOMAIN.NAME axfr
/dns/usr/local/bin/dig @192.168.128.34 test1.com axfrMake sure the option forward only has not been enabled by mistake in named.conf.
Make sure that the filesystem where you do your chroot'ing is not mounted nosuid, otherwise /dev/zero won't work.
truss is very useful for following program execution, for example:
truss /dns/usr/local/sbin/named -u named
truss /usr/sbin/chroot /dns /usr/local/sbin/named -u named
Check the domains using the IP-Plus tool 4.
If you suspect that the chroot is causing problems
Read the sections Known Problems and Configuration Notes below.
Check the BIND-users email list [10].
Read the book DNS and BIND [5].
Copy to /dns/var/named: test1.com, rev.192.168.128
Copy to /dns/etc/named.conf: named.conf.primary
Copy to /dns/etc/named.conf: named.conf.secondary
Notes:
In this case, we copy the /dns/var/named/test1.com configuration above to test2.com, but the domain names are changed. The new zone file /dns/var/named/test2.com must belong to named and be writeable by named.
chown named.named /dns/var/named/test2.com;
chmod 600 /dns/var/named/test2.com
In named.conf we add a few lines that allow dynamic updates from the IP address 192.168.128.33 only.
acl "updaters" {
192.168.128.33;
};
zone "test2.com" {
type master;
file "test2.com";
allow-update { updaters; };
};
When we restart named, the following entry appears in syslog warning us that the method chosen above is not the most secure for dynamic updates. Our next example will improve on this.
/usr/local/sbin/named: zone 'test2.com' allows up dates by IP address, which is
insecure
Updates are only allowed from 192.168.128.33 and we assume the primary has the address 192.168.128.34, so we have to run the 'nsupdate' program from 192.168.128.33. The nsupdate program reads the update commands from a file or standard input, hence we use the "<<" redirection symbols in the following examples:
# add "host1" to the domain
/dns/usr/local/bin/nsupdate <<EOF
server 192.168.128.34 53
update add host1.test2.com 3600 A 10.1.1.1
EOF
echo $status
/dns/usr/local/bin/nslookup -sil host1.test2.com 192.168.128.34
# remove "host1" from the domain
/dns/usr/local/bin/nsupdate <<EOF
server 192.168.128.34 53
update delete host1.test2.com A
EOF
echo $status
/dns/usr/local/bin/nslookup -sil host1.test2.com 192.168.128.34
# First delete the host (if it exists), then add it:
/dns/usr/local/bin/nsupdate <<EOF
server 192.168.128.34 53
update delete host1.test2.com A
update add host1.test2.com 3600 A 10.1.1.1
EOF
echo $status
/dns/usr/local/bin/nslookup -sil host1.test2.com 192.168.128.34
Dynamic updates in the previous example are usually to a list of IP addresses (via the ACL mechanism) which correspond to specific servers for a zone. Since only IP addresses are used, this mechanism is open to IP spoofing. BIND allows additional authentication of the servers in the ACL list. A key is configured on each server and used to sign messages exchanged between them. Its important that the server times are synchronized. If the communication is not authenticated with the correct key, no updates may take place.
In this case, we copy the /dns/var/named/test2.com configuration above to test3.com, but the domain names are changed.
Let's look at an example where we use TSIG to authenticate updates.
a) Generate an MD5 key, which will be used as a shared secret. The "dnssec-keygen" tool is used. The key is written to a file.
/dns/usr/local/sbin/dnssec-keygen -a HMAC-MD5 -b 128 -n HOST updater1
Which creates files like: Kupdater1.+157+08531.key and Kupdater1.+157+08531.private. What interests us is the 'Key' entry in the private file, which looks something like k2Pb7gEcbXg6ZosOqAbV8A==.
So we add the following to /dns/etc/named.conf:
// TSIG keys
key updater1 { algorithm hmac-md5; secret "k2Pb7gEcbXg6ZosOqAbV8A=="; };
And in the zone definition for test3.com:
allow-update { key updater1; };
Testing updates:
a) We try to add a "host1" to the domain in the usual manner: this will fail (exist status 2, with an "update denied" entry in the primary's log), because we have tried an update without a TSIG key exchange.
/dns/usr/local/bin/nsupdate <<EOF
server 192.168.128.34 53
update add host1.test3.com 3600 A 10.1.1.1
EOF
echo $status
b) This time we do it correctly - add a "host1" to the domain and provide the TSIG key on the command line.
/dns/usr/local/bin/nsupdate -y
"updater1:k2Pb7gEcbXg6ZosOqAbV8A=="
<<EOF
server 192.168.128.34 53
update add host1.test3.com 3600 A 10.1.1.1
EOF
echo $status
c) Nsupdate can use a TSIG key also be stored in a file, for example Kupdater1.+157+08531.private which we generated above. The file Kupdater1.+157+08531.key must also be in the same directory or in the PATH.
/dns/usr/local/bin/nsupdate -k Kupdater1.+157+08531.private <<EOF
server 192.168.128.34 53
update add host1.test3.com 3600 A 10.1.1.1
EOF
echo $status
allow-update { key updater1; updaters};
The named.conf file consists of options, logging, ACL, server and Zone sections. Some of the directives are:
logging {
channel syslog_errors {syslog daemon; severity info; };
channel debug_file {file "debuglog"; severity dynamic;};
category queries {debug_file; };
};
/dns/usr/local/sbin/rndc querylog
category edns-disabled { null; };
zone "10.IN-ADDR.ARPA" { type forward; forwarders { 1.2.3.4; }; forward only; };Or add an empty zone
zone "10.IN-ADDR.ARPA" { type master; file "empty"; };The file "empty" conatins:
@ 10800 IN SOAThis should be done for 16.172.IN-ADDR.ARPA, 31.172.IN-ADDR.ARPA and 168.192.IN-ADDR.ARPA too.. . ( 1 3600 1200 604800 10800 ) @ 10800 IN NS .
dig @NAMESERVER version.bind chaos txt
transfer-source A.B.C.D
) for the external
namespace. match-clients
for the internal view.176.17.17.8
as the special address for external zone transfers.
view "internal" {// This should match our internal networks.
match-clients { !176.17.17.8; 10.0.0.0/8; }; // important to exclude
176.17.17.8 from the Internal view
allow-transfer { internal-nameservers; };
// Provide recursive service to internal clients only.
recursion yes;
// Provide a complete view of the example.com zone
// including addresses of internal hosts.
zone "example.com" {
type master;
file "example-internal.db";
};
zone "localhost" {
type master;
file "localhost.zone";
notify no;
allow-update { none; };
};
};
view "external" {
match-clients { any; };
// Refuse recursive service to external clients.
//transfer-source 176.17.17.8; // On secondary: Network Interface for
Internal ZoneTx
recursion no;
// Provide a restricted view of the example.com zone
// containing only publicly accessible hosts.
zone "example.com" {
type master;
file "example-external.db";
};
zone "localhost" {
type master;
file "localhost.zone";
notify no;
allow-update { none; };
};
};
Bind v9 provides the rndc tool for stopping, starting, reloading the named daemon. In this section we examine ways of using rndc and document problems and limitations.
Bind v8 included the ndc tool, so what is the difference? Well, rndc (v9) uses TCP sockets (default 953) as opposed to ndc's (v8) UNIX-domain sockets. Ndc didn't work in a chroot environment, rndc does.
/dns/usr/local/sbin/dnssec-keygen -a hmac-md5 -b 128 -n user rndc
key key_rndc {algorithm hmac-md5; secret "NsuYsQ0Pp7J3LaOsVHr0uw=="; };
controls {inet 192.168.128.34 port 953 allow {localhost;} keys {key_rndc;} ;
};
sh /etc/init.d/dns stop
sh /etc/init.d/dns start
You should see a message in the logs like:
/usr/local/sbin/named[12993]: command channel listening on 19 2.168.128.34#953
key key_rndc {
algorithm hmac-md5;
secret "NsuYsQ0Pp7J3LaOsVHr0uw==";
};
options {
default-server 192.168.128.34;
default-key key_rndc;
};
Protect this file:
chmod 600 /etc/rndc.conf
To reload the named server configuration:
/dns/usr/local/sbin/rndc reload
A message like 'rndc: reload command successful' should appear.Let's reload a specific zone only:
/dns/usr/local/sbin/rndc reload test1.com
Let's force a secondary to update from its master:
/dns/usr/local/sbin/rndc refresh test1.com
Write some statistics to /dns/var/named/named.stats:
/dns/usr/local/sbin/rndc stats
Switch on logging of queries on or off:
/dns/usr/local/sbin/rndc querylog
Write DNS cache contents to /dns/var/named/named_dump.db:
/dns/usr/local/sbin/rndc dumpdb
Nice things about rndc:
Disadvantages:
BINDv9 and Internet Security
Fingerprinting Bind 9
(discussion)BIND Manual
http://www.bind9.net/manuals
Securing an Internet Name Server: Presentation
Cricket Liu
www.cert.org/archive/pdf/dns.pdf
Dnsjava
is dns server and client in Java. I found it interesting as a basis for programming dynamic DNS updates in Java.Thanks to Rejane Forré for proof-reading, David "Tale" Lawrence and Brian Wellington of Nominum for precise feedback and help.
Brian Friday, 6.mar.02
debug_file:
Instead of putting this into the named directory you could put this in the var directory by putting "/var/log/debuglog" in the file area of the channel debug_file section of the named.conf file./var/named directory usage:
I did take some tips from the linux chroot guide one of them was putting a directory under /var/named called "slave" making only that directory writeable by named. /var/named remains writeable only by root but this slave directory can be written by named. Using this you could be a master/slave for some zones and still retain a decent security level.RNDC:
I discovered it was easier to use the rndc-confgen application then follow the instructions you have for enabling rndc. The rndc-confgen actually prints out the code which you should put in the /etc/rndc.conf and named.conf. Not really a big deal just a little shortcut.
Boran Consulting, Sean Boran,