Serveur web mutualisé (3/5) : Architecture basique

I. Présentation

Dans de précédents billets (concept et limites), nous avons vu en quoi un serveur web mutualisé consistait et quelles étaient leurs limités générales. Nous allons ici aborder un post un peu plus technique où nous allons, pour mieux les comprendre, monter une architecture système qui nous permettrait de faire tourner un serveur web mutualisé (aussi basique soit il). Je ne prétends pas ici révolutionner le serveur web mutualisé mais au contraire montrer de quoi il est, en théorie, composé et faire en sorte que les services que nous allons installer permettent un fonctionnement global pouvant être assimilé à celui d'un serveur web mutualisé.

II. De quoi a t-on besoin ?

Comme nous l'avons résumé dans le précédent billet sur le sujet, nous avons vu que le serveur web mutualisé a besoin de plusieurs services basiques pour être considéré en tant que tel :

SRVMUT01

Chaque accès utilisateurs ayant alors besoin d'un accès au FTP, au minimum une base de données et d'un système pouvant comprendre et traiter les requêtes HTTP de ses clients.

III. Installation

Nous allons ici partir sur une base d'une machine sous Debian 7 à jour sans système de sécurité particulier (type Selinux). Une machine standard en somme sur laquelle nous allons installer nos différents services. On commence bien entendu par mettre à jour notre liste de dépôt :

apt-get update

Puis on pourra commencer par installer notre service web :

apt-get install apache2 php5

On installera également notre service de base de données ainsi que l'ensemble des fonctions qui permettront au PHP de communiquer et de communiquer avec ce service :

apt-get install mysql-server php5-mysql

On installe ensuite notre service FTP pour que les utilisateurs puissent manager le tout à distance :

wget http://http.us.debian.org/debian/pool/main/v/vsftpd/vsftpd_3.0.2-3_amd64.deb -O vsftpd.deb 
dpkg -i vsftpd.deb 

On va éviter de donner un accès shell à nos utilisateurs, on va donc leur donner tout de même la possibilité de manager leurs bases de données via une interface prévu à cet effet :

apt-get install phpmyadmin

On a ici un début de quelque chose, la base tout du moins. Il ne nous reste plus qu'à réfléchir sur leur configuration puis à la mettre en place.

Note : Sur des infrastructures réelles, les hébergeurs peuvent être amenés à mettre des services supplémentaires comme des services de caches, des services de surveillance des accès, de monitoring des ressources utilisées. etc. Nous aurons surement l'occasion de les étudier en détail plus tard.

SRVMUT97

IV. Les besoins de configuration

Nous allons à présent réfléchir sur comment les services doivent être calibrés et configurés pour avoir un fonctionnement global se rapprochant au maximum d'un serveur web mutualisé, le plus basique soit il. Nous avons déjà ciblé les services à mettre en place. Réfléchissons sur les points de configuration qu'il va falloir calibrer.

A. Apache/ PHP

Notre serveur Apache va être utilisé par plusieurs dizaines, centaines voire milliers de sites web en même temps qui génèrent eux aussi des milliers de visites par jour. Il faut donc penser à adapter sa configuration en conséquence. On vérifiera les valeurs de connexions simultanées par défaut et on les adaptera si besoin. On prévoira également un dossier web par client ainsi qu'un vHost pour chacun d'entre eux.

B. VSFTP

Chaque utilisateur doit avoir accès à son espace web, et pas à celui du voisin. On doit donc éviter qu'un utilisateur puisse remonter l'arborescence du serveur pour aller s'y balader dans son client FTP. On mettra, de façon plus technique, un chroot sur l'accès FTP de chaque utilisateur. On se basera sur la base utilisateur du système pour se connecter. C'est un choix qui n'est peut être pas judicieux mais qui est le plus utilisé aujourd'hui (pour sa simplicité principalement), il faut donc veiller à ce que les utilisateurs d'administration (root par exemple) ne puisse pas avoir d'accès FTP. Eh bien oui, si "client1" a envie de tester un mot de passe pour accéder au compte FTP de root, il sera bien qu'il n'y arrive pas... On y déterminera également les droits qui seront par défaut affectés aux fichiers uploadés pour que ceux-ci soient lisibles par apache directement sans intervention de l'administrateur. Nous verrons cela dans un deuxième temps car cela introduira le prochain billet sur les risques que cela engendre.

