Vhosts mit separaten UIDs/GIDs mit Apache2-MPM-peruser auf Debian Etch nutzen

Version 1.0
Autor: Falko Timme


Diese Anleitung erläutert wie man einen Apache2-MPM-Peruser auf einem Debian Etch Server installiert und konfiguriert. Apache2-MPM-peruser ist ein MPM (Multi-Processing Modul) für den Apache 2 Webserver und Apache2-MPM-itk sehr ähnlich, jedoch schneller (fast wie Apache2-MPM-Prefork). MPM-peruser ermöglicht die Benutzung jeden Vhosts unter einer separaten UID und GIB - kurzgefasst, die Skripte und die Konfigurationsdateien müssen nicht mehr für die anderen virtuellen Hosts lesbar sein. Es basiert auf metuxmpm, eine funktionsfähige Implementierung des perchild-MPM. Das Ergebnis ist ein ausgewogenes und sicheres Webserver-Umfeld für die Nutzer, ohne Behelfslösungen wie PHPs safe_mode.

Dieses Anleitung ist ohne Gewähr! Ich kann leider nicht garantieren, dass es bei Dir genauso funktioniert.

1 Vorbemerkung

Für die Berücksichtigung von Geschwindigkeiten, bitte unter http://blog.stuartherbert.com/php/2008/03/20/using-mpm-peruser-to-secure-a-shared-server/ nachschauen.

Ich gehe davon aus, dass Du bereits eine funktionierende Apache2 Installation mit mod_php auf einem Debian Etch Server hast, beispielsweise folgendermassen installiert:

apt-get install apache2-mpm-prefork libapache2-mod-php5

Wenn eine PHP Datei mit der phpinfo(); Funktion erstellt wird, z. B.:

vi /var/www/info.php

<?php
phpinfo(); ?>
... und im Browser aufgerufen wird, wird sichtbar dass prefork in der Zeile Loaded Modules unter apache2handler aufgelistet ist:

2 Apache2-MPM-peruser installieren

Apache2-MPM-peruser ist leider nicht wie Apache2-MPM-itk als Debian Paket erhältlich, daher erstelle ich ein eigenes Debian Paket. Hierfür nutze ich das Apache2-MPM-itk Quelltextpaket als Basis für mein eigenes Apache2-MPM-peruser Debian Paket, da sie sich sehr ähnlich sind.

Bevor das Paket erstellt wird, installiere ich einige Grundvoraussetzungen:

apt-get install build-essential dpkg-dev fakeroot debhelper dpatch apache2-prefork-dev libcap-dev apache2-src autoconf

Dann gehe ich zu /usr/src und lade das Apache2-MPM-itk Quelltext Paket herunter:

cd /usr/src
apt-get source apache2-mpm-itk

ls -l


server1:/usr/src# ls -l
total 52
drwxr-xr-x 3 root root  4096 2008-08-16 13:29 apache2-mpm-itk-2.2.3-01
-rw-r--r-- 1 root src  11392 2007-10-03 19:02 apache2-mpm-itk_2.2.3-01-2.diff.gz
-rw-r--r-- 1 root src    664 2007-10-03 19:02 apache2-mpm-itk_2.2.3-01-2.dsc
-rw-r--r-- 1 root src  29071 2006-10-31 00:04 apache2-mpm-itk_2.2.3-01.orig.tar.gz
server1:/usr/src#

Als nächstes bennene ich das Verzeichnis Apache2-MPM-itk zu Apache2-MPM-peruser:

mv apache2-mpm-itk-2.2.3-01 apache2-mpm-peruser-2.2.3-01

Dann gehe ich zu diesem Verzeichnis, lade den MPM-peruser Patch herunter und lösche den MPM-itk Patch, der sich bereits im Verzeichnis befindet:

cd apache2-mpm-peruser-2.2.3-01/
wget http://www.telana.com/files/httpd-2.2.3-peruser-0.3.0.patch
rm -f apache2.2-mpm-itk.patch

Gehen wir nun zum debian/ Unterverzeichnis :

cd debian/
ls -l

