Permettre une authentification unifiée pour SMTP, POP/IMAP et FTP
Sommaire
Introduction
Objectif
Avoir une authentification unifiée entre services FTP, IMAP, POP3 et SMTP.
Notes
Ici il s'agira d'un "backend" PostgreSQL. L'équivalent est tout à fait imaginable pour MySQL bien entendu, à quelques détails près.
Cette solution permet, dans un second temps, de mettre en place une interface unifiée de gestion de ses comptes. Ainsi en deux clics, il sera possible de créer un compte courriel et son compte FTP associé et que tout soit mis en place très rapidement.
Pré-requis
Vous aurez sans doute besoin de prendre connaissance de la première partie de cette documentation : Paramétrer un serveur mail Postfix, Courier-IMAP avec authentification PostgreSQL et SASL
Les commandes proposées sont parfois directement liées aux infrastructures basées sur les distributions Debian (Ubuntu par exemple).
Mise en œuvre de l'authentification unifiée
Besoins et débouchés
Nous avons tout notre système de messagerie qui fonctionne déjà sur une authentification via PostgreSQL. Nous souhaitons donc appuyer l'authentification des utilisateurs virtuels de vsftpd sur ce même mécanisme.
Afin de permettre l'authentification sur PostgreSQL de vsftpd, il faut passer par pam-pgsql. Installons donc ce module de PAM si ce n'est déjà fait :
sudo apt-get install libpam-pgsql
PAM
il est nécessaire de configurer PAM pour se connecter à PostgreSQL :
$ sudo vi /etc/pam.d/vsftpd # Standard behaviour for ftpd(8). auth required pam_listfile.so item=user sense=deny file=/etc/ftpusers onerr=succeed # Note: vsftpd handles anonymous logins on its own. Do not enable # pam_ftp.so. auth required pam_pgsql.so config_file=/etc/pam.d/vsftpd.pgsql.conf account required pam_pgsql.so config_file=/etc/pam.d/vsftpd.pgsql.conf
Afin que l'authentification se fasse correctement, il faut faire connaître à PAM le schéma vu précédemment :
$ sudo vi /etc/pam.d/vsftpd.pgsql.conf debug pw_type = md5 connect = hostaddr=HOST port=5432 dbname=DB user=USER password=PASSWORD connect_timeout=15 auth_query = select substring(password from 9) from mailbox where username = %u acct_query = select NOT active AS acc_expired, 0 AS acc_new_pwreq, (password ISNULL OR password = ) as user_password from mailbox where username = %u
Vous noterez 3 points importants :
- n'oubliez pas d'entrer vos paramètres pour permettre à PAM de se connecter à votre base de données
- le mot de passe est en clair (cf. ci-après)
- la requête spécifiée pour récupérer le mot de passe en base de données a été sensiblement adaptée par "substring(password from 9)" car vfstpd ne comprend pas le préfixe nécessaire à Postfix {MD5RAW}, que nous retirons donc artificiellement via ce hack.
afin d'éviter toute fuite d'information, nous ne pouvons que vous recommander de changer les droits du dernier fichier créé :
$ sudo chmod 640 /etc/pam.d/vsftpd.pgsql.conf
vsftpd
Enfin, pour ne pas que vsftpd fasse de correspondance entre nos utilisateurs virtuels et nos utilisateurs réels, nous allons le paramétrer en ce sens en rajoutant à votre configuration personnalisée :
$ sudo vi /etc/vsftpd.conf # ajouter ces lignes dans le fichier de configuration guest_enable=YES guest_username=ftpsecure user_sub_token=$USER local_root=/ftp/$USER EOF
Attention à ce que le guest_username corresponde à un utilisateur réel de votre système, créé spécialement pour cet usage. Ça sera l'utilisateur réel commun à tous vos utilisateurs virtuels.
Bug possible sur le chroot des utilisateurs virtuels
Il est possible, depuis les dernières version 2.x de vsftpd que vous obteniez le message suivant lors d'une tentative de connection :
500 OOPS: vsftpd: refusing to run with writable root inside chroot()
Cela est en lien avec l'option chroot_local_user=YES. Pour contourner ce problème, tout en laissant les répertoires de vos utilisateurs accessibles en écriture, il est nécessaire d'ajouter l'option :
allow_writeable_chroot=YES #allow_writable_chroot=YES # pour vsftpd-ext
Cependant, ce n'est pas tout. Pour certaines version 2.x de vsftpd (au moins la 2.3.5 fournie avec la Debian Wheezy à l'heure où ces lignes sont écrites) cette option est non supportée. Ainsi la seule solution trouvée, afin de conserver un comportement conforme à vos attentes, a été d'installer une version 3.x issue de Debian SID. Pour ce faire, nous sommes aller voir packages de Debian, puis nous avons téléchargé la version 3.x de notre architecture et la plus proche de notre distribution Debian (ici version 3.0.2 issue de la Debian SID) pour l'installer finalement "à la main" :
$ sudo dpkg -i vsftpd_3.0.2-1_amd64.deb
Limites
Dès maintenant, tous vos comptes courriels deviennent également des comptes FTP. Cependant, cela revêt 3 grandes limites :
- Les mots de passe passent en clair via FTP, alors qu'ils sont peut-être déjà sécurisés via vos solutions courriels... pensez donc à rajouter les fonctionnalités de cryptage à vsftpd ("FTPS", FTP over SSL)
- Tous les comptes courriels ont leur équivalent FTP... on peut donc imaginer rajouter un boolean dans la table mailbox pour définir si un compte est actif pour l'accès FTP ou non (ajout d'une colonne pour se faire)
- Lors de la création d'un nouveau compte courriel/FTP, le répertoire de stockage des emails est créé automatiquement mais pas le répertoire FTP... il faut donc soit l'automatiser de manière externe à vsftpd qui n'a pas cette fonctionnalité, soit le faire "à la main".
Automatiser la création des répertoires FTP des nouveaux comptes
La meilleure solution que nous avons vu pour le moment est de passer par une tâche "cron" (le plannificateur des tâches). Nous avons choisi une tâche exécutée en PHP car c'est déjà le langage utilisé par notre "backend" de gestion qui est sous Symfony. Voici donc la solution déployée sur nos serveurs :
pré-requis
Il faut déjà installer php5-cli sur le serveur :
$ sudo apt-get intall php5-cli
/etc/cron.hourly/create-ftp-dirs.php
Voici donc le script utilisé, placé dans un répertoire contenant les scripts à lancer toutes les heures :
$ sudo vi /etc/cron.d/create-ftp-dirs.php #!/usr/bin/php <?php define('HOST',); define('DB',); define('USER',); define('PASSWD',); define('FTPROOT',); $conn = pg_connect('host='.HOST.' dbname='.DB.' user='.USER.' password='.PASSWD); $q = pg_query("SELECT username FROM mailbox"); while ( $row = pg_fetch_row($q) ) if ( !file_exists(FTPROOT.'/'.$row[0]) ) { mkdir(FTPROOT.'/'.$row[0]); chown(FTPROOT.'/'.$row[0],'ftpsecure'); chgrp(FTPROOT.'/'.$row[0],'ftpsecure'); } pg_free_result($q); ?>
Sécurisons les informations
Les identifiants pour se connecter à la base de données sont accessibles depuis ce script, veillez donc à ce que seul l'utilisateur root puisse y accéder :
$ sudo chown root:root /etc/cron.hourly $ sudo chmod 700 /etc/cron.hourly
Conclusion
Créez un nouveau compte email, vérifiez qu'il peut bien recevoir des courriels. Vérifiez également, après avoir attendu une heure que le dossier soit créé, qu'il accède bien au service FTP... CQFD !