C. MySQL

Notre base de données, comme notre serveur Apache va subir un nombre très important de requêtes en simultané. Il faudra donc également adapter les valeurs de connexion maximales en conséquence. On prendra également soin de donner un accès dédié à chaque base de données client pour chaque client. Il est évident qu'un client ne devra pas avoir accès à la base de donnée du voisin !

D. Linux, groupe, droits et home

Comme dit précédemment, nous utiliserons les comptes UNIX pour créer les accès utilisateurs. On y déterminera leurs droits, le groupe dans lequel ils seront, leur mot de passe, leur "home" qui correspondra à leur chroot FTP, etc. C'est un point central de la configuration du serveur.

E. Arborescence

Nous allons mettre en place une arborescence logique où nous pourrons nous y retrouver facilement parmi les futurs milliers de sites web qui viendront s'y déposer ;). Il nous faut :

  • Un répertoire pour les utilisateurs contenant un emplacement où stocker leur site web, c'est sur ce répertoire que chaque vHost d'Apache pointera.
  • Un répertoire pour les logs de chaque site, il est difficilement envisageable de tout stocker dans un seul et unique fichier.
  • Un emplacement pour les sessions/upload temporaires PHP.

V. Configuration

Nous allons maintenant passer à la configuration de nos différents services. Afin de mieux vous faire comprendre la problématique du serveur web mutualisé, je vais volontairement dans un premier temps oublier des modifications de configuration que je corrigerais dans le dernier chapitre de cet article. Le but est simplement de vous montrer qu'avec une configuration par défaut (standard), on ne peut monter un serveur web mutualisé et que nous sommes obligé d'ouvrir des accès qui peuvent être dangereux pour qu'un serveur web mutualisé soit monté. Cet aspect sécurité sera expliqué plus en détail par la suite.

A. Création de l'arborescence

On va donc commencer par créer notre arborescence, on va par exemple décider de tout stocker dans "/storage" en supposant par exemple que c'est le montage d'un deuxième cluster de disque en RAID 1 (au minimum) et que notre premier disque est donc un disque réservé au système :

mkdir /storage

On va dire que les accès clients seront dans les répertoires "/storage/web/www-client1", "/storage/web/www-client2" et ainsi de suite, les sessions dans "/storage/web/sessions" et les uploads temporaires dans "/storage/web/uploads". Les Logs étant des éléments critiques, nous les mettrons dans "/storage/logs". On pensera également à leur rotation au moment voulu. Enfin on créera par sécurité un dossier vide pour qu'Apache amène les utilisateurs qui tentent des accès un peu suspicieux à l'intérieur. Par exemple "/storage/web/default" :

mkdir /storage/web
mkdir /storage/web/default
mkdir /storage/web/sessions
mkdir /storage/web/uploads
mkdir /storage/logs

Voilà une arborescence de base, nous l'étofferons au fur et à mesure si besoin. On met ensuite Apache en groupe  et propriétaire de toute cette arborescence web, sinon il ne pourra aller lire les fichiers qui s'y situent.

chown www-data:www-data /storage/web -Rf

On va également enlever les droits "other" sur ces répertoires pour que tout le monde ne puisse pas tout lire par défaut :

chmod 770 /storage/web -Rf

B. Configuration du service HTTP - Apache

Nous allons commencer par modifier la configuration de base d'Apache. Nous nous occuperons des vHosts clients après leur création (sous peine de créer une erreur au redémarrage d'apache car les répertoires spécifiés n'existeront pas ;)). On va donc modifier le fichier "/etc/apache2/apache2.conf" où nous irons chercher et modifier ces différentes valeurs (elle sont réparties dans le fichier de configuration voire commentées pour certaines) :

