Sécuriser Debian 9 avec Fail2ban

Généralités

Fail2ban se charge d’analyser les logs de divers services (SSH, Apache, FTP, Postifx, …) installés sur la machine, puis recherche les échecs d’authentification répétés et ajoute automatiquement une règle au pare-feu (iptables,  nftables, shorewall ou ufw) pour bannir l’adresse IP de la source.

Installation

Il suffit d’installer le paquet.

apt install fail2ban

Et pour vérifier l’état du service Fail2Ban.

systemctl status fail2ban

Si la ligne commençant par Active contient la mention active (running), cela signifie que le service Fail2Ban est bien installé et en cours d’exécution.

Les dossiers et fichiers de configuration

Le chemin standard de la configuration se trouve dans /etc/fail2ban/.

Une configuration typique ressemble à ceci :

/etc/fail2ban
├── action.d/                   → Actions à exécuter lors d’un ban/unban
│     ├── apf.conf              → Action pour le service apf
│     ├── badips.conf           → Action pour le service badips
│     ├── badips.py             → Script associé
│     └── …                     → Autres actions disponibles
│
├── fail2ban.conf               → Configuration globale
│
├── fail2ban.d/                 → Répertoire de surcharge de config globale
│     └── *.conf                → Tes propres ajustements généraux
│
├── filter.d/                   → Filtres qui détectent les intrusions
│     ├── 3proxy.conf           → Filtre pour 3proxy
│     ├── apache-auth.conf      → Détection des échecs d’auth Apache
│     ├── apache-badbots.conf   → Détection des robots malveillants
│     └── …                     → Autres Filtres disponibles
│
├── jail.conf                   → Configuration par défaut des jails
│
├── jail.d/                     → Répertoire pour tes propres jails
│     └── defaults-debian.conf  → Paramètres spécifiques à Debian
│     └── *.local               → Fichiers de tes jails personnalisées
│
├── paths-common.conf           → Définitions des chemins de logs
├── paths-debian.conf           → Spécifique à Debian (Apache, SSH, etc.)
└── paths-opensuse.conf         → Spécifique à openSUSE

Pour s’y retrouver et y voir plus clair, voici un récapitulatif.

Fichier / DossierRôle / DescriptionUsage recommandé
fail2ban.confFichier principal de configuration globale (paramètres généraux de Fail2Ban)Ne pas modifier directement, surcharger via fail2ban.d
fail2ban.d/Répertoire pour ajouter des fichiers de configuration personnalisés pour les paramètres globauxCréer des fichiers .conf pour personnaliser la config
jail.confFichier principal définissant les jails (associations service + filtre + action)Ne pas modifier directement, utiliser jail.d/
jail.d/Répertoire pour ajouter ou activer des jails personnaliséesCréer un fichier .conf par jail pour surcharger ou ajouter des prisons
filter.d/Contient les filtres (regex) utilisés pour détecter les échecs dans les logsAjouter ou modifier un filtre si besoin
action.d/Contient les actions exécutées lorsqu’un filtre détecte un comportement suspect (ban, mail…)Ajouter ou personnaliser des actions selon l’environnement

Chaque fichier .conf peut être remplacé par un fichier nommé .local.

Les modifications doivent avoir lieu dans le fichier .local et non dans le fichier .conf, donc il ne faut en aucun cas modifier jail.conf et fail2ban.conf car vous risquez de perdre leur contenu à la prochaine mise à jour de la distribution, ils doivent servir uniquement de référence et de documentation.

Paramétrage par défaut

Sur Debian, par défaut la prison (jail) sshd est active, ainsi elle protège des attaques bruteforce contre le service SSH.

Les paramètres par défaut sont visibles dans le fichier /etc/fail2ban/jail.conf.

La section [DEFAULT] définit les paramètres globaux qui s’appliquent à toutes les prisons (jails) si ceux-ci ne sont pas explicitement redéfinis dans la configuration d’une prison.

ParamètreDescriptionValeur par défaut
ignoreipListe d’adresses IP ou plages à ne jamais bannir127.0.0.1/8
bantimeDurée du bannissement d’une IP (en secondes)600 (10 min)
findtimeIntervalle de temps pendant lequel les échecs sont comptés600 (10 min)
maxretryNombre d’échecs autorisés avant bannissement5
backendMéthode de surveillance des journaux (auto, systemd, polling…)auto
usednsUtilisation de la résolution DNS inverse (yes, no, warn, raw)warn
logencodingEncodage utilisé pour lire les fichiers de logauto
enabledActivation d’une jailfalse
filterNom du filtre associé à la jail%(__name__)s
portPorts surveillés (un ou plusieurs)0:65535 (tous)
protocolProtocole réseau à surveillertcp
chainChaîne du pare-feu où ajouter les règlesINPUT
destemailAdresse email de destination des alertesroot@localhost
senderAdresse email de l’expéditeurroot@localhost
mtaAgent de transport de mail utilisésendmail
banactionAction appliquée pour bannir sur les ports spécifiésiptables-multiport
banaction_allportsAction appliquée pour bannir sur tous les portsiptables-allports
actionActions exécutées lorsqu’un filtre détecte une correspondance%(action_)s