server1:/usr/src/apache2-mpm-peruser-2.2.3-01/debian# ls -l
total 64
-rw-r--r-- 1 root root    10 2008-08-15 16:21 apache2-mpm-itk.dirs
-rw-r--r-- 1 root root   633 2008-08-15 16:21 apache2-mpm-itk.postinst
-rw-r--r-- 1 root root   561 2008-08-15 16:21 apache2-mpm-itk.preinst
-rw-r--r-- 1 root root   342 2008-08-15 16:21 apache2-mpm-itk.prerm
-rw-r--r-- 1 root root   438 2008-08-15 16:21 changelog
-rw-r--r-- 1 root root     2 2008-08-15 16:21 compat
-rw-r--r-- 1 root root   980 2008-08-15 16:21 control
-rw-r--r-- 1 root root 31777 2008-08-15 16:21 copyright
-rwxr-xr-x 1 root root  1328 2008-08-15 16:21 rules
server1:/usr/src/apache2-mpm-peruser-2.2.3-01/debian#

Wir bennenen alle Dateien, die itk im Dateinamen enthalten, um:

mv apache2-mpm-itk.dirs apache2-mpm-peruser.dirs
mv apache2-mpm-itk.postinst apache2-mpm-peruser.postinst
mv apache2-mpm-itk.preinst apache2-mpm-peruser.preinst
mv apache2-mpm-itk.prerm apache2-mpm-peruser.prerm

Dann müssen wir die changelog Datei ändern, z.B. folgendermassen:

cat /dev/null > changelog
vi changelog

apache2-mpm-peruser (2.2.3-01-1) stable; urgency=low
* Initial port to Apache 2.2. -- Falko Timme <ft@falkotimme.com> Fri, 15 Aug 2008 14:29:36 +0100
Bitte versichere Dich dass die letzte Zeile genau eine Leerzeile am Anfang (vor --) hat, sowie zwei Leerzeichen zwischen der Email-Adresse und dem Datum!

Nun öffnen wir die control Datei und ersetzen alle apache2-mpm-itk mit apache2-mpm-peruser. Ich lasse die Description unverändert, ersetze jedoch ITK mit Peruser. In der Conflicts Zeile füge ich apache2-mpm-itk hinzu:

vi control

Source: apache2-mpm-peruser
Section: net Priority: extra Build-Depends: apache2-src, apache2-prefork-dev, libcap-dev, autoconf, debhelper (>> 5.0.0) Maintainer: Falko Timme <ft@falkotimme.com> Standards-Version: 3.7.2 Package: apache2-mpm-peruser Provides: apache2-modules, apache2, httpd, httpd-cgi Conflicts: apache2-mpm-prefork, apache2-mpm-itk, apache2-mpm-worker, apache2-mpm-perchild, apache2-mpm-event, apache2-common Depends: ${apache:Depends}, ${shlibs:Depends} Architecture: any Description: multiuser MPM for Apache 2.2 The Peruser Multi-Processing Module (MPM) works in about the same way as the classical "prefork" module (that is, without threads), except that it allows you to constrain each individual vhost to a particular system user. This allows you to run several different web sites on a single server without worrying that they will be able to read each others' files. . Please note that this MPM is highly experimental, and is not from the same tree as the other MPMs.
Nun ändern wir die rules Datei:

vi rules