ServerTokens Prod
MaxClients 500
ServerLimit 500
ServerSignature Off
NameVirtualHost *:80
  •  J'ai déjà expliqué l'intérêt de modifier les valeurs ServerTokens et ServerSignature dans ce tutoriel que je vous invite à aller voir si vous avez besoin de plus de précisions.
  • La valeur MaxClient du fichier de configuration d'Apache2 permet de fixer le nombre maximal de connexions qui pourront être traitées de façon simultanées, les autres seront mises dans une fil d'attente. Comme nous l'avons précisé plus haut, nous aurons énormément de connexions sur notre serveur web mutualisé, il convient donc d'élever cette barrière qui est à 150 par défaut, il est en lien avec "ServerLimit" que nous modifions également, les valeurs sont à adapter selon la puissance de voter serveur et la charge de celui-ci, il s'agit ici d'un exemple.
  • On déclare ensuite que nos vHost se positionneront sur le port 80.

On ira ensuite modifier le fichier "/etc/apache/sites-enabled/000-default" qui contient la configuration du site par défaut. En effet, celui-ci pointe toujours sur "/var/www". Nous allons donc changer la valeur "Directory" et "DocumentRoot" pour les faire pointer vers "/storage/web/default". On pourra ensuite recharger une première fois notre service http :

service apache2 reload

C. PHP

Nous allons à présent modifier quelques paramètres au niveau de la configuration générale de PHP :

vim /etc/php5/apache2/php.ini

A nouveau, nous irons trouver et/ou décommenter certains paramètres. D'abord on précisera le chemin du répertoire d'upload temporaire. PHP se sert de ce répertoire pour uploader de façon temporaire les fichiers des utilisateurs (via le web, rien à voir avec le FTP) puis pour les vérifier (par un système antivirus par exemple ou pour des vérifications de format), une fois l'upload terminé, il transfert ce fichier vers son emplacement réel :

upload_tmp_dir = /storage/web/uploads

Même chose pour les fichiers de sessions PHP :

session.save_path="/storage/web/sessions"

On précise combien de mémoire nous souhaitons allouer au processus PHP :

memory_limit = 256M

On pourra à nouveau redémarrer Apache pour être certain que ces paramètres sont bien pris en compte :

service apache2 reload

D. MySQL

Nous allons également apporter quelques modifications à la configuration de base de notre service de base de données (Mysql server) pour qu'il s'adapte à la charge qu'il est susceptible de supporter. On va pour cela modifier le fichier ("/etc/mysql/my.cnf") pour changer certaines valeurs qui permettent d'augmenter le nombre de requêtes et la taille des requêtes que MySQL peut supporter. Parmi ces valeurs qu'il faut adapter selon la puissance du serveur, on trouve Max_allowed_paquet, max_connexions ou encore open_files_limit.

F. Logs et PhpMyadmin

Je mets ces deux éléments dans le même sous-titre car ils n'ont aucune importance dans le contexte du tutoriel et de ce que je souhaites démontrer. On va donc installer phpmyadmin :

apt-get install phpmyadmin

La configuration de PhpMyadmin prévoit automatiquement un alias qui sera disponible pour chaque URL (ex : www.blog1.fr/phpmyadmin)

Pour les logs on indique simplement notre répertoire de logs personnalisés dans /etc/logrotate.d/apache2/ de la façon suivante :