La section # JAILS du fichier, indique les paramètres des prisons (jails).

ParamètreDescriptionExemple
[xxx]Indique le nom de la jail[sshd]
enabledActive la jailtrue
portPort à surveiller22
filterUtilise le filtre /etc/fail2ban/filter.d/xxx.conf (sans le .conf)sshd
logpathIndique le chemin du ou des fichiers journaux (logs) que Fail2Ban doit surveiller pour détecter les échecs ou comportements suspects/var/log/auth.log

Les valeurs représentées ainsi %(… …)s sont des variables qui sont définies dans les fichiers de configuration /etc/fail2ban/paths_common.conf et /etc/fail2ban/paths_debian.conf.
La variable %(sshd_logs)s est égale à /var/log/auth.log.
Le parametre port = ssh est égale à port = 22 (on peut mettre directement le numéro du port, 22 pour ssh). Si vous avez changé le port par défaut, changez ici en conséquence.

L’activation de la prison (jail) sshd se trouve dans le fichier /etc/fail2ban/jail.d/defaults-debian.conf grâce au paramètre enabled à true.

Schéma simplifié :

sshd (jail)
|
|---> enabled → true
|---> logpath/var/log/auth.log
|---> filter → filter.d/sshd.conf
|---> action → action.d/iptables-multiport.conf

Fail2ban va alors scruter le contenu de /var/log/auth.log afin de vérifier les tentatives de connexion SSH.
Ensuite il reporte tout dans son fichier journal. Ainsi pour vérifier si des détections ont lieu, il faut regarder dans le fichier /var/log/fail2ban.log.

Notes :

Found : l’occurrence est trouvée
Ban : le seuil est dépassé (maxfailure) et l’action est réalisée

Explication de l’exemple [sshd] avec les valeurs par défaut :

Si une machine tente de se connecter à SSH et échoue 5 fois (maxretry = 5).
Si ces tentatives se produisent dans une fenêtre de 600 secondes (findtime = 600, soit 10 minutes).
Alors Fail2Ban déclenche la jail [sshd] et bloque uniquement le port 22 (port = 22) en TCP (protocol = tcp).

En résumé :

5 échecs en moins de 10 minutes → IP bannie sur le port SSH pendant 10 minutes.

Configuration avancée

Vous pouvez supprimer le fichier defaults-debian.conf.

rm /etc/fail2ban/jail.d/defaults-debian.conf

Vous pouvez créer un fichier jail.local (nomdevotrechoix.local) dans le dossier /etc/fail2ban/jail.d/.

nano /etc/fail2ban/jail.d/jail.local

Pour configurer les paramètres globaux (qui concerne donc toutes les prisons, si le paramètre n’est pas défini dans la prison), ressaisissez les paramètres comme dans l’exemple.

[INCLUDES]

before = paths-debian.conf

[DEFAULT]

ignoreip = 127.0.0.1/8 192.168.1.1
bantime  = 86400
findtime  = 3600
maxretry = 5
backend = auto
usedns = warn
logencoding = auto
enabled = false
filter = %(__name__)s
protocol = all 
chain = INPUT
port = 0:65535
fail2ban_agent = Fail2Ban/%(fail2ban_version)s
destemail = root@localhost
sender = root@localhost
mta = sendmail
banaction = iptables-multiport
banaction_allports = iptables-allports
action = %(action_mwl)s