Ersetze
cd apache2.2/ && patch -p1 < ../apache2.2-mpm-itk.patch
mit
cd apache2.2/ && patch -p1 < ../httpd-2.2.3-peruser-0.3.0.patch
Ersetze
sed 's,prefork,itk,;s,^".*/configure",../apache2.2/configure,;s,^"--srcdir=.*",--srcdir=../apache2.2/,' < /usr/share/apache2/build/config.nice > build-tree/config.nice
mit
sed 's,prefork,peruser,;s,^".*/configure",../apache2.2/configure,;s,^"--srcdir=.*",--srcdir=../apache2.2/,' < /usr/share/apache2/build/config.nice > build-tree/config.nice
Ersetze
install -m 0755 build-tree/apache2 debian/apache2-mpm-itk/usr/sbin/
mit
install -m 0755 build-tree/apache2 debian/apache2-mpm-peruser/usr/sbin/
Ersetze
echo "apache:Depends=apache2.2-common (= `dpkg -s apache2.2-common | grep ^Version: | cut -d" " -f2`)" >> debian/apache2-mpm-itk.substvars
mit
echo "apache:Depends=apache2.2-common (= `dpkg -s apache2.2-common | grep ^Version: | cut -d" " -f2`)" >> debian/apache2-mpm-peruser.substvars
Die vollständige Datei sieht folgendermassen aus:
#! /usr/bin/make -f
clean: dh_testdir dh_testroot dh_clean $(RM) -r build-tree/ $(RM) -r apache2.2/ $(RM) build-stamp build: build-stamp build-arch: build-stamp build-stamp: dh_testdir mkdir build-tree/ mkdir apache2.2/ cd apache2.2/ && tar zxf /usr/src/apache2.tar.gz # workaround for apache2-src 2.2.3-3 if [ -d apache2.2/apache2 ]; then mv apache2.2/apache2/* apache2.2/; rmdir apache2.2/apache2/; fi cd apache2.2/ && patch -p1 < ../httpd-2.2.3-peruser-0.3.0.patch cd apache2.2/ && autoconf sed 's,prefork,peruser,;s,^".*/configure",../apache2.2/configure,;s,^"--srcdir=.*",--srcdir=../apache2.2/,' < /usr/share/apache2/build/config.nice > build-tree/config.nice chmod +x build-tree/config.nice cd build-tree/ && ./config.nice cd build-tree/ && $(MAKE) touch build-stamp binary: binary-arch binary-indep: binary-arch: build-arch dh_testdir dh_testroot dh_installdirs install -m 0755 build-tree/apache2 debian/apache2-mpm-peruser/usr/sbin/ dh_fixperms dh_strip dh_installdocs README dh_installchangelogs dh_installdeb dh_compress dh_shlibdeps echo "apache:Depends=apache2.2-common (= `dpkg -s apache2.2-common | grep ^Version: | cut -d" " -f2`)" >> debian/apache2-mpm-peruser.substvars dh_gencontrol dh_md5sums dh_builddeb .PHONY: clean build build-arch binary binary-arch binary-indep
Das sind alle Änderungen die wir vornehmen mussten - nun können wir das Paket erstellen:

cd ..
dpkg-buildpackage

Das Paket wird im /usr/src Verzeichnis verfügbar sein:

cd /usr/src
ls -l

server1:/usr/src# ls -l
total 6512
-rw-r--r-- 1 root src    11392 2007-10-03 19:02 apache2-mpm-itk_2.2.3-01-2.diff.gz
-rw-r--r-- 1 root src      664 2007-10-03 19:02 apache2-mpm-itk_2.2.3-01-2.dsc
-rw-r--r-- 1 root src    29071 2006-10-31 00:04 apache2-mpm-itk_2.2.3-01.orig.tar.gz
drwxr-xr-x 5 root root    4096 2008-08-16 13:40 apache2-mpm-peruser-2.2.3-01
-rw-r--r-- 1 root src      353 2008-08-16 13:36 apache2-mpm-peruser_2.2.3-01-1.dsc
-rw-r--r-- 1 root src      710 2008-08-16 13:40 apache2-mpm-peruser_2.2.3-01-1_i386.changes
-rw-r--r-- 1 root src   165438 2008-08-16 13:40 apache2-mpm-peruser_2.2.3-01-1_i386.deb
-rw-r--r-- 1 root src    50282 2008-08-16 13:36 apache2-mpm-peruser_2.2.3-01-1.tar.gz
-rw-r--r-- 1 root root 6364431 2008-03-22 10:35 apache2.tar.gz
server1:/usr/src#

Das MPM-peruser Paket, das wir gerade erstellt haben, wird apache2-mpm-peruser_2.2.3-01-1_i386.deb benannt. Bevor wir es installieren können, müssen wir das Apache2-MPM-prefork deinstallieren, da es mit dem Apache2-MPM-peruser konfligiert (denken wir an die control Datei):

apt-get remove apache2-mpm-prefork

server1:/usr/src# apt-get remove apache2-mpm-prefork
Reading package lists... Done
Building dependency tree... Done
The following packages will be REMOVED:
apache2-mpm-prefork libapache2-mod-php5 0 upgraded, 0 newly installed, 2 to remove and 68 not upgraded.
Need to get 0B of archives.
After unpacking 6115kB disk space will be freed.
Do you want to continue [Y/n]? 
<-- Y (Reading database ... 29620 files and directories currently installed.)
Removing libapache2-mod-php5 ...
Module php5 disabled; run /etc/init.d/apache2 force-reload to fully disable.
Removing apache2-mpm-prefork ...
Stopping web server (apache2)....
server1:/usr/src#

