scott at wunsch.org
This is the Chroot-BIND8 HOWTO; see Where? for the master site, which contains the latest copy. It is assumed that you already know how to configure and use BIND (the Berkeley Internet Name Domain). If not, I would recommend that you read the DNS HOWTO first. It is also assumed that you have a basic familiarity with compiling and installing software on your UNIX-like system.
This document describes some extra security precautions that you can take when you install BIND. It explains how to configure BIND so that it resides in a ``chroot jail'', meaning that it cannot see or access files outside its own little directory tree. We shall also configure it to run as a non-root user.
The idea behind chroot is fairly simple. When you run BIND (or
any other process) in a chroot jail, the process is simply unable
to see any part of the filesystem outside the jail. For example,
in this document, we'll set BIND up to run chrooted to the
directory /chroot/named. Well, to BIND, the contents
of this directory will appear to be /, the root
directory. Nothing outside this directory will be accessible to
it. You've probably encounted a chroot jail before, if you've
ever ftped into a public system.
The idea behind running BIND in a chroot jail is to limit the amount of access any malicious individual could gain by exploiting vulnerabilities in BIND. It is for the same reason that we run BIND as a non-root user.
This should be considered as a supplement to the normal security precautions (running the latest version, using access control, etc.), not a replacement for them.
If you're interested in DNS security, you might also be interested in a few other products. Building BIND with StackGuard would probably be a good idea for even more protection. Using it is easy; it's just like using ordinary gcc. Also, DNScache is a secure replacement for BIND, written by Dan Bernstein. Dan is the author of qmail, and DNScache appears to follow a similar philosophy.
The latest version of this document is always available from the web site of the Linux/Open Source Users of Regina, Sask., at http://www.losurs.org/docs/howto/Chroot-BIND8.html.
There is now a Japanese translation of this document,
maintained by nakano at apm.seikei.ac.jp. This is
available at
http://www.linux.or.jp/JF/JFdocs/Chroot-BIND8-HOWTO.html.
BIND is available from the Internet Software Consortium at http://www.isc.org/bind.html. As of this writing, the current version of BIND 8 is 8.2.4. BIND 9.x has now been released, and has been around for a little while. You may consider upgrading to it; the chroot process is certainly much simpler and cleaner. If you are running BIND 9, then you want the Chroot-BIND HOWTO, which should be available from the same location as this document.
Keep in mind that there are known security holes in all versions of BIND 8 less than 8.2.3, so make very sure that you're running the latest version!
I wrote this document based on my experiences in setting BIND up in a chroot environment. In my case, I already had an existing BIND installation in the form of a package that came with my Linux distribution. I'll assume that most of you are probably in the same situation, and will simply be transferring over and modifying the configuration files from your existing BIND installation, and then removing the package before installing the new one. Don't remove the package yet, though; we may want some files from it first.
If this is not the case for you, you should still be able to follow this document. The only difference is that, where I refer to copying an existing file, you first have to create it yourself. The DNS HOWTO may be helpful for this.
These steps worked for me, on my system. Your mileage may vary. This is but one way to approach this; there are other ways to set the same thing up (although the general approach will be the same). It just happens that this was the first way that I tried that worked, so I wrote it down.
My BIND experience to date has been installing on Linux servers. However, most of the instructions in this document should be easily applicable to other flavours of UNIX as well, and I shall try to point out differences of which I am aware.
As mentioned in the introduction, it's not a good idea to run
BIND as root. So, before we begin, let's create a separate user
for BIND. Note that you should never use an existing generic user
like nobody for this purpose. However, some
distributions, such as SuSE and Linux Mandrake have started
providing a specific user (generally called named);
you can simply adapt this user for our purposes, if you like.
This requires adding a line something like the following to
/etc/passwd:
And one like this tonamed:x:200:200:Nameserver:/chroot/named:/bin/false
/etc/group:
This creates a user and group callednamed:x:200:
named for BIND. Make sure that the UID and GID (both
200 in this example) are unique on your system. The shell is set
to /bin/false because this user will never need to
log in.
Now, we must set up the directory structure that we will use
for the chroot jail in which BIND will live. This can be anywhere
on your filesystem; the truly paranoid may even want to put it on
a separate volume. I shall assume that you will use
/chroot/named. Let's start by creating the following
directory structure:
/chroot +-- named +-- bin +-- dev +-- etc | +-- namedb +-- lib +-- var +-- run
Assuming that you have already done a conventional
installation of BIND and are using it, you will already have an
existing named.conf and zone files. These files must
now be moved (or copied, to be safe) into the chroot jail, so
that BIND can get at them. named.conf goes in
/chroot/named/etc, and the zone files can go in
/chroot/named/etc/namedb. For example:
# cp -p /etc/named.conf /chroot/named/etc/ # cp -a /var/named/* /chroot/named/etc/namedb/
BIND will likely need to write to the namedb
directory, and probably some of the files in it. For example, if
your DNS serves as a slave for a zone, it will have to update
that zone file. Also, BIND can dump statistical information, and
does so in this directory. For that reason, you should probably
make the named user the owner of this directory and
its contents:
BIND will also need to write to the# chown -R named:named /chroot/named/etc/namedb
/var/run directory, to put its pidfile and ndc
socket there, so let's allow it to do so:
# chown named:named /chroot/named/var/run
Once BIND is running in the chroot jail, it will not be able to access files outside the jail at all. However, it needs to access a few key files, such as the system's C library. Exactly what libraries are required will depend on your flavour of UNIX. For most modern Linux systems, the following commands will be sufficient to put the necessary libraries in place:
As an alternative, you could simply build statically-linked versions of the BIND binaries to put in your chroot jail. You should also copy# cd /chroot/named/lib # cp -p /lib/libc-2.*.so . # ln -s libc-2.*.so libc.so.6 # cp -p /lib/ld-2.*.so . # ln -s ld-2.*.so ld-linux.so.2
ldconfig into the
jail, and run it to create an etc/ld.so.cache for
the jail environment. The following commands could take care of
this:
# cp /sbin/ldconfig /chroot/named/bin/ # chroot /chroot/named /bin/ldconfig -v
BIND needs one more system file in its jail: good ol'
/dev/null. Again, the exact command necessary to
create this device node may vary from system to system; check
your /dev/MAKEDEV script to be sure. Some systems
may also require /dev/zero. For most Linux systems,
we can use the following command:
# mknod /chroot/named/dev/null c 1 3
Finally, you need a couple extra files in the
/etc directory inside the jail. In particular, you
must copy /etc/localtime (this sometimes known as
/usr/lib/zoneinfo/localtime on some systems) in
there so that BIND logs things with the right time on them, and
you must make a simple group file with the
named group in it. The following two commands will
take care of this:
# cp /etc/localtime /chroot/named/etc/ # echo 'named:x:200:' > /chroot/named/etc/group
Keep in mind that the GID, 200 in this example, must match the
one you defined in the real /etc/group above.
Unlike a conventional jailbird, BIND can't just scribble its
log entries on the walls :-). Normally, BIND logs through
syslogd, the system logging daemon. However, this
type of logging is performed by sending the log entries to the
special socket /dev/log. Since this is outside the
jail, BIND can't use it any more. Fortuantely, there are a couple
options to work around this.
The ideal solution to this dilemma requires a reasonably
recent version of syslogd which supports the
-a switch introduced by OpenBSD. Check the manpage
for your syslogd(8) to see if you have such a
version.
If you do, all you have to do is add the switch ``-a
/chroot/named/dev/log'' to the command line when you
launch syslogd. On systems which use a full
SysV-init (which includes most Linux distributions), this is
typically done in the file /etc/rc.d/init.d/syslog.
For example, on my Red Hat Linux system, I changed the line
todaemon syslogd -m 0
daemon syslogd -m 0 -a /chroot/named/dev/log
On Caldera OpenLinux systems, they use a daemon launcher
called ssd, which reads configuration from
/etc/sysconfig/daemons/syslog. You simply need to
modify the options line to look like this:
OPTIONS_SYSLOGD="-m 0 -a /chroot/named/dev/log"
Similarly, on SuSE systems, I'm told that the best place to
add this switch is in the /etc/rc.config file.
Changing the line
to readSYSLOGD_PARAMS=""
should do the trick.SYSLOGD_PARAMS="-a /chroot/named/dev/log"
Once you've figured out how to make this change for your
system, simply restart syslogd, either by killing it
and launching it again (with the extra parameters), or by using
the SysV-init script to do it for you:
# /etc/rc.d/init.d/syslog stop # /etc/rc.d/init.d/syslog start
Once it's been restarted, you should see a ``file'' in
/chroot/named/dev called log, that
looks something like this:
srw-rw-rw- 1 root root 0 Mar 13 20:58 log
If you have an older syslogd, then you'll have to
find another way to do your logging. There are a couple programs
out there, such as holelogd, which are designed to
help by acting as a ``proxy'' and accepting log entries from the
chrooted BIND and passing them out to the regular
/dev/log socket.
Alteratively, you can simply configure BIND to log to files instead of going through syslog. See the BIND documentation for more details if you choose to go this route.
You should be able to find the BIND source by visiting
http://www.isc.org/bind.html.
You need the bind-src.tar.gz package. Be sure to get
the latest version!
Things can get a bit confusing at this point, because different parts of the BIND package will be referring to the same directories by different names (depending on whether or not they're running inside the jail). I'll try not to confuse you too much :-).
The main directory that we have to worry about here is
/var/run, because its contents are required for both
the main named daemon (inside the jail), and the
ndc utility (on the outside). We'll start by setting
everything up to find this directory from the outside world. To
do this, we need to modify
src/port/linux/Makefile.set (substitute your port's
directory if you're not running Linux), and change the line
toDESTRUN=/var/run
While you're in there, you may want to change the other destination paths fromDESTRUN=/chroot/named/var/run
/usr to
/usr/local.
Now everything should be able to find that directory... except
the named daemon itself, to which it's still just
/var/run inside the jail. We can get around this by
making a small change in the named source. In the
file src/bin/named/named.h, find the line
and add the following line immediately after it#include "pathnames.h"
This way,#define _PATH_NDCSOCK "/var/run/ndc"
named will ignore our
definition of DESTRUN over in
Makefile.set and use the correct location (from its
perspective in the chroot jail). You will notice some warnings
about redefinitions of _PATH_NDCSOCK when you do the build; just
ignore them.
You should now be able to compile BIND as normal, following
the instructions in the INSTALL file. At this stage,
we only want to compile BIND, not install it. Don't go too far
when following the INSTALL file. Essentially, it's
just make clean, make depend, and
make.
I should mention that if you have an existing installation of
BIND, such as from an RPM, you should probably remove it before
installing the new one. On Red Hat systems, this probably means
removing the packages bind and
bind-utils, and possibly bind-devel and
caching-nameserver, if you have them.
You may want to save a copy of the init script (e.g.,
/etc/rc.d/init.d/named), if any, before doing so;
it'll be useful later on.
This is the easy part :-). Just run make install
and let it take care of it for you. You may want to chmod
000 /usr/local/sbin/named afterwards, to make sure you
don't accidentally run the non-chrooted copy of BIND. (This is
/usr/sbin/named if you didn't tell it to go in
/usr/local/sbin like I suggested.)
Only two parts of the package have to live inside the chroot
jail: the main named daemon itself, and
named-xfer, which it uses for zone transfers. You
can simply copy them in from the source tree:
# cp src/bin/named/named /chroot/named/bin # cp src/bin/named-xfer/named-xfer /chroot/named/bin
If you have an existing init script from your distribution, it
would probably be best simply to modify it to run
/chroot/named/bin/named, with the appropriate
switches. The switches are... (drumroll please...)
-u named, which tells BIND to run as the user
named, rather than root.-g named, to run BIND under the group
named too, rather than root or
wheel.-t /chroot/named, which tells BIND to chroot
itself to the jail that we've set up.The following is the init script I use with my Red Hat 6.0
system. As you can see, it is almost exactly the same as the way
it shipped from Red Hat. I have also modified the ndc
restart command so that it restarts the server properly,
and keeps it chrooted. You should probably do the same in your
init script, even if you don't copy this one.
#!/bin/sh # # named This shell script takes care of starting and stopping # named (BIND DNS server). # # chkconfig: 345 55 45 # description: named (BIND) is a Domain Name Server (DNS) \ # that is used to resolve host names to IP addresses. # probe: true # Source function library. . /etc/rc.d/init.d/functions # Source networking configuration. . /etc/sysconfig/network # Check that networking is up. [ ${NETWORKING} = "no" ] && exit 0 [ -f /chroot/named/bin/named ] || exit 0 [ -f /chroot/named/etc/named.conf ] || exit 0 # See how we were called. case "$1" in start) # Start daemons. echo -n "Starting named: " daemon /chroot/named/bin/named -u named -g named -t /chroot/named echo touch /var/lock/subsys/named ;; stop) # Stop daemons. echo -n "Shutting down named: " killproc named rm -f /var/lock/subsys/named echo ;; status) /usr/local/sbin/ndc status exit $? ;; restart) /usr/local/sbin/ndc -n /chroot/named/bin/named "restart -u named -g named -t /chroot/named" exit $? ;; reload) /usr/local/sbin/ndc reload exit $? ;; probe) # named knows how to reload intelligently; we don't want linuxconf # to offer to restart every time /usr/local/sbin/ndc reload >/dev/null 2>&1 || echo start exit 0 ;; *) echo "Usage: named {start|stop|status|restart}" exit 1 esac exit 0
On Caldera OpenLinux systems, you simply need to modify the variables defined at the top, and it will apparently take care of the rest for you:
NAME=named DAEMON=/chroot/named/bin/$NAME OPTIONS="-t /chroot/named -u named -g named"
You will also have to add or change a few options in your
named.conf to keep the various directories straight.
In particular, you should add (or change, if you already have
them) the following directives in the options
section:
Since this file is being read by thedirectory "/etc/namedb"; pid-file "/var/run/named.pid"; named-xfer "/bin/named-xfer";
named daemon, all the paths are of course relative
to the chroot jail.
Some people have also reported having to add an extra block to
their named.conf to get ndc working
properly:
controls { unix "/var/run/ndc" perm 0600 owner 0 group 0; };
Everything should be set up, and you should be ready to put your new, more secure BIND into action. Assuming you set up a SysV-style init script, you can simply launch it as:
Make sure you kill any old versions of BIND still running before doing this.# /etc/rc.d/init.d/named start
If you take a look at your logs, you should find the
initialisation messages that BIND spits out when it loads. (If
not, there's a problem with your logging
configuration that you need to fix.) Amongst those messages,
BIND should tell you that it chrooted successfully, and that it
is running as the user and group named. If not, you
have a problem.
You can go take a nap now ;-).
So, you had BIND 8.2.2_P7 all nicely chrooted and tweaked to your taste... and then you hear this nasty rumour that there's a remotely-exploitable root hole in that version too, and you need to upgrade to 8.2.3 right away. Do you have to go through this whole long process to install this new version?
Nope. In fact, you really just need the section on Compiling BIND and the first two parts of the section on Installing BIND (installing the binaries outside and inside the jail, respectively).
The rest of the HOWTO deals with setting up the jail and other things like that, which shouldn't need to be altered between versions of BIND. You can just dump the new binaries in over top of the old ones, and you're good to go. But don't forget to kill and restart BIND afterwards, or the old, vulnerable version will still be running!
I'd like to thank the following people for their assistance in the creation of this HOWTO:
<lonny at abyss.za.org>
for "testing" the first version of this HOWTO and making sure
that I didn't miss any steps.<chirik at CastleFur.COM>, Dwayne
Litzenberger <dlitz at dlitz.net>, Phil
Bambridge <phil.b at cableinet.co.uk>,
Robert Cole <rcole at metrum-datatape.com>,
Colin MacDonald <colinm at telus.net>, and
others for pointing out errors, omissions, and providing other
useful advice to make this HOWTO even better.<erikw at sec.se> and Brian
Cervenka <brian at zerobelow.org> for
providing good suggestions for further tightening the
jail.And last but certainly not least, I'd like to thank Nakano
Takeo <nakano at apm.seikei.ac.jp> for
translating the Chroot-BIND HOWTO into Japanese. You can find his
translation at
http://www.linux.or.jp/JF/JFdocs/Chroot-BIND-HOWTO.html.
Copyright © Scott Wunsch, 2000-2001. This document may be distributed only subject to the terms set forth in the LDP licence at http://metalab.unc.edu/LDP/COPYRIGHT.html.
This HOWTO is free documentation; you can redistribute it and/or modify it under the terms of the LDP licence. It is distributed in the hope that it will be useful, but without any warranty; without even the impled warranty of merchantability or fitness for a particular purpose. See the LDP licence for more details.