Chrooting Apache2 howto

Credits

This article was inspired by Artur
Maj's article Securing
Apache: Step-by-Step shows in a step-by-step fashion, how to install and
configure the Apache 2.0.x series web server in much the same way as the 1.3.X
covered in Artur's article, i.e. "in order to mitigate or avoid successful
break-in when new vulnerabilities in this software are found".

Introduction

Configuring your Apache2 server in accordance to the specifications laid out
in this howto will result in limited functionality. The following will be
available:

Apache2 will be accessible from the Internet

only static pages will be served (e.g. HTML or XHTML)

name based virtual hosting

specified web pages can be accessible only from selected IP addresses or
users (basic .htaccess authentication)

all web requests will be logged including information about the browsers

This howto does not cover such things as relational databases (MySQL, PostgreSQL,
etc.), scripting languages (Python, Perl, PHP, Tcl, etc.), or any of a myriad
of server side gadgets for interaction with web services. The reasons for this
are beyond the scope of this howto, but involve security on multiple levels.
For a better explanation to this and a number of other good security oriented
observations, read Artur's article.

Setup

The rest of this howto has been performed on my LFS 3.3 (
Linux from scratch) based distribution
of Linux called Jinx, running on a i586-pc-linux-gnu, with the 2.4.18 kernel
(I know it's not the latest kernel patch, but I'm such a lazy bastard).

I'm sure most of the stuff in this howto will be applicable in most unixes,
but some variations may occur. I'll try to add them, if you report them,
with the exclusion of anything involving the microsoft corporation.

The first step in securing any service is to close as many security holes
in the operating system and then start closing holes in the service itself.
This so called hardening of the OS is beyond the scope of this article,
but there are some very good articles about the issue on e.g. the
SecurityFocus site. So feel free
to stop by there and come back later for the Apache2 part.

Installation and settings

Once all the other planned hardening has been executed we can begin the
process of bolting up Apache2.

The first thing is to create a new username and usergroup to be used
only by Apache2. We can use the name for both "apache2" and create the
new group and regular user like this:

This sets the home directory to nada and gives no shell. Thus if the
user account is compromised the cracker will have a hard time obtaining
a shell from which to launch any serious attack.

Also, by default, the Apache2 processes run with privileges of user nobody
(except the main process, which runs with root privileges) and GID of
group nogroup. If the account was compromised the intruder would gain
access to all processed running under user nobody and group nogroup.
Hence we run Apache2 under the UID/GID of a unique regular user/group,
dedicated to Apache2.

Getting Apache2

Next you need to download the latest stable version of the
Apache2 web server from your nearest
mirror. Since some of the options of Apache2 can only be disabled
during compilation, you need to download the source instead of a binary
release. It is also good practice to always compile your own software,
since then you'll know what crap got put in and what got left out, right?

If you download the software from a mirror, be sure to verify the
authenticity of the packages with PGP, GPG or MD5 as instructed
here.

After downloading and verifying the packets, you need to unpack them.
Then you need to decide which modules are to remain enabled. All the
modules available in the latest version of Apache 2.0.X (currently 2.0.47)
can be found at
http://httpd.apache.org/docs-2.0/mod.

Apache2 modules

The choice of modules is one of the most important steps in securing Apache2.
The fewer you have, the better. In order to not incapasitate Apache2 completely
and fulfill the functionality and security assumptions stated in the beginning,
the following modules must remain enabled:

Module

Description

core

Core Apache HTTP Server features that are always available

mod_access

Access control based on client hostname, IP address, or other
characteristics of the client request

Associates the requested filename's extensions with the file's behavior
(handlers and filters) and content (mime-type, language, character set and
encoding)

All of the aforementioned modules are installed by default, but a number of
other modules are also installed by default. Since configure for Apache2
doesn't seem to support the --disable-all switch you need to
disable the ones you don't want and leave untouched the default ones you
want. The following modules should thus be removed:

mod_actions

mod_alias

mod_asis

mod_autoindex

mod_cgi

mod_env

mod_imap

mod_include

mod_negotiation

mod_setenvif

mod_so

mod_status

mod_userdir

This will leave the wanted modules listed before and use the default MPM,
prefork.c.

