Author: Mike Peters
chroot
daemon allows you to run a program and have it see a givendirectory as the root (
/
) directory. This effectively locks the processinto its very own filesystem (“chroot jail”) isolated from the real
/
filesystem. In this article we will look at how to install the Apache Web server in such an environment.
Installing Apache in a chroot jail does not make Apache itself any more
secure. Rather, it serves to restrict the access of Apache and its child processes to a small subset of the filesystem. The advantage in chrooting a process is not in
preventing a breakin, but rather in containing a potential threat.
Before deciding whether you need to chroot your Web server you should consider
the advantages and disadvantages of such a setup.
Advantages
If Apache is compromised, an intruder will have access only to the files
within the chroot jail.
Potentially dangerous CGI scripts do not have access to your server’s filesystem.
Your Web tree is contained in one area that’s easy to back up and move.
Disadvantages
A chroot environment is more difficult to set up than a traditional install,
especially if you run external software such as Perl, PHP, MySQL, or Python.
The process is only viable if your entire Web tree can exist on a single filesystem.
Compiling and installing the Apache binary
There are no special steps needed to build the Apache binary in order to
install it in a chroot jail. The following steps apply equally to a precompiled binary (such as an RPM) or one you have compiled yourself. Starting with a working binary helps with debugging later, if necessary. Just make sure that you are using the latest patched version of the server, install Apache normally, and ensure that it is working as
expected.
Finally, make sure you configure Apache to run with its own user and
group IDs. Create a user and group with the commands:
# groupadd apache
# useradd -c "Apache Server" -d /dev/null -g apache -s /bin/false apache
These commands create the regular user apache
and the apache
group. Apache runs as
nobody
by default. User nobody
may be used
by many processes, and if it is compromised an intruder will gain access to all
processes on your system running under that UID.
Creating the chroot tree
Our chroot jail is a mini-version of the Linux filesystem. I prefer to use a
seperate partition mounted as /chroot
, with Apache under a
directory named httpd
on my chroot partition.
# mkdir /chroot/httpd # mkdir /chroot/httpd/dev # mkdir /chroot/httpd/lib # mkdir /chroot/httpd/etc # mkdir -p /chroot/httpd/usr/sbin # mkdir /chroot/httpd/usr/lib # mkdir /chroot/httpd/usr/libexec # mkdir -p /chroot/httpd/var/run # mkdir -p /chroot/httpd/var/log/apache # mkdir -p /chroot/httpd/home/httpd
Now set the permissions on your directory structure:
# chown -R root /chroot/httpd # chmod -R 0755 /chroot/httpd # chmod 750 /chroot/httpd/var/log/apache/
Your exact structure may vary slightly depending upon what features of Apache
you are using and where the nescessary libraries live on your main file
system.
Once you have created the nescessary directories you need to create the
null
device.
# mknod /chroot/httpd/dev/null c 1 3 # chown root.sys /chroot/httpd/dev/null # chmod 666 /chroot/httpd/dev/null
You need the null
device and
/chroot/httpd/var/log/httpd/
because, when run in chroot jail, Apache
sees the /chroot/httpd
directory as the equivalent of /
. This means that it cannot access /dev/null
or /var/log
on the normal filesystem.
Copying the nescessary files
Now shut down Apache, run killall httpd
, and you’re ready to start
copying across the necessary files. Note that some directory names may be
different in your case depending upon how you originally installed Apache.
First, copy your configuration files:
# cp -r /etc/apache /chroot/httpd/etc/
Next, copy your Apache DocumentRoot and CGI scripts:
# cp -r /home/httpd/html /chroot/httpd/home/httpd/
# cp -r /home/httpd/cgi-bin /chroot/httpd/home/httpd/
Now copy your httpd binary (and, if you use them, the Apache
scripts) from /usr/sbin
:
# cp /usr/sbin/httpd /chroot/usr/sbin/
# cp /usr/sbin/apache* /chroot/usr/sbin/
If you use mod_ssl you need to copy the /etc/ssl
directory and
its contents too:
# cp -a /etc/ssl /chroot/httpd/etc/
You should also copy any modules from your original install:
cp -r /usr/libexec/apache /chroot/httpd/usr/libexec/
Once you have copied Apache itself (and ssl if needed) you need to copy all of
the shared libraries Apache relies on to run. To find out which libraries you
need, execute # ldd /chroot/httpd/usr/sbin/httpd
. This should give output something like:
/lib/libsafe.so.2 => /lib/libsafe.so.2 (0x40017000) libm.so.6 => /lib/libm.so.6 (0x40037000) libcrypt.so.1 => /lib/libcrypt.so.1 (0x40059000) libdb.so.2 => /lib/libdb.so.2 (0x40086000) libexpat.so.0 => /usr/lib/libexpat.so.0 (0x40096000) libdl.so.2 => /lib/libdl.so.2 (0x400b6000) libc.so.6 => /lib/libc.so.6 (0x400b9000) /lib/ld-linux.so.2 => /lib/ld-linux.so.2 (0x40000000)
The exact output will depend upon how your httpd binary was built in the first
place. Copy the required files to their respective directories in your
chroot:
# cp /lib/libsafe* /chroot/httpd/lib/ # cp /lib/libm* /chroot/httpd/lib/ # cp /lib/libcrypt* /chroot/httpd/lib/ # cp /lib/libdb* /chroot/httpd/lib/ # cp /usr/lib/libexpat* /chroot/httpd/usr/lib/ # cp /lib/libdl* /chroot/httpd/lib/ # cp /lib/libc* /chroot/httpd/lib/ # cp /lib/ld-* /chroot/httpd/lib/
You need certain libraries for some standard networking functionality:
# cp /lib/libnss_compat* /chroot/httpd/lib/ # cp /lib/libnss_dns* /chroot/httpd/lib/ # cp /lib/libnss_files* /chroot/httpd/lib/ # cp /lib/libnsl* /chroot/httpd/lib/
The /chroot/httpd/etc configuration files
For Apache to function properly you also need several configuration files from
/etc
. First, edit the /etc/passwd
and /etc/group
files. These should contain only entries for the Apache user and group you created earlier. For example:
/etc/passwd: apache:x:12347:12348:Apache Server:/dev/null:/bin/false /etc/group: apache:x:12347:
You also need several network configuration files:
# cp /etc/hosts /chroot/httpd/etc/ # cp /etc/host.conf /chroot/httpd/etc/ # cp /etc/resolv.conf /chroot/httpd/etc/ # cp /etc/nsswitch.conf /chroot/httpd/etc/
For extra security you can set the immutable bit on these configuration files.
When the immutable bit is set, root has to specifically
unset it before a file can be modified, making it much harder for an intruder to tamper with the files:
# chattr +i /chroot/httpd/etc/hosts # chattr +i /chroot/httpd/etc/host.conf # chattr +i /chroot/httpd/etc/resolv.conf # chattr +i /chroot/httpd/etc/nsswitch.conf # chattr +i /chroot/httpd/etc/passwd # chattr +i /chroot/httpd/etc/group
In order that the log files be written with the correct time, you need to check
/etc/localtime
. localtime
is a symlink to a file in
/usr/share/zoneinfo
. To find out which file, run
ls -l /etc/localtime
and copy the appropriate file to
/chroot/httpd/etc/localtime
.
By default, syslogd
monitors log files only in
/var/log
. The chrooted httpd daemon will write its logs to
/chroot/httpd/var/log
, however, so you need to tell syslogd to
monitor this directory too. To change this you need to edit the appropriate
startup script, /etc/rc.d/rc.syslog
or
/etc/rc.d/init.d/syslog
, depending upon your distro.
For /etc/rc.d/rc.syslog
change daemon syslogd -m 0
to
daemon syslogd -m 0 -a /chroot/httpd/dev/log
.
For /etc/rc.d/rc.syslog
change:
echo -n " /usr/sbin/syslogd" /usr/sbin/syslogd
to:
echo -n " /usr/sbin/syslogd" /usr/sbin/syslogd -m 0 -a /chroot/httpd/dev/log
It is a good idea to create the nescessary log files and set the appendable
bit on them too.
# touch /chroot/httpd/var/log/apache/access_log # touch /chroot/httpd/var/log/apache/error_log # chmod 600 /chroot/httpd/var/log/apache/* # chattr +a /chroot/httpd/var/log/apache/*
Finally, you need to change the httpd startup script to run the chrooted
httpd. Depending on your distro, open up /etc/rc.d/rc.httpd
or
/etc/rc.d/init.d/httpd
and change the command that starts the
httpd daemon to read /usr/sbin/chroot /chroot/httpd/ /usr/sbin/httpd
.
Testing the server
If you have not already done so you should shut down the httpd daemon now.
Next, restart the syslog daemon: /etc/rc.d/rc.syslog
(or
restart/etc/rc.d/init.d/syslog restart
accordingly).
Now start the chrooted version of Apache with /etc/rc.d/rc.httpd
(or
start/etc/rc.d/init.d/httpd start
).
If there are no errors, check the daemon is running with the command
ps -aux | grep httpd
. You should see several entries indicating a
running httpd process. Taking the process number from the output of ps
and running ls -l /proc/PROC_NUMBER/root/
should show the structure of
your /chroot/httpd
rather than your server’s /
filesystem.
If something has gone wrong, you should try running your chrooted httpd with
strace
. The command # strace chroot /chroot/httpd /usr/sbin/httpd 2> httpd.strace
redirects the output of strace
to a file named
httpd.strace
which should give you an idea where the problem lies.
Once everything is running you can remove your original Apache install.
Summary
Although chroot
can be used to help create a more secure environment, it is not
perfect. You still need to keep your Web server patched up to date and monitor your logs. Your
chroot
environment should help to contain a potential breakin and protect your system’s
main filesystem from unseen vulnerabilities in your Web server.
Category:
- Security