/storage/logs/*/*log {
weekly
compress
missingok
notifempty
sharedscripts
delaycompress
endscript
}

Puis on redémarre les services affectés :

service apache2 reload
service rsyslog reload

Nous indiquerons également dans la configuration Apache la répartition des logs par vHosts.

E. FTP avec VSFTPD

Nous allons enfin configurer notre service FTP. La chose la plus importante à configurer autour de ce service est le chroot qui permettra de restreindre chaque utilisateur utilisant son compte FTP à son seul répertoire web, l'empêchant ainsi d'aller dans celui des voisins ou autre part dans le serveur. Je vous mets ici le fichier de configuration complet de vsftpd qui peut, quand on ne le connais pas, être un peu complexe à configurer, "/etc/vsftpd/vsftpd.conf" :

anonymous_enable=NO
local_enable=YES
write_enable=YES
dirmessage_enable=YES
use_localtime=YES
dual_log_enable=YES
xferlog_enable=YES
xferlog_file=/var/log/vsftpd.xfer.log
log_ftp_protocol=YES
vsftpd_log_file=/var/log/vsftpd.log
connect_from_port_20=YES
chroot_local_user=NO
chroot_list_enable=YES
chroot_list_file=/etc/vsftpd.chroot_list
secure_chroot_dir=/var/run/vsftpd/empty
pam_service_name=vsftpd
rsa_cert_file=/etc/ssl/private/vsftpd.pem
allow_writeable_chroot=YES

 On commence bien sûr par rendre l'authentification et l'accès anonyme impossible en désactivant ce type d'accès. On va ensuite indiquer que nous allons chrooter nos utilisateurs en mettant la variable "chroot_local_user" à NO puis en activant la chroot list que nous indiquerons à la ligne suivante. Il s'agira d'un fichier texte possédant la liste des utilisateurs à chrooter (un utilisateur par ligne). On autorise ensuite l’affichage des fichiers cachés (ceux qui commencent par un ".") pour que nos utilisateurs puissent, par exemple manager leur fichier .htaccess. On pourra ensuite redémarre notre service VSFPD :

service vsftpd reload

 F. Création d'un utilisateur

Nous allons à présent créer deux accès pour faire nos tests et vérifier que notre petit bout de serveur fonctionne. On utilisera pour cela la commande adduser puis passwd pour affecter les mots de passe, on crée par exemple deux espaces web "blog1" et "blog2" :

adduser user-blog1 -d /storage/web/www-blog1 
passwd blog1
adduser user-blog2 -d /storage/web/www-blog2 
passwd blog2
chmod 770 /storage/web/www-blog1 /storage/web/www-blog2

On précise donc le nom des utilisateurs ainsi que leur "home" qui sera également leur répertoire web et chroot FTP. On crée également les répertoires de logs :

mkdir /storage/logs/www-blog1
mkdir /storage/logs/www-blog2
chmod 777 /storage/logs -Rf

Leur base de données respectives dans MySQL :

create database sql01blog1;
create user "user_blog1"@"localhost" identified by "password";
grant all privileges on sql01blog1.* to "user_blog1"@"localhost";

Puis on fait la même chose pour l'utilisateur blog2 et sa base de données :

create database sql01blog2;
create user "user_blog2"@"localhost" identified by "password";
grant all privileges on sql01blog2.* to "user_blog2"@"localhost";

On va ensuite ajouter nos deux utilisateurs dans la liste des utilisateurs chrooté, pour rappel, un utilisateur par liste pour le fichier "/etc/vsftpd/chroot_list" :

mkdir /etc/vsftpd
user_blog1
user_blog2

On va ensuite créer la configuration Apache pour chacun des site. www.blog1.fr et www.blog2.fr

Note : J'utilise mon fichier hosts au niveau DNS pour tester rapidement ces accès.

On passe maintenant à la configuration Apache. On va utiliser un fichier de configuration par espace web ("/etc/apache2/sites-enabled/blog1.conf" et blog2.conf par exemple) dans lesquels on mettra cette configuration :

<VirtualHost *:80>
        ServerAdmin webmaster@localhost
        ServerName www.blog1.fr
        DocumentRoot /storage/web/www-blog1
        Alias /database/ "/usr/share/php5/phpmyadmin/"
        ErrorLog "/storage/logs/www-blog1/blog1.error.log"
        CustomLog "/storage/logs/www-blog1/blog1.access.log" common
        <Directory /storage/web/www-blog1>
                Options -Indexes FollowSymLinks MultiViews
                AllowOverride None
                Order allow,deny
                allow from all
        </Directory>
</VirtualHost>

Note : Remplacer blog1 par blog2 pour configuration du deuxième site

On pourra redémarrer le tout :

service vsftp reload
service apache2 reload

VI. Test des accès

Pour tester notre accès, on va simplement faire un fichier "index.php" qui affichera "Bonjour blog1" :

<html>
<body>
<?php
   echo "Bonjour blog1";
?>
</body>
</html>

A.Uploader d'un fichier web via FTP

On va donc se connecter à notre service FTP, j’utiliserai FileZilla pour cela :

SRVMUT02

Première chose , on voit que nous sommes bien chrooté et que nous ne pouvons pas  remonter sur le serveur pour aller se balader. On upload donc notre fichier index.php et on va alors sur notre navigateur sur l'URL www.blog1.fr pour y voir notre fichier...

B. Ca ne marche pas !!

Eh oui ça ne marche pas, comme je l'ai dit précédemment. Le but de ce poste est de vous montrer qu'avec des droits et des paramètres par défaut, l'ensemble ne peut fonctionner pour un système mutualisé. Ici, le transfert de fichiers se fait via FTP, ceux-ci prennent donc user_blog1 en propriétaire et en groupe et doit être lu par www-data pour être affiché en HTTP. On est donc obligé d’élargir les droits et de donner des permissions supplémentaires. On doit donc faire en sorte qu'apache puisse lire les fichiers uploadés. On a deux choix, soit on donne les permissions de lecture et d'exécution à "other" via :

chmod o+rx /storage/web -Rf

Mais il faudra réaffecter ces droits à chaque nouveau fichier uploadé. Sinon on peut mettre tous les utilisateurs web dans le groupe d'Apache et ensuite dire dans la configuration vsftpd que les fichiers uploadés doivent être lisibles par le groupe de celui qui les uploads. En d'autres mots, il faut dire à vsftpd que les fichiers uploadés par les utilisateurs doivent être exécutables, modifiables et lisibles par le propriétaire et au moins son groupe, qui pour l'instant est son propre groupe. Dans un deuxième temps on mettra les utilisateurs web dans le groupe apache pour que l'utilisateur Apache dispose des droits de lecture sur ces fichiers de façon automatique.

C. Correction / le début des ennuis !

On commence donc par automatiser le fait que tous les fichiers uploadés pourront être lu par "other" pour qu'apache puisse y accéder, on effectue cette modification dans VSFTPD :

local_umask= 002

Pour que les fichiers en question soient exécutables (il faut bien que nos scripts php s'exécutent) il faut également ajouter cette option :

file_open_mode=0777

On redémarre ensuite vsftpd pour que les changements de configuration soient pris en compte :

service vsftpd restart

On met ensuite nos utilisateurs dans le groupe Apache :

adduser user_blog1 www-data
adduser user_blog2 www-data

On peut alors essayer d'uploader à nouveau notre index.php et on verra alors les droits du fichier se mettre en rwxrwxr-x. Pour rappel, les droits du répertoire au dessus ("/storage/web/www-userblog1") sont :

rwxrwx---  user_blog1 www-data

Autrement dit, l'utilisateur peut y écrire, www-data aussi (ce qui est utile dans le cadre d'un wordpress par exemple) qui crée des fichiers en tant que www-data. Nous pourrons rester via navigateur et voir que cela fonctionne. Seulement voilà, quand on y réfléchit nous avons un petit problème de droit. La permission rwxrwxr-x est quand même bien permissive,  tout les utilisateurs du système ont le droit de lire les fichiers des répertoires web. Je vous laisse y méditer jusqu'au prochain billet où je développerais cette problématique.

Les autres articles :

Partagez cet article Partager sur Twitter Partager sur Facebook Partager sur Linkedin Partager sur Google+ Envoyer par mail

Mickael Dorigny

Co-fondateur d'IT-Connect.fr. Auditeur/Pentester chez Orange Cyberdéfense.

Nombre de posts de cet auteur : 523.Voir tous les posts

7 thoughts on “Serveur web mutualisé (3/5) : Architecture basique

  • Salute,

    Quelques petites erreurs :
    service apache2 relaod –> service apache2 reload
    adduser ussr_blog2 –> add user_blog2

    Dans les paquets que tu proposes d’installer, il ne va pas manquer libapache2-mod-php5 ? D’ailleurs il faudrait rajouter logrotate.

    Ce serait top aussi de rajouter les # et les $ en début de ligne voire les mysql> afin qu’on comprenne bien tout.

    Une raison que tu n’utilises pas ces paramètres dans vsftpd ?
    chroot_local_user=YES
    # On autorise les utilisateurs virtuels à se mapper sur un compte local #
    guest_enable=yes
    # On autorise l’utilisation des privilèges des utilisateurs locaux pour les utilisateurs virtuels #
    virtual_use_local_privs=YES
    # L’utilisateur virtuel user-blog1 est mappé sur le compte local www-data #
    guest_username=www-data

    Super boulot et sacré tuto ! Bravo !

    Tcho !

    Répondre
    • Bonjour, merci pour tes corrections. Je vais m’occuper de cela. Pour libapache2-mod-php5, il s’installe automatique avec php5 si apache est installé (Sous Debian du moins).

      Les paramètres que tu proposes pour VSFPTd me semble concorder avec le fonctionnement que je propose. Je ferait des test, tu prends le problème dans l’autre sense, au lieu d’ouvrir les droits à www-apache, tu le mets en pseudo-propriétaire, ca me semble intéressant et fonctionnel. Néanmoins je t’invite à suivre les tutoriels qui sortiront prochainement et qui sont la suite de ce tuto, j’y indiquerais des problèmes de sécurité quant à l’ouverture des droits comme nous le faisons.

      Merci pour ta contribution =)

      Répondre
  • La permission rwxrwxr-x est quand même bien permissive, tout les utilisateurs du système ont le droit de lire les fichiers des répertoires web.

    Comprendre : ussr_blog2 aura accès en lecture aux fichiers de ussr_blog1 ?

    Répondre
    • Bonjour Teh,

      Oui c’est exacte, c’est ce que je vais développer dans la prochaine partie de ce dossier, le billet sort mardi. Je t’invite à le lire lors de sa sortie, j’y développe le problème de sécurité que nos derniers ajustement fait dans ce tutoriel amènent. Mais oui tu as effectivement raison, le fonctionnement que nous développons dans un serveur web mutualisé fait que user_blog2 aura accés à user_blog1. Heureusement on suppose ici que nos utilisateurs n’ont pas de shell sur le serveur, auquel cas il faut mettre des barrières de sécurité autre. Mais il reste plusieurs moyens d’aller sur le dossier du voisin, encore une fois je te laisse y réfléchir, je le développerais dans le billet de mardi prochain 😉

      Répondre
  • bonjour Mickael.
    Pour ces tutos Vous préciser que vous utilisez une debian 7 (Wheezy) on ne peut plus classique.
    Vous avez choisi pour Vstpd comme serveur ftp.
    Le dernier disponible ds les dépots Debian est la 2.3.5-3.
    Comme moi vous avez optez pour une version plus récente une 3.0.2-X ( wget ….)
    Par contre je suis étonné que vous avez pas connu de problèmes de dépendances notamment la libc6.
    Pour une version récente vsftpd réclame au moins une 2.15 alors que par défaut debian 7 n’offre que la version 2.13.
    Il existe des « bidouilles » pour installer une version 2.15 ou plus. Mais cela est déconseillé parce que cela peut casser le fonctionnement d’autres logiciels.
    En gros comment avez vous fait pour contourner ce problème ?

    Répondre
  • Manque plus que les boîtes mail virtuelles par user et c’est parfait

    Répondre
  • Bravo tout est décrit avec beaucoup de pédagogie et de clarté.
    Super boulot !
    Merci.

    Répondre

Répondre à Mickael Annuler la réponse

Votre adresse e-mail ne sera pas publiée. Les champs obligatoires sont indiqués avec *

Ce site utilise Akismet pour réduire les indésirables. En savoir plus sur comment les données de vos commentaires sont utilisées.