Chroot
environment for Apache
The chroot
utility is often used to jail a daemon in a restricted
tree. You can use it to insulate services from one another, so that security
issues in a software package do not jeoparize the whole server. When using the
makejail
script, setting up and updating the chrooted tree is much
easier.
FIXME: Apache can also be chrooted using http://www.modsecurity.org
which
is available in libapache-mod-security
(for Apache 1.x) and
libapache2-mod-security
(for Apache 2.x).
This document is copyright 2002 Alexandre Ratti. It has been dual-licensed and
released under the GPL version 2 (GNU General Public License) the GNU-FDL 1.2
(GNU Free Documentation Licence) and is included in this manual with his
explicit permission. (from the original
document
)
This procedure was tested on Debian GNU/Linux 3.0 (Woody) with
makejail
0.0.4-1 (in Debian/testing).
root
and create a new jail directory:
$ mkdir -p /var/chroot/apache
chrapach
.
$ adduser --home /var/chroot/apache --shell /bin/false \ --no-create-home --system --group chrapach
FIXME: is a new user needed? (Apache already runs as the apache user)
/etc/apache/httpd.conf
configuration file , set the Group
and User options to chrapach. Restart Apache and make
sure the server is working correctly. Now, stop the Apache daemon.
makejail
(available in Debian/testing for now). You
should also install wget
and lynx
as they will be
used by makejail
to test the chrooted server: apt-get
install makejail wget lynx
/etc/makejail
directory:
# cp /usr/share/doc/makejail/examples/apache.py /etc/makejail/
/etc/makejail/apache.py
. You need to change the
chroot, users and groups options. To run this
version of makejail
, you can also added a packages
option. See the makejail
documentation
. A sample is shown here:
chroot="/var/chroot/apache" testCommandsInsideJail=["/usr/sbin/apachectl start"] processNames=["apache"] testCommandsOutsideJail=["wget -r --spider http://localhost/", "lynx --source https://localhost/"] preserve=["/var/www", "/var/log/apache", "/dev/log"] users=["chrapach"] groups=["chrapach"] packages=["apache", "apache-common"] userFiles=["/etc/password", "/etc/shadow"] groupFiles=["/etc/group", "/etc/gshadow"] forceCopy=["/etc/hosts", "/etc/mime.types"]
FIXME: some options do not seem to work properly. For instance,
/etc/shadow
and /etc/gshadow
are not copied, whereas
/etc/password
and /etc/group
are fully copied instead
of being filtered.
/etc/password
and /etc/group
were fully copied,
type:
$ grep chrapach /etc/passwd > /var/chroot/apache/etc/passwd $ grep chrapach /etc/group > /var/chroot/apache/etc/group
to replace them with filtered copies.
makejail
's
configuration file).
# cp -Rp /var/www /var/chroot/apache/var # cp -Rp /var/log/apache/*.log /var/chroot/apache/var/log/apache
/var/chroot/apache/dev/log
socket. In
/etc/init.d/sysklogd
, replace: SYSLOGD=""
with SYSLOGD=" -a /var/chroot/apache/dev/log" and
restart the daemon (/etc/init.d/sysklogd restart).
/etc/init.d/apache
). You might
need to make some changes to the default startup script for it to run properly
with a chrooted tree. Such as:
/proc
filesystem within the
jail.
#! /bin/bash # # apache Start the apache HTTP server. # CHRDIR=/var/chroot/apache NAME=apache PATH=/bin:/usr/bin:/sbin:/usr/sbin DAEMON=/usr/sbin/apache SUEXEC=/usr/lib/apache/suexec PIDFILE=/var/run/$NAME.pid CONF=/etc/apache/httpd.conf APACHECTL=/usr/sbin/apachectl trap "" 1 export LANG=C export PATH test -f $DAEMON || exit 0 test -f $APACHECTL || exit 0 # ensure we don't leak environment vars into apachectl APACHECTL="env -i LANG=${LANG} PATH=${PATH} chroot $CHRDIR $APACHECTL" if egrep -q -i "^[[:space:]]*ServerType[[:space:]]+inet" $CONF then exit 0 fi case "$1" in start) echo -n "Starting web server: $NAME" mount -t proc proc /var/chroot/apache/proc start-stop-daemon --start --pidfile $PIDFILE --exec $DAEMON \ --chroot $CHRDIR ;; stop) echo -n "Stopping web server: $NAME" start-stop-daemon --stop --pidfile "$CHRDIR/$PIDFILE" --oknodo umount /var/chroot/apache/proc ;; reload) echo -n "Reloading $NAME configuration" start-stop-daemon --stop --pidfile "$CHRDIR/$PIDFILE" \ --signal USR1 --startas $DAEMON --chroot $CHRDIR ;; reload-modules) echo -n "Reloading $NAME modules" start-stop-daemon --stop --pidfile "$CHRDIR/$PIDFILE" --oknodo \ --retry 30 start-stop-daemon --start --pidfile $PIDFILE \ --exec $DAEMON --chroot $CHRDIR ;; restart) $0 reload-modules exit $? ;; force-reload) $0 reload-modules exit $? ;; *) echo "Usage: /etc/init.d/$NAME {start|stop|reload|reload-modules|force-reload|restart}" exit 1 ;; esac if [ $? == 0 ]; then echo . exit 0 else echo failed exit 1 fi
FIXME: should the first Apache process be run as another user than root (i.e. add --chuid chrapach:chrapach)? Cons: chrapach will need write access to the logs, which is awkward.
/etc/logrotate.d/apache
/var/log/apache/*.log with
/var/chroot/apache/var/log/apache/*.log
/etc/init.d/apache start
) and check what is it
reported in the jail log
(/var/chroot/apache/var/log/apache/error.log
). If your setup is
more complex, (eg. if you also use PHP and MySQL), files will probably be
missing. if some files are not copied automatically by makejail
,
you can list them in the forceCopy (to copy files directly) or
packages (to copy full packages and their dependencies) option the
/etc/makejail/apache.py
configuration file.
root 180 0.0 1.1 2936 1436 ? S 04:03 0:00 /usr/sbin/apache chrapach 189 0.0 1.1 2960 1456 ? S 04:03 0:00 /usr/sbin/apache chrapach 190 0.0 1.1 2960 1456 ? S 04:03 0:00 /usr/sbin/apache chrapach 191 0.0 1.1 2960 1456 ? S 04:03 0:00 /usr/sbin/apache chrapach 192 0.0 1.1 2960 1456 ? S 04:03 0:00 /usr/sbin/apache chrapach 193 0.0 1.1 2960 1456 ? S 04:03 0:00 /usr/sbin/apache
/proc
filesystem: ls -la
/proc/process_number/root/. where process is one of
the PID numbers listed above (2nd column; 189 for instance). The entries for a
restricted tree should be listed:
drwxr-sr-x 10 root staff 240 Dec 2 16:06 . drwxrwsr-x 4 root staff 72 Dec 2 08:07 .. drwxr-xr-x 2 root root 144 Dec 2 16:05 bin drwxr-xr-x 2 root root 120 Dec 3 04:03 dev drwxr-xr-x 5 root root 408 Dec 3 04:03 etc drwxr-xr-x 2 root root 800 Dec 2 16:06 lib dr-xr-xr-x 43 root root 0 Dec 3 05:03 proc drwxr-xr-x 2 root root 48 Dec 2 16:06 sbin drwxr-xr-x 6 root root 144 Dec 2 16:04 usr drwxr-xr-x 7 root root 168 Dec 2 16:06 var
To automate this test, you can type:ls -la /proc/`cat /var/chroot/apache/var/run/apache.pid`/root/.
FIXME: Add other tests that can be run to make sure the jail is closed?
The reason I like this is because setting up the jail is not very difficult and the server can be updated in just two lines:
apt-get update && apt-get install apache makejail /etc/makejail/apache.py
If you are looking for more information you can consider these sources of information in which the information presented is based:
makejail homepage
,
this program was written by Alain Tesio
Chrooting
daemons and system processes HOWTO
by Jonathan, Network Dweebs,
21/10/2002
Securing Debian Manual
Version: 3.2, Mon, 16 May 2005 21:27:53 +0200jfs@debian.org