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 user like nobody
for this purpose.
This requires adding a line something like the following to /etc/passwd
:
named:x:200:200:Nameserver:/chroot/named:/bin/false
And one like this to /etc/group
:
named:x:200:
This creates a user and group called 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:
# chown -R named:named /chroot/named/etc/namedb
BIND will also need to write to the /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:
# 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
As an alternative, you could simply build statically-linked versions
of the BIND binaries to put in your chroot jail.
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. 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
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
daemon syslogd -m 0
to
daemon syslogd -m 0 -a /chroot/named/dev/log
The simply restart syslogd
, either by killing it and launching it again,
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.