Les paramètres globaux sont définis dans la section [DEFAULT].

  • [INCLUDES] 
  • before = paths-debian.conf : contient les chemins vers différents fichiers logs
  • [DEFAULT] 
  • ignoreip = 127.0.0.1/8 192.168.1.1 : ne pas bannir les IP 127.0.0.1 et 192.168.1.1
  • bantime  = 86400 : temps de bannissement (1 jour)
  • findtime  = 3600 : intervalle de temps pendant laquelle les essais vont incrémenter maxretry (1 heure)
  • maxretry = 5 : nombre de tentatives de connexion échoué
  • backend = auto : méthode de surveillance des logs (auto)
  • usedns = warn : si un nom d’hôte est rencontré, une recherche DNS sera effectuée
  • logencoding = auto : encodage des fichiers logs gérés par les prisons
  • enabled = false : désactive par défaut les prisons, pour pouvoir les activer une par une
  • filter = %(__name__)s : les prisons ont des noms correspondant à leur nom de filtre
  • protocol = all : bloque le(s) port(s) sur tous les protocoles (TCP/UDP/ICMP)
  • chain = INPUT : chaîne qui devraient être ajoutés dans les actions iptables
  • port = 0:65535 : ports pouvant être bannis
  • fail2ban_agent = Fail2Ban/%(fail2ban_version)s : variable utilisé par Fail2Ban
  • destemail = root@localhost : adresse email pour envoyer des notifications de banissement
  • sender = root@localhost : adresse email de l’émeteur
  • mta = sendmail : type de serveur de messagerie électronique utilisé
  • banaction = iptables-multiport : bannissement de l’IP sur un port spécifique
  • banaction_allports = iptables-allports : bannissement de l’IP sur tous les ports
  • action = %(action_mwl)s : bannie l’IP + envoie un mail avec whois + log l’événement

Pour créer une prison (jail) du service SSH, ressaisissez les paramètres comme dans l’exemple.

[sshd]
enabled = true
port = 2222
logpath = /var/log/auth.log
filter = sshd
banaction = %(banaction_allports)s
action = %(action_mwl)s
maxretry = 4
findtime = 3600
bantime = 86400
  • [sshd] : nom de la prison (jail)
  • enabled = true : active la prison (jail)
  • port = 2222 : le port à bloquer
  • logpath = /var/log/auth.log : emplacement du fichier de log à surveiller
  • backend = %(sshd_backend)s : méthode de surveillance des logs (auto)
  • filter = sshd : utilise le filtre /etc/fail2ban/filter.d/sshd.conf (sshd, sans le .conf)
  • banaction = %(banaction_allports)s : bannissement de l’IP sur tous les ports (iptables-allports)
  • action = %(action_mwl)s : envoye un mail avec le whois et les logs de l’ip bannie
  • maxretry = 4 : nombre de tentatives de connexion échoué
  • findtime = 3600 : intervalle de temps pendant laquelle les essais de connexion vont incrémenter maxretry (1 heure)
  • bantime = 86400 : temps de bannissement (1 jour)

Cela permet d’ajuster la configuration et le filtre associé à cette prison, en spécifiant par exemple un nombre de tentatives différent de la valeur par défaut, un port différent, un temps de bannissement différent de la valeur par défaut, etc…

Explication de l’exemple [sshd] avec ses paramètres :

Si une machine tente de se connecter à SSH et échoue 4 fois (maxretry = 4).
Si ces tentatives se produisent dans une fenêtre de 3600 secondes (findtime = 3600, soit 1 heure).
Alors Fail2Ban déclenche la jail [sshd] et bloque tous les ports (banaction = %(banaction_allports)s) sur tous les protocoles (protocol = all) pendant 86400 secondes (bantime = 86400, soit 1 jour) et envoie un mail & écrit l’événement dans les logs Fail2Ban (action = %(action_mwl)s).

En résumé :

4 échecs en moins de 1 heure → IP bannie sur tous les ports pendant 1 jour + un mail est envoyé + log l’événement.

Le paramètre action correspond à l’exécution d’un ou plusieurs fichier(s) du dossier /etc/fail2ban/action.d/, typiquement, Fail2ban exécutera une action lorsqu’une ligne de log détectée par nos filtres apparaitra un certain nombre de fois. Les actions peuvent alors être des événements de protections (bannir l’IP en question, etc…) ou alors des événements d’alerte (envoyer un mail, etc …).

Le paramètre filter correspond à un fichier de configuration situé dans le dossier /etc/fail2ban/filter.d/, il faut le déclarer sans l’extension (.conf). Ce fichier de configuration va contenir des expressions régulières qui permettent de déterminer si une ligne dans les logs est considérée comme un échec d’authentification.

Configurer les filtres

Fail2ban fournit pas mal de prisons pour la plupart des services réseaux (HTTP, SMTP, SSH, …). Chaque prison est associé à un fichier de filtrage du même nom dans le dossier /etc/fail2ban/filter.d/ (pour la prison [sshd], le filtre sshd.conf).

Ces fichiers contiennent une ou plusieurs expressions régulières qui servent de motif de recherche pour les lignes correspondantes dans les logs. Les expressions sont définies par la directive failregex.

Voici un exemple de l’une des expressions du filtre sshd.conf. Sans détailler toute l’expression, on recherche ici les échecs d’authentification sur le service SSH. On va donc ici appliquer ce filtre sur un fichier de log du service SSH.

