Après [l'aspect de la sauvegarde](/2015/deploiement-et-sauvegarde) je me suis attaqué à la sécurisation du serveur. C'est un vaste sujet et on n'est jamais certain d'être parfaitement protégé : on se documente et on essaie de parer à l'essentiel. Je recommande cet article publié sur [Mes potes Geek](https://mespotesgeek.fr/debian-8-jessie-securisation/) qui dresse un panorama des outils couramment utilisés et leur mise en oeuvre. Un des piliers de la sécurisation d'un serveur GNU/Linux est l'outil [Fail2Ban](http://www.fail2ban.org) qui va surveiller les logs du serveur pour trouver des traces d'attaque et contre-attaquer en bannissant le malotru. Techniquement, l'outil parse les logs systèmes ou applicatifs à grand coup d'expressions régulières et bloque les attaques avec le pare-feu [iptable](https://fr.wikipedia.org/wiki/Iptables). Les règles de bannissement sont configurables : nombre de tentatives de connexions infructueuses, durée du bannissement. On peut facilement étendre Fail2Ban pour ajouter la surveillance d'une application *maison* pour peu qu'elle écrive dans un log les tentatives ratées de connexion et on peut aussi personnaliser les notifications. En standard, Fail2Ban envoie un e-mail à l'administrateur à chaque *ban*. En pratique, un petit serveur comme le mien bannit une quinzaine d'adresses IP par jour, essentiellement des tentatives ratées par SSH et c'est vite fastidieux de recevoir autant d'e-mails. Fail2Ban propose un envoi groupé, c'est à dire qu'il regroupe un nombre d'attaques paramétrable dans un seul e-mail. C'est mieux mais je suis habitué à configurer mes outils pour recevoir des rapports à fréquence fixe, journaliers ou hebdomadaires. N'ayant rien trouvé en standard, j'ai décidé d'étendre Fail2Bane avec mon propre script de configuration pour arriver au résultat voulu. Sur Debian, la configuration est installée sous **/etc/fail2ban**. Dans ce répertoire, on va trouver */etc/failban/filter.d/* qui contient les filtres de détection et */etc/fail2ban/action.d/* qui contient les actions à appliquer. Le fichier de configuration principal est *jail.conf* mais on ne le modifie jamais (pour éviter de perdre les modifications lors des mises à jour de fail2ban). On préfère redéfinir les parties de la configurations modifiées dans un fichier *jail.local*. Pour rajouter une action personnalisée, on va donc rajouter un fichier d'action dans */etc/fail2ban/action.d* et décrire quand et comment l'appliquer dans *jail.local*. J'ai donc dupliqué le fichier d'action *sendmail-buffered* et je l'ai adapté pour créer *sendmail-cron*. Pourquoi CRON ? Et bien l'idée est la suivante : chaque bannissement est écrit dans un fichier temporaire par *sendmail-buffered* et quand le nombre de ligne configuré est atteint, ce fichier est envoyé par e-mail. Je conserve ce fonctionnement mais je change le déclencheur de l'envoi : ce n'est plus le nombre de lignes du fichier mais la présence d'un fichier *mail.flag* dans un certain répertoire qui conditionne l'envoi. Ce fichier *mail.flag* est créé par une tâche CRON. Ainsi, on délègue à CRON la configuration de la fréquence d'envoi du rapport. Quant au fichier d'action, il est simple : on conserve les IP bannies dans un fichier temporaire avec le détail de l'opération (date de l'attaque, filtre concerné, IP source) et on regarde si on a le feu vert pour créer le rapport en testant la présence du fichier *mail.flag*. Si c'est le cas, on envoie le rapport puis on supprime le fichier temporaire et le fichier *mail.flag*. Voici le fichier */etc/fail2ban/action.d/sendmail-cron.conf* complet : ``` # Fail2Ban configuration file # # Author: Yannic Arnoux # Based on sendmail-buffered written by Cyril Jaquier # # [INCLUDES] before = sendmail-common.conf [Definition] # Option: actionstart # Notes.: command executed once at the start of Fail2Ban. # Values: CMD # actionstart = printf %%b "Subject: [Fail2Ban] : started on `uname -n` From: <> To: \n Hi,\n The jail has been started successfully.\n Regards,\n Fail2Ban" | /usr/sbin/sendmail -f # Option: actionstop # Notes.: command executed once at the end of Fail2Ban # Values: CMD # actionstop = if [ -f ]; then printf %%b "Subject: [Fail2Ban] Report from `uname -n` From: <> To: \n Hi,\n These hosts have been banned by Fail2Ban.\n `cat ` \n,Regards,\n Fail2Ban" | /usr/sbin/sendmail -f rm fi printf %%b "Subject: [Fail2Ban] : stopped on `uname -n` From: Fail2Ban <> To: \n Hi,\n The jail has been stopped.\n Regards,\n Fail2Ban" | /usr/sbin/sendmail -f # Option: actioncheck # Notes.: command executed once before each actionban command # Values: CMD # actioncheck = # Option: actionban # Notes.: command executed when banning an IP. Take care that the # command is executed with Fail2Ban user rights. # Tags: See jail.conf(5) man page # Values: CMD # actionban = printf %%b "`date`: ban after failure(s)\n" >> if [ -f ]; then printf %%b "Subject: [Fail2Ban] Report from `uname -n` From: <> To: \n Hi,\n These hosts have been banned by Fail2Ban.\n `cat ` \n,Regards,\n Fail2Ban" | /usr/sbin/sendmail -f rm rm fi # Option: actionunban # Notes.: command executed when unbanning an IP. Take care that the # command is executed with Fail2Ban user rights. # Tags: See jail.conf(5) man page # Values: CMD # actionunban = [Init] # Default name of the chain # name = default # Default temporary file # tmpfile = /var/run/fail2ban/tmp-mail.txt # Default flag file # mailflag = /var/run/fail2ban/mail.flag ``` Dans mon cas, la tâche CRON est journalière : ```shell # fail2ban report @daily touch /var/run/fail2ban/mail.flag ``` Ceux qui suivent ont remarqué que mon rapport ne sera envoyé que sur un bannissement donc potentiellement longtemps après que la tâche CRON ait créé le fichier *mail.flag*. Je fais confiance à mes intrus et à leurs tentatives soutenues pour que ce rapport soit bien envoyé à une fréquence journalière ;-) Il reste à configurer fail2ban pour utiliser cette nouvelle action. J'ai redéfini dans ma configuration *jail.local* les actions à appliquer sur détection d'attaque : d'abord on bloque, ensuite on informe : action_mwlc = %(banaction)s[name=%(__name__)s, port="%(port)s", protocol="%(protocol)s", chain="%(chain)s"]%(mta)s-cron[name=%(__name__)s, dest="%(destemail)s", logpath=%(logpath)s, chain="%(chain)s", sendername="%(sendername)s"] action = %(action_mwlc)s Il reste à redémarrer Fail2Ban et à attendre l'envoi du prochain rapport. Au fait, je reviens à peine de vacances où j'ai rencontré un postulant au rôle de mascotte de ce blog :D ![poulet](/images/2015/poulet.jpg)