Leider wird dabei das libapache2-mod-php5 Paket entfernt, so dass PHP nicht mehr funktioniert. Darum werden wir und anschliessend kümmern.


Nun installieren wir das Apache2-MPM-peruser Paket:

dpkg -i apache2-mpm-peruser_2.2.3-01-1_i386.deb

Wenn wir nun versuchen das Libapache2-mod-PHP5 Paket zu reinstallieren, wird apt verlangen Apache2-MPM-peruser zu entfernen und stattdessen Apache2-MPM-prefork wieder zu installieren, was wir aber nicht wollen. Daher brechen wie diesen Vorgang ab:

server1:/usr/src# apt-get install libapache2-mod-php5
Reading package lists... Done
Building dependency tree... Done
The following extra packages will be installed:
apache2-mpm-prefork Suggested packages:
php-pear
The following packages will be REMOVED:
apache2-mpm-peruser The following NEW packages will be installed:
apache2-mpm-prefork libapache2-mod-php5
0 upgraded, 2 newly installed, 1 to remove and 61 not upgraded.
Need to get 0B/2833kB of archives.
After unpacking 5681kB of additional disk space will be used.
Do you want to continue [Y/n]? 
<-- n Abort.
server1:/usr/src#

Als das Libapache2-mod-PHP5 Paket erstellt wurde, hat der Programmierer eine Abhängigkeit von Apache2-MPM-prefork oder Apache2-mpm-itk eingebaut. Für uns bedeutet das, dass wir Libapache2-mod-PHP5 anhand des Quelltextes wiederherstellen müssen und das Apache2-MPM-peruser Paket zu den Abhängigkeiten dieses Pakets hinzufügen müssen. Das gilt auch für alle anderen Pakete, bei denen solche Probleme auftreten, aber dazu werde ich gleich noch kommen.

3 Apache2-MPM-peruser konfigurieren

In diesem Beispiel benutze ich den standardmässigen Debian Apache Vhost, dessen Konfiguration unter /etc/apache2/sites-available/default liegt, mit dem Dokumentenroot /var/www (für andere Vhosts bitte gegebenenfalls anpassen), und der Vhost soll als Benutzer web1_admin und als Gruppe web1 laufen.

Falls es diesen Benutzer sowie die Gruppe nicht schon gibt, können wir sie folgendermassen erstellen:

groupadd web1
useradd -s /bin/false -d /home/web1_admin -m -g web1 web1_admin

Anschliessend öffnen wir die Hauptkonfigurationsdatei von Apache (/etc/apache2/apache2.conf) und suchen die Stelle wo die verschiedenen MPMs (prefork, worker, etc.) konfiguriert sind, um folgendes hinzuzufügen:

vi /etc/apache2/apache2.conf

[...]
<IfModule peruser.c> ServerLimit 256 MaxClients 256 MinSpareProcessors 2 MaxProcessors 10 MaxRequestsPerChild 1000 # kill idle processors after this many seconds (0 to disable) IdleTimeout 60 # kill hung processes after this many seconds (0 to disable) ExpireTimeout 300 # set up a few multiplexer processes running as nobody Multiplexer nobody nogroup Multiplexer nobody nogroup Multiplexer nobody nogroup # Processor <user> <group> <chroot> # chroot is optional Processor web1_admin web1 </IfModule> [...]
Die Processor Zeile ist wichtig! Es teilt Apache mit, welcher Benutzer/Gruppenpaar den Vhost betreiben darf. Wenn es einen zweiten Vhost gibt, der als Benutzer web2_admin und Gruppe web2 laufen soll, muss eine zweite Processor Zeile hinzugefügt werden. line. Man kann den Benutzer/die Gruppe sogar chrooten indem man ein optionalesVerzeichnis hinzufügt:
[...]
Processor web1_admin web1 /var/www [...]
Wir müssen dann die Vhosts anpassen, beispielsweise folgendermassen:

vi /etc/apache2/sites-available/default