failregex = ^%(__prefix_line)s(?:error: PAM: )?[aA]uthentication (?:failure|error|failed) for .* from <HOST>( via \S+)?\s*$

Cette expression entrera en correspondance avec toutes les lignes du fichier de log du service SSH (/var/log/auth.log) contenant des erreurs ou des échecs d’authentification.

Créer son propre filtre

Pour rappel, les filtres sont stockés dans /etc/fail2ban/filter.d/, nous allons donc nous y rendre pour créer un nouveau filtre. Chaque filtre est représenté et assigné par son nom dans une configuration de prison (jail) dans Fail2ban. On va donc être attentif au nom que l’on donne à notre filtre.

Un filtre sous Fail2ban va contenir une structure prédéfinie qui ressemble à ceci :

[INCLUDES]
before = 
after =
[Definition]
_daemon =
failregex =
ignoreregex =
[Init]
maxlines =
journalmatch =

Dans la partie [Definition], failregex et ignoreregex sont important. Pour s’y retrouver et y voir plus clair, voici un récapitulatif.

  • [INCLUDES]  (facultatif)
  • before : importation d’un autre filtre avant la déclaration de se filtre, ce champ est optionnel
  • after : importation d’un autre filtre après la déclaration de se filtre, ce champ est optionnel
  • [Definition]
  • _daemon : utilisée pour construire l’expression régulière __prefix_line, ce champ est optionnel (utilisé avec common.conf)
  • failregex : expression régulière du filtre, on définit ici ce qu’il faut surveiller (toutes les lignes de log analysées qui correspondront aux lignes mis ici seront susceptibles de déclencher l’action associée dans la jail)
  • ignoreregex : exceptions que l’on souhaite déclarer, ce champ est optionnel, mais il peut avoir un réel intérêt dans certains cas
  • [Init]  (facultatif)
  • maxlines : nombre de lignes de log à mettre en mémoire tampon pour les recherches regex multi-lignes, ce champ est optionnel
  • journalmatch : spécifie la correspondance de log systemd utilisée pour filtrer les entrées de log, ce champ est optionnel

Pour créer un filtre personnalisé, je rappelle qu’il faut avoir clairement identifié :

  1. La ou les ligne(s) de logs que l’on souhaite surveiller
  2. Le ou les fichier(s) de logs dans lesquel(s) ces lignes seront ajoutées

imaginons un service fictif qui écrit ses logs dans /var/log/log-perso.log.

Pour l’exemple, je vais créer un filtre nommé filtre-perso.conf, qui va détecter une expression dans le fichier de log fictif.

nano /etc/fail2ban/filter.d/filtre-perso.conf

Je souhaite qu’à chaque fois que mon service fictif génère une ligne du genre, ci dessous, dans ses logs, l’IP source soit bannie.

Apr-07-13 07:08:36 Invalid command user from 192.168.1.4

Je vais donc créer l’expression régulière me permettant de surveiller l’apparition de ce genre de ligne dans mes logs.

[Definition]
failregex = .* Invalid command .* from <HOST>
ignoreregex =

Notez tout d’abord que mon expression régulière n’est pas complexe du tout. 
La présence de la chaine <HOST> est obligatoire dans un filtre Fail2ban lorsque l’on souhaite récupérer une IP, par exemple pour la renseigner à iptables en vue d’un bannissement temporaire. La chaine <HOST> est donc positionnée à l’endroit où sera l’IP dans la ligne de logs filtrée.

Une fois votre failregex créé, il est possible de le tester rapidement via la commande fail2ban-regex, pour tester le filtre filtre-perso.conf sur le fichier journal log-perso.log.

fail2ban-regex /var/log/log-perso.log /etc/fail2ban/filter.d/filtre-perso.conf

Ce que fait la commande :

  • Scanne le fichier de log ligne par ligne.
  • Compare chaque ligne avec le failregex du filtre.
  • Affiche un résumé :
    • lines = nombre total de lignes analysées
    • ignored = lignes ignorées par ignoreregex
    • matched = lignes qui correspondent à failregex
    • missed = lignes qui ne correspondent pas
  • Utile pour valider que votre filtre détecte bien les tentatives échouées avant de l’ajouter à une jail.

Voici mon fichier de log fictif de mon service fictif :

Apr-07-13 07:08:28 Accepted command paul from 192.168.0.15
Apr-07-13 07:08:32 Invalid command thomas from 192.168.0.15
Apr-07-13 07:08:36 Accepted command pierre from 192.168.0.15
Apr-07-13 07:08:41 Accepted command mic from 192.168.0.15
Apr-07-13 07:08:45 Invalid command pierre from 192.168.0.15