Now, you may choose to include some more modules and change the MPM to
suit your needs better. It is, however, worth to note that some Apache2
modules are more dangerous than others. For a discussion of these, please
refer to the original Securing
Apache: Step-by-Step article or any number of security related sites
for example SecurityFocus.

The next issue is whether to compile the modules dynamically or statically.
Static is better. If new vulnerabilities in Apache2 are found, you will
probably have to recompile the whole thing anyway and by choosing the static
method, you eliminate the need of one more module, mod_so.

Compiling Apache2

The latest distribution should have all necessary security patches included,
but if for some reason it does not, you need to apply all these patches.
After this, the server can be compiled as follows:

The choice of prefix is naturally up to you, but I happen to use that one.
It is a good idea not to leave any marks about the version of apache in
use, thus for example --prefix=/opt/apache-2.0.47
would be a bad choice.

After configure, run make, switch to root,
make sure the default access right settings for files and directories are
proper, run make install and set the ownership for the new
files and directories to root.

make
su
umask 022
make install
chown -R root:root /opt/apache

The actual Chrooting of Apache2

The next phase is to limit Apache2's access to the filesystem. This can
be achieved by chrooting it's main daemon, httpd. Chrooting
means creating a new root directory structure. Thus when you move daemon files
to it, and run the proper daemon in the new environment, it and all it's child
processes will have access only to the new directory structure.

First you need to create the new root directory structure. I've done it
under /chroot/httpd, you can choose whatever you like. To
make the directory structure under /chroot/httpd, do this:

Naturally you'd want to put the zoneinfo, that's relevant for you.
The owner of all these directories must be root and the
access rights must be set to 0755. Next you create the
special device file, /dev/null and set its access rights:

Also a log device must be created under the chroot jail. This can be
achieved by adding the line

syslogd_flags="-l chroot/httpd/dev/log"

to the /etc/syslog.conf file and restarting the
syslogd daemon.

kill -SIGHUP 'cat /var/run/syslogd.pid'

Note: for FreeBSD systems you would need to change the /etc/rc.conf
file.

After these comes the time consuming part. You need to check each and
every program and library for dependancies. I used ldd to
begin with and strace to get all the rest. You should get
something like this, when you ldd the main daemon,
httpd:

The reason why we strace the httpd is
that you need to copy each of these open files to
the chroot jail with the exeption of the /etc/ld.so.cache,
which is created at runtime and the /etc/ld.so.preload,
which is only found on some systems (excluding e.g. mine).

As you can see from the output of the httpd strace the
daemon systematically first checks for the libraries from its own
lib/ directory. Thus you can copy the libraries directly
to the /chroot/httpd/opt/apache/lib directory. You need
to have ld-linux.so.2 and libc.so.6 in the
/lib/ of the chroot, but all the rest can go straight
to Apache2's own lib/ directory.

So, moving on. You copy the libraries to the chroot jail and put
them in the /opt/apache/lib/ and /lib/
directories.

Testing

Now it's time to see if the bugger works. Copy one of the
index files from /opt/apache/htdocs/
to /chroot/httpd/web/index.html:

cp /opt/apache/htdocs/index.html.en /chroot/httpd/web/index.html

Change your /chroot/httpd/opt/apache/conf/httpd.conf
to point to it. You can change only the DocumentRoot
variable to /web for testing. Then try to run Apache2
in the chroot jail:

/usr/sbin/chroot /chroot/httpd/ /opt/apache/bin/httpd

If you made use of the virtual hosts then you need to
make the directories to which you point i.e. I have the
directories /chroot/httpd/opt/apache/logs/kakkonen.fi/,
/chroot/httpd/opt/apache/logs/www.bostonpromenade.com//chroot/httpd/web/vhosts/kakkonen.fi/ and
/chroot/httpd/web/vhosts/www.bostonpromenade.com/.

If Apache2 still won't work, try to strace the
httpd again and grep the file for
ENOENT (something not found).

You can also try to increase the level of Apache2's logging
by changing the LogLevel in the httpd.conf
to debug.

Tuning

Fine tuning the httpd.conf is an artform, but
you can get far with something like this:

Permission is granted to copy, distribute and/or modify this document
under the terms of the GNU Free Documentation License, Version 1.2
or any later version published by the Free Software Foundation;
with no Invariant Sections, no Front-Cover Texts, and no Back-Cover
Texts. A copy of the license is included in the section entitled
"GNU Free Documentation License".