[...]
<IfModule peruser.c> # this must match a Processor line ServerEnvironment web1_admin web1 # these are optional - defaults to the values specified above #MinSpareProcessors 4 #MaxProcessors 20 </IfModule> [...]
Das muss in einem <VirtualHost></VirtualHost> Container stehen. Die Zeile ServerEnvironment muss genau! einer der Processor Zeilen der MPM-peruser Konfiguration entsprechen . Wurde ein Chroot in der Processor Zeile definiert, muss das Chroot hier ebenfalls aufgeführt werden, z. B.:
[...]
ServerEnvironment web1_admin web1 /var/www [...]
Das gibt an unter welchem Benutzer und Gruppe der bestimmte Vhost läuft.

Danach starten wir Apache neu:

/etc/init.d/apache2 restart


4 Libapache2-mod-PHP5 wiederherstellen

Endlich stellen wir die Libapache2-mod-PHP5 wieder her. Zunächst installieren wir einige Grundvoraussetzungen:

apt-get install apache-dev bison chrpath firebird2-dev flex freetds-dev libbz2-dev libc-client-dev libcurl3-openssl-dev libfreetype6-dev libgcrypt11-dev libgd2-xpm-dev libjpeg62-dev libmcrypt-dev libmhash-dev libmysqlclient15-dev libncurses5-dev libpam0g-dev libpng12-dev libpspell-dev librecode-dev libsnmp9-dev libsqlite0-dev libt1-dev libtidy-dev libwrap0-dev libxmltok1-dev libxml2-dev libxslt1-dev re2c unixodbc-dev automake1.4 libtool shtool

Dann holen wir uns das PHP5 Quelltextpaket...

cd /usr/src
apt-get source php5

... und gehen zum Quelltextverzeichnis :

cd php5-5.2.0

Nun müssen wir PHP5 beibringen, dass es entweder Apache2-MPM-prefork oder Apache2-MPM-itk oder Apache2-MPM-peruser als Abhängigkeit akzeptieren soll. Öffne debian/rules:

vi debian/rules

Zum Ende der Datei finden wir folgende Zeile:
[...]
echo "apache2:Depends=apache2-mpm-prefork (>> 2.0.52) | apache2-mpm-itk, apache2.2-common" >>debian/libapache2-mod-php5.substvars [...]
Ändere das zu :
[...]
echo "apache2:Depends=apache2-mpm-prefork (>> 2.0.52) | apache2-mpm-itk | apache2-mpm-peruser, apache2.2-common" >>debian/libapache2-mod-php5.substvars [...]
Dann gib ein:

dpkg-buildpackage

...um die PHP5 Pakete wiederherzustellen:

Prüfen wir nun das Ergebnis:

cd /usr/src
ls -l

