Configuring apache2 with fastcgi & suExec [fr]

Introduction

L’utilisation de mod_fastcgi couplé à la fonctionnalité suExec d’apache permet de faire tourner des processus supportant CGI (comme PHP, Django…), chacun avec un utilisateur spécifique. Ainsi, il devient possible d’héberger plusieurs sites sur une machine, et chaque site tournera avec des privilèges différent : Si du code malicieux est introduit sur un site, il n’aura pas les permissions pour accéder aux autres sites, puisque tournant avec un utilisateur différent. Cette méthode convient donc très bien pour monter un petit service d’hébergement sur un serveur (à condition de gérer correctement les droits d’accès…).

Les processus CGI restant en marche, les performances sont donc très bonnes. Toutefois, il y aura (au moins) un processus CGI par utilisateur, donc la consommation de mémoire vive peut vite devenir assez élevée.

suExec

Tout d’abord, installez suExec :

apt-get install apache2-suexec

Il n’y a pas de configuration à faire, tout étant codé en dur pour des raisons de sécurité. Notez que sous debian, un paquet apache2-suexec-custom est aussi disponible, et peut être configuré, notamment pour changer le répertoire web racine.

mod_fastcgi

apt-get install libapache2-mod-fastcgi
a2enmod fastcgi

Modifiez votre /etc/apache2/mods-enabled/fastcgi.conf et mettez-y ceci :

<IfModule mod_fastcgi.c>
    AddHandler fastcgi-script .fcgi
    FastCgiWrapper /usr/lib/apache2/suexec
    FastCgiIpcDir /var/lib/apache2/fastcgi
    FastCgiConfig -idle-timeout 70 -maxClassProcesses 3 -minProcesses 0 -init-start-delay 3 -restart-delay 20 -startDelay 15
</IfModule></code>

La ligne FastCgiConfig est facultative et définit diverses options de configuration. La configuration que j’utilise est adaptée a un petit serveur, pour des sites recevant peu de visites, mais vous êtes libre de la modifier. Cf: la documentation.

Site utilisant PHP

Voyons désormais comment mettre en place un VirtualHost pour un site utilisant PHP :

Dans mon exemple, le VirtualHost sera localisé dans /var/www/checksam, et le processus PHP tournera avec l’utilisateur checksam.

Commencez par créer un répertoire cgi-bin dans /var/www/checksam et mettez y un fichier php.fcgi contenant :

#!/bin/sh
export PHP_FCGI_CHILDREN=0
exec /usr/bin/php-cgi</code>

Si, pour ce VirtualHost, vous souhaitez lancer PHP avec l’utilisateur checksam et le groupe checksam, alors vous devez attribuer aux fichier php.fcgi ce même couple utilisateur/groupe. Mettez-y un chmod 700.

Voici à quoi doit ressembler le VirtualHost pour ce site :

<VirtualHost *:80>
    ServerName www.checksam.fr
    DocumentRoot /var/www/checksam
    SuexecUserGroup checksam checksam # lance PHP en tant qu'utilisateur checksam (groupe checksam).
    # support des scripts PHP
    ScriptAlias /cgi-bin /var/www/checksam/cgi-bin
    Action application/x-httpd-php /cgi-bin/php.fcgi
</VirtualHost>

Site utilisant Django

Supposons maintenant que je souhaite avoir un autre site (utilisant Django), nommé djangosite et tournant avec l’utilisateur djangosite. Le site sera localisé dans /var/www/djangosite.

Je crée un fichier /var/www/djangosite/django.fcgi contenant :

#!/usr/bin/env python
import os, sys
from flup.server.fcgi import WSGIServer
from django.core.handlers.wsgi import WSGIHandler
sys.path.insert(0, '/var/www/djangosite/')
os.environ['DJANGO_SETTINGS_MODULE'] = 'settings'
WSGIServer(WSGIHandler()).run()

Comme dans le cas de PHP, je dois mettre les bonnes permissions au fichier django.fcgi:

chown djangosite:djangosite django.fcgi
chmod 700 django.fcgi

Et voici le contenu du VirtualHost :

<VirtualHost *:80>
    ServerName www.djangosite.tld
    DocumentRoot /var/www/djangosite
    SuexecUserGroup djangosite djangosite
    Alias /static /var/www/djangosite/static
    ScriptAlias / /var/www/djangosite/django.fcgi/
</VirtualHost>

Conclusion

Le procédé est donc très facilement adaptable à tout langage pouvant tourner en CGI :)

Il devient donc possible de gérer finement les droits d’accès pour chaque site, et d’interdire toute interaction ou accès aux données d’un site vers un autre..

Pour renforcer la sécurité, il est même possible d’utiliser iptables pour interdire l’accès internet aux utilisateurs faisant tourner les sites : la communication avec les processus CGI passe par des socket UNIX ou par l’interface loopback. L’utilisateur les faisant tourner peut donc ne pas avoir accès à internet, ce qui empéche toutes les failles d’inclusion distantes, l’envoi de fichier sur le serveur, ou même l’utilisation du site comme base pour effectuer des actions malveillantes sur internet en cas de piratage.

Annexe : en cas de problème

Si vous avez des difficultés à faire fonctionner votre système, regardez les fichiers logs d’apache, mais sachez aussi que SuExec a son propre fichier de log nommé suexec.log dans le répertoire des logs d’apache.

Vous pouvez aussi regarder cette page, qui liste les conditions devant être vérifiées pour que SuExec accepte de fonctionner.