Il y a quelques temps il me devenait nécessaire de sécuriser un serveur Apache2 sous environnement Debian/Ubuntu Server de manière assez restrictive. Celui-ci dispose bien évidemment de MySQL5, PHP5 et de diverses autres bibliothèques.
L’objectif était de déployer un mini-service d’hébergement composé de plusieurs sites, tous aussi différents les uns que les autres. Certains de ces sites devraient avoir la possibilités d’exécuter des commandes spéciales sur le serveur, d’accéder à des binaires bien définis, et d’effectuer des requêtes au travers de l’Internet spécifiques.
Après une multitude de tests divers et variés sur comment cloisonner ses serveurs Apache2/MySQL5 via un chroot, je finissais toujours par bloquer face à une ressource ou une bibliothèque en dehors du chroot pour les fonctionnalités du site… Je passais mon temps à intégrer dans le chroot des fichiers/liens pour que mes services accèdent aux ressources nécessaires…
Que cette tâche fût fastidieuse, et à vrai dire la solution finale ne me convenait pas en termes d’évolution. En discutant avec un ami, Jill, que je remercie pour son temps consacré, nous avons opté pour une solution bien plus drastique, plus simple, plus lourde et selon moi mieux adaptée à mes besoins en termes de dépendances externes au chroot.
L’idée est de déployer une autre distribution complète (Debian squeeze en l’occurrence), de manière inerte, au sein du serveur actuel. Cette distribution complète se verrait installer tous les services/outils/démons/bibliothèques nécessaires, et chaque processus serait chrooté dans cette distribution. Bien plus simple à la gestion ! Mais en contrepartie plus lourde sur le système hôte. Cette méthode peut être apparentée au déploiement d’une nouvelle distribution au sein d’un système sain (telle de la virtualisation), sans que cette distribution soit directement active (elle reste inerte dans son chroot).
Comment faire cela? La solution : debootstrap. Ce paquet permet de récupérer une distribution Debian sur les serveurs officiels et en fait une réplique locale.
root@ubuntu:/home/x# apt-get update && apt-get upgrade root@ubuntu:/home/x# apt-get install debootstrap root@ubuntu:/home/x# mkdir -p /chroot/web/ root@ubuntu:/home/x# debootstrap squeeze /chroot/web/ http://ftp.debian.org/debian [...] I: Base system installed successfully.
A la suite de ces commandes, l’environnement Debian Squeeze qui accueillera le chroot est fin prêt. Si votre souhait est de scinder plusieurs serveurs applicatifs dans des prisons différentes, il sera possible aisément de le faire dans « /chroot/ftp/ » pour un serveur FTP par exemple. La dernière commande « debootstrap » récupère une distribution Debian complète et la déploie dans « /chroot/web/ ». Cette étape peut être un peu longue en fonction de votre connexion.
Une fois le debootstrap d’achevé, il suffit de se chrooter sur cette nouvelle distribution :
root@ubuntu:/home/x# chroot /chroot/web/ root@ubuntu:/# apt-get update && apt-get upgrade root@ubuntu:/# apt-get install apache2 mysql-server php5 phpmyadmin
Une fois chrooté dans la nouvelle distribution, on met à jour sa liste de paquets et on installe les paquets nécessaires à notre service Web (ou un quelconque autre). Après l’installation, si l’on démarre Apache, un avertissement concernant le « FQDN » nous est indiqué :
root@ubuntu:/# /etc/init.d/apache2 start Starting web server: apache2apache2: Could not reliably determine the server's fully qualified domain name, using 192.168.0.137 for ServerName
Pour désactiver ce message, il suffit de renseigner la directive « ServerName localhost » dans le fichier de configuration d’Apache :
root@ubuntu:/# nano /etc/apache2/apache2.conf root@ubuntu:/# /etc/init.d/apache2 stop Stopping web server: apache2. root@ubuntu:/# /etc/init.d/apache2 start Starting web server: apache2.
Idem, il se peut qu’il y ait régulièrement des messages d’avertissement liés aux « locales » de la Debian chrootée :
Processing triggers for man-db ... locale: Cannot set LC_CTYPE to default locale: No such file or directory locale: Cannot set LC_MESSAGES to default locale: No such file or directory locale: Cannot set LC_ALL to default locale: No such file or directory
En effet, il est nécessaire de générer les locales français :
root@ubuntu:/# apt-get install locales root@ubuntu:/# nano /etc/locale.gen # Décomenter les "fr_FR*" et "en_US*" root@ubuntu:/# locale-gen Generating locales (this might take a while)... en_US.ISO-8859-1... done en_US.ISO-8859-15... done en_US.UTF-8... done fr_FR.ISO-8859-1... done fr_FR.UTF-8... done Generation complete.
Il ne reste plus qu’à automatiser le lancement des serveurs à partir de la distribution hôte. Pour cela, quitter le chroot (Ctrl+D) pour revenir au prompt de la distribution principale, et créer le fichier /etc/init.d/apache2Chrooted :
root@ubuntu:/home/x# nano /etc/init.d/apache2Chrooted root@ubuntu:/home/x# cat /etc/init.d/apache2Chrooted #!/bin/bash chroot /chroot/web/ /etc/init.d/apache2 $1 root@ubuntu:/home/x# nano /etc/init.d/mysqldChrooted root@ubuntu:/home/x# cat /etc/init.d/mysqldChrooted #!/bin/bash chroot /chroot/web/ /etc/init.d/mysql $1 root@ubuntu:/home/x# chmod +x /etc/init.d/apache2Chrooted root@ubuntu:/home/x# chmod +x /etc/init.d/mysqldChrooted root@ubuntu:/home/x# update-rc.d apache2Chrooted defaults update-rc.d: warning: /etc/init.d/apache2Chrooted missing LSB information update-rc.d: see <http://wiki.debian.org/LSBInitScripts> Adding system startup for /etc/init.d/apache2Chrooted ... /etc/rc0.d/K20apache2Chrooted -> ../init.d/apache2Chrooted /etc/rc1.d/K20apache2Chrooted -> ../init.d/apache2Chrooted /etc/rc6.d/K20apache2Chrooted -> ../init.d/apache2Chrooted /etc/rc2.d/S20apache2Chrooted -> ../init.d/apache2Chrooted /etc/rc3.d/S20apache2Chrooted -> ../init.d/apache2Chrooted /etc/rc4.d/S20apache2Chrooted -> ../init.d/apache2Chrooted /etc/rc5.d/S20apache2Chrooted -> ../init.d/apache2Chrooted root@ubuntu:/home/x# update-rc.d mysqldChrooted defaults update-rc.d: warning: /etc/init.d/mysqldChrooted missing LSB information update-rc.d: see <http://wiki.debian.org/LSBInitScripts> Adding system startup for /etc/init.d/mysqldChrooted ... /etc/rc0.d/K20mysqldChrooted -> ../init.d/mysqldChrooted /etc/rc1.d/K20mysqldChrooted -> ../init.d/mysqldChrooted /etc/rc6.d/K20mysqldChrooted -> ../init.d/mysqldChrooted /etc/rc2.d/S20mysqldChrooted -> ../init.d/mysqldChrooted /etc/rc3.d/S20mysqldChrooted -> ../init.d/mysqldChrooted /etc/rc4.d/S20mysqldChrooted -> ../init.d/mysqldChrooted /etc/rc5.d/S20mysqldChrooted -> ../init.d/mysqldChrooted
Les services Apache2 et MySQL5 sont à présents cloisonnés dans un chroot composé d’une distribution debian complète, idéal pour les dépendances. Les services se lancent au démarrage du serveur au travers du chroot d’eux même.
Il est conseillé de modifier vos prompts aussi bien dans la machine hôte que dans la machine chrootée, pour éviter de se perdre dans l’emplacement des commandes (coloration des prompt à régler dans /etc/bash.bashrc pour chaque machine).
Cette technique ne dispense pas par la suite de modifier la configuration de l’Apache/MySQL dans le chroot, pour supprimer les fingerprint, renforcer la sécurité, installer des modules comme mod_security, suphp, etc.
Edit du 20/12/2012 :
Dans le cas d’un déploiement debootstrap au sein d’une distribution protégée par GRSecurity au niveau du noyau, le debootstrap ne pourra s’effectuer correctement. En effet, lorsque la distribution est installée via le debootstrap, des montages de partition (/proc notamment) de manière chrootée sont réalisés automatiquement. GRSecurity dispose d’une protection pour l’exécution de commande « mount » ou encore « chmod » au sein d’un chroot, ce qui empêche le debootstrap de se finaliser :
[...] I: Extracting util-linux... I: Extracting zlib1g... W: Failure trying to run: chroot /prison/cage mount -t proc proc /proc
Pour forcer le déploiement du debootstrap malgré la protection de GRSecurity, il est nécessaire d’autoriser explicitement la commande « mount » et « chmod » dans un « chroot ». Pour cela, exécuter les commandes suivantes avant le debootstrap :
echo 0 > /proc/sys/kernel/grsecurity/chroot_deny_mount echo 0 > /proc/sys/kernel/grsecurity/chroot_deny_chmod
A noter que sur des serveurs dédiés « Kimsufi » avec une distribution installée sur le HDD local (type Ubuntu Server 12.10 64bits), GRSecurity est déployé au travers de la partition de boot, et n’est donc pas configurable de la sorte…