server1:/usr/src# ls -l
total 28940
-rw-r--r--  1 root src    11392 2007-10-03 19:02 apache2-mpm-itk_2.2.3-01-2.diff.gz
-rw-r--r--  1 root src      664 2007-10-03 19:02 apache2-mpm-itk_2.2.3-01-2.dsc
-rw-r--r--  1 root src    29071 2006-10-31 00:04 apache2-mpm-itk_2.2.3-01.orig.tar.gz
drwxr-xr-x  5 root root    4096 2008-08-16 13:40 apache2-mpm-peruser-2.2.3-01
-rw-r--r--  1 root src      353 2008-08-16 13:36 apache2-mpm-peruser_2.2.3-01-1.dsc
-rw-r--r--  1 root src      710 2008-08-16 13:40 apache2-mpm-peruser_2.2.3-01-1_i386.changes
-rw-r--r--  1 root src   165438 2008-08-16 13:40 apache2-mpm-peruser_2.2.3-01-1_i386.deb
-rw-r--r--  1 root src    50282 2008-08-16 13:36 apache2-mpm-peruser_2.2.3-01-1.tar.gz
-rw-r--r--  1 root root 6364431 2008-03-22 10:35 apache2.tar.gz
-rw-r--r--  1 root src  2413278 2008-08-16 14:30 libapache2-mod-php5_5.2.0-8+etch11_i386.deb
-rw-r--r--  1 root src  2412784 2008-08-16 14:30 libapache-mod-php5_5.2.0-8+etch11_i386.deb
drwxr-xr-x 20 root root    4096 2008-08-16 14:29 php5-5.2.0
-rw-r--r--  1 root src     1040 2008-08-16 14:30 php5_5.2.0-8+etch11_all.deb
-rw-r--r--  1 root src   914599 2008-08-16 13:55 php5_5.2.0-8+etch11.diff.gz
-rw-r--r--  1 root src     1741 2008-08-16 13:55 php5_5.2.0-8+etch11.dsc
-rw-r--r--  1 root src     4768 2008-08-16 14:30 php5_5.2.0-8+etch11_i386.changes
-rw-r--r--  1 root src  8583491 2006-11-07 13:34 php5_5.2.0.orig.tar.gz
-rw-r--r--  1 root src  4757790 2008-08-16 14:30 php5-cgi_5.2.0-8+etch11_i386.deb
-rw-r--r--  1 root src  2397698 2008-08-16 14:30 php5-cli_5.2.0-8+etch11_i386.deb
-rw-r--r--  1 root src   215284 2008-08-16 14:30 php5-common_5.2.0-8+etch11_i386.deb
-rw-r--r--  1 root src    24478 2008-08-16 14:30 php5-curl_5.2.0-8+etch11_i386.deb
-rw-r--r--  1 root src   344780 2008-08-16 14:30 php5-dev_5.2.0-8+etch11_i386.deb
-rw-r--r--  1 root src    33426 2008-08-16 14:30 php5-gd_5.2.0-8+etch11_i386.deb
-rw-r--r--  1 root src    34508 2008-08-16 14:30 php5-imap_5.2.0-8+etch11_i386.deb
-rw-r--r--  1 root src    44362 2008-08-16 14:30 php5-interbase_5.2.0-8+etch11_i386.deb
-rw-r--r--  1 root src    17250 2008-08-16 14:30 php5-ldap_5.2.0-8+etch11_i386.deb
-rw-r--r--  1 root src    12844 2008-08-16 14:30 php5-mcrypt_5.2.0-8+etch11_i386.deb
-rw-r--r--  1 root src     5052 2008-08-16 14:30 php5-mhash_5.2.0-8+etch11_i386.deb
-rw-r--r--  1 root src    64620 2008-08-16 14:30 php5-mysql_5.2.0-8+etch11_i386.deb
-rw-r--r--  1 root src    34060 2008-08-16 14:30 php5-odbc_5.2.0-8+etch11_i386.deb
-rw-r--r--  1 root src    50482 2008-08-16 14:30 php5-pgsql_5.2.0-8+etch11_i386.deb
-rw-r--r--  1 root src     8632 2008-08-16 14:30 php5-pspell_5.2.0-8+etch11_i386.deb
-rw-r--r--  1 root src     4774 2008-08-16 14:30 php5-recode_5.2.0-8+etch11_i386.deb
-rw-r--r--  1 root src    11308 2008-08-16 14:30 php5-snmp_5.2.0-8+etch11_i386.deb
-rw-r--r--  1 root src    34160 2008-08-16 14:30 php5-sqlite_5.2.0-8+etch11_i386.deb
-rw-r--r--  1 root src    18414 2008-08-16 14:30 php5-sybase_5.2.0-8+etch11_i386.deb
-rw-r--r--  1 root src    16482 2008-08-16 14:30 php5-tidy_5.2.0-8+etch11_i386.deb
-rw-r--r--  1 root src    36458 2008-08-16 14:30 php5-xmlrpc_5.2.0-8+etch11_i386.deb
-rw-r--r--  1 root src    12258 2008-08-16 14:30 php5-xsl_5.2.0-8+etch11_i386.deb
-rw-r--r--  1 root src   311360 2008-08-16 14:30 php-pear_5.2.0-8+etch11_all.deb
server1:/usr/src#

Wir können das neue PHP5 Paket folgendermassen installieren:

dpkg -i php5*.deb
dpkg -i libapache2-mod-php5_5.2.0-8+etch11_i386.deb

Dieses Mal wird es sich nicht mehr über das fehlende Apache2-MPM-prefork Paket beschweren, da Apache2-MPM-peruser installiert wurde und das für das neue Paket ausreicht.

Wir müssen nur noch das PHP5 Modul aktivieren und Apache neu starten:

a2enmod php5
/etc/init.d/apache2 restart

Öffne die phpinfo(); Seite erneut im Browser - es sollte nun peruser anstatt prefork in der Loaded ModulesZeile unter apache2handler anzeigen:


5 Links