Chrooting Apache

How to install Apache in a chroot jail on a Linux box.

by Mike Peters, May 2004
(Originally published on Linux.com)

Introduction

The chroot daemon allows us to run a program and have it see a given directory as the root (/) directory. This effectively locks the process into its very own file system (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 it's child processes to a small subset of the file system. The advantage in chrooting a process is not in prevention, rather containment of 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, the intruder will only have access to the files within the chroot jail.

Potentially dangerous cgi scripts will not have access to your server's file system.

Your web-tree is contained in one easy to back-up and move area.

Disadvantages

A chroot environment is more difficult to set up than a traditional install, especially if you run external features such as perl, php, MySQL or Python etc.

The process is only viable if your entire web tree can exist on a single file system.

Compiling/Installing the Apache Binary

There are no special steps needed to build the Apache binary in order to install it in a chroot jail. Therefore I am not going to detail how to compile Apache. The following steps apply equally to a precompiled binary (such as an RPM) or one you have compiled yourself. Just make sure that you are using the latest patched version of the server and install normally.

Once you have installed Apache normally, ensure that it is working as expected. Starting with a working binary will help with de-bugging later.

Finally, make sure you configure apache to run with its own user and group ID's. Create a user and group with the commands:

# groupadd apache
# useradd -c "Apache Server" -d /dev/null -g apache -s /bin/false apache

This will create a regular user apache and the apache group. Apache runs as nobody by default. However, user nobody may be used by many processes and if compromised the intruder will have 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 file system. 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 you 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 we have created the nescessary directories we 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
    

We need the null device and /chroot/httpd/var/log/httpd/ because, when run in our chroot jail, Apache will see the /chroot/httpd directory as the equivalent of / . This means that it will not be able to access /dev/null or /var/log on the normal file system.

Copying the Nescessary Files

Now shut down apache, killall httpd and we are ready to start copying across the nescessary files. Note that some directory names may be different in your case depending upon how you originally installed Apache. Firstly, copy your configuration files:

# cp -r /etc/apache /chroot/httpd/etc/

Next, 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 for 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 we have copied Apache itself (and ssl if needed) we need to copy all of the shared libraries which apache relies on to run. To find out which libraries we 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 will need certain libraries for some standard networking functionality as follows:

    # 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 we also need several configuration files from /etc.

Firstly we edit the /etc/passwd and /etc/group files. These should only contain entries for our apache user and group we created earlier. For example

    /etc/passwd:
    apache:x:12347:12348:Apache Server:/dev/null:/bin/false

    /etc/group:
    apache:x:12347:
    

Several network configuration files are also needed:

    # 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 we can set the immutable bit on these configuration files. This means that before the files can be modified, root, has to specifically unset the immutable bit 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 our log files be written with the correct time, we 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, will only be monitoring log files in /var/log. Our chrooted httpd daemon will be writing its logs to /chroot/httpd/var/log however, so, we need to tell syslogd to monitor this directory too. To change this you need to edit the appropriate start-up 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, we need to change our httpd start-up script to run our chrooted httpd. Depending on your distro, open up /etc/rc.d/rc.httpd or /etc/rc.d/init.d/httpd and change the command which starts the http 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 we need to restart the syslog daemon /etc/rc.d/rc.syslog restart (or /etc/rc.d/init.d/syslog restart accordingly). Now start the chrooted version of apache with /etc/rc.d/rc.httpd start (or /etc/rc.d/init.d/httpd start).

If there are no errors, check the daemon is running, ps -aux | grep httpd. You should see several entries indicating a running httpd process. Taking the process number from the output of ps, running ls -l /proc/PROC_NUMBER/root/ should show the structure of your /chroot/httpd rather than your servers / file system.

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 will redirect 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 break in and protect your system's main file system from unseen vulnerabilities in your web server.



Save This Page
mikepeters See mikepeters' photos on flickr
Created with Vim   Graphics by GIMP