La sortie Lines: 5 lines, 0 ignored, 2 matched, 3 missed indique que Fail2Ban a analysé un total de 5 lignes du fichier de log. Aucune ligne n’a été ignorée (0 ignored), 2 lignes correspondent à l’expression régulière du filtre (2 matched), et 3 lignes n’ont pas correspondu (3 missed).

On voit bien les 2 lignes Invalid command.

Modifions maintenant notre fichier de configuration pour activer notre nouveau filtre.

nano /etc/fail2ban/jail.d/jail.local

Ne pas oublier de déclarer le filtre SANS le .conf (filter = filtre-perso).

[filtre-perso]
enabled = true
port = 1234
logpath = /var/log/log-perso.log
filter = filtre-perso
banaction = %(banaction_allports)s
action = %(action_mwl)s
maxretry = 8
findtime = 3600
bantime = 86400

En vrais vous n’avez pas besoin de déclarer le filtre si le nom de la prison (jail) et le même que le nom du filtre (nom de la prison [filtre-perso] et nom du filtre filtre-perso).

Commandes de base

Voir le status des jails

Pour savoir si votre jail est actif, vous devriez le voir affiché, après avoir taper cette commande :

fail2ban-client status

Cette commande affiche tous les jails que fail2ban traite.

Pour savoir si une de vos jails de votre fail2ban a bannis une ou plusieurs IP, taper cette commande :

fail2ban-client status nom_du_jail

Cette commande va afficher le nombre de tentative lu dans vos logs, le nombre de bannis et, le plus intéressant, les IPs qui sont bannis temporairement.

Redémarrer fail2ban

Pour redémarrer fail2ban :

systemctl restart fail2ban

Tester un filtre

Pour tester un filtre sur un fichier de log particulier :

fail2ban-regex /var/log/apache2/access.log /etc/fail2ban/filter.d/apache-badbots.conf

Cette commande teste le filtre apache-badbots sur le fichier journal d’Apache (prend en premier paramètre une chaine ou un fichier de log, et en second le filtre que l’on souhaite tester)

Dé-bannir une IP de l’un de vos jails

Si une de vos adresse IP se retrouve blacklisté suite à une mauvaise manipulation répété ou un test de sécurité. Vous pouvez la retirer de la liste des IP blacklisté de fail2ban avec cette commande :

fail2ban-client set nom_du_jail unbanip ip_à_débannir

Bannir manuellement une IP sur l’un de vos jails

Vous voulez tester plus rapidement l’interdiction d’un accès d’une adresse IP, ou bloquer une personne malveillante. Renseignez son IP dans cette commande :

fail2ban-client set nom_du_jail banip ip_à_bannir

Configurer une jail recidive

La prison (jail) très intéressante à activer, la jail recidive est une prison (Jail) pour les récidivistes.

Lors de l’activation de cette jail, Fail2ban scanne son propre fichier de log (/var/log/fail2ban.log) et y recherche les IPs récurrentes qui ont été bannies par les règles définies dans les autres jails.

Vous pouvez créer un fichier fail2ban.local (nomdevotrechoix.local) dans le dossier /etc/fail2ban/fail2ban.d/.

nano /etc/fail2ban/fail2ban.d/fail2ban.local

Fail2ban utilise une base sqlite3. Nous allons définir le paramètre dbpurgeage (durée de rétention des informations dans la base de données de Fail2ban) à 648000 (soit 7.5 jours) pour la configuration de la prison (jail) recidive, ressaisissez les paramètres comme dans l’exemple.

[Definition]
loglevel = INFO
logtarget = /var/log/fail2ban.log
dbpurgeage = 648000

Maintenent, il faut paramétrer et activer la prison (jail) recidive.

Dans le fichier jail.local (nomdevotrechoix.local) dans le dossier /etc/fail2ban/jail.d/.

nano /etc/fail2ban/jail.d/jail.local

Ressaisissez les paramètres comme dans l’exemple.

[recidive]
enabled = true
bantime = 2592000
findtime = 604800
maxretry = 3
action = %(action_mwl)s
banaction = %(banaction_allports)s
logpath = /var/log/fail2ban.log

Les IPs sont alors bannies et ceci sur tous les ports pour une période plus longue (bantime = 2592000, ici 30 jours) si sur 7 jours (findtime = 604800), une IP est bannie plus de 3 fois (maxretry = 3). C’est pourquoi le paramètre de rétention dbpurgeage a été fixé à 7.5 jours, sinon la jail recidive ne fonctionnerait pas très bien.