Fail2ban

Sécuriser son serveur Debian 9 avec Fail2ban

Généralités
Installation
Les dossiers et fichiers de configuration
Paramétrage par défaut
Configuration avancée
Configurer les filtres
Créer son propre filtre
Commandes de base
Configurer sa jail recidive

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.

Il suffit d'installer le paquet.

apt install fail2ban

Et pour contrôler la bonne installation.

systemctl status fail2ban

Si la réponse comporte du vert et les mots active (running) sur la ligne commençant par Active alors le service est installé et actif.

Le chemin standard de la configuration se trouve dans /etc/fail2ban/.
Une configuration typique ressemble à ceci :

/etc/fail2ban/
|---action.d
|     |---apf.conf
|     |---badips.conf
|     |---badips.py
|     |---....
|---fail2ban.conf
|---fail2ban.d
|---filter.d
|     |---3proxy.conf
|     |---apache-auth.conf
|     |---apache-badbots.conf
|     |---...
|---jail.conf
|---jail.d
|     |---defaults-debian.conf
|---paths-common.conf
|---paths-debian.conf
|---paths-opensuse.conf


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

action.d Les actions à effectuer lorsqu'un filtre est positif
fail2ban.conf Les paramètres généraux de fail2ban
fail2ban.d L'utilisateur peut créer un fichier de configuration pour personnaliser les paramètres généraux de fail2ban
filter.d Les fichiers de configuration des filtres
jail.conf Le fichier de configuration des prisons
jail.d L'utilisateur peut créer un ou plusieurs fichiers de configuration pour ajouter et activer les prisons


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.

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] » du fichier, indique les paramètres qui s’appliquerons a toutes les prisons (jails), si le paramètre n'est pas défini dans la prison (jail).

  • ignoreip : les adresses IP ignorées par les actions de fail2ban (par défaut 127.0.0.1/8)
  • bantime : le temps de bannissement en secondes (par défaut 600)
  • findtime : l'intervalle de temps pendant laquelle les essais de connexion vont incrémenter maxretry (par défaut 600)
  • maxretry : le nombre d'essais de connexion au bout duquel fail2ban banni une IP (par défaut 5)
  • backend : la méthode de surveillance des logs (par défaut auto)
  • usedns : spécifie si les prisons doivent faire confiance aux noms d'hôtes dans les logs (par défaut warn)
  • logencoding : spécifie l'encodage des fichiers logs gérés par les prisons (par défaut auto)
  • enabled : par défaut les prisons configurées ne sont pas activées (par défaut false)
  • filter : par défaut les prisons ont des noms correspondant à leur nom de filtre (par défaut %(__name__)s)
  • destemail : l'adresse email pour envoyer des notifications de banissement (par défaut root@localhost)
  • sender : l'adresse email de l'émeteur (par défaut root@localhost)
  • mta : le type de serveur de messagerie électronique utilisé (par défaut sendmail)
  • protocol : le protocole reseau sur lequel fail2ban bloque le(s) port(s) (par défaut tcp)
  • chain : la chaîne qui devraient être ajoutés dans les actions iptables (par défaut INPUT)
  • port : les ports pouvant être bannis (par défaut 0:65535)
  • banaction : méthode de ban, un port spécifique (par défaut iptables-multiport)
  • banaction_allports : méthode de ban, tous les ports (par défaut iptables-allports)
  • action : les actions exécutées par fail2ban lorsqu'une correspondance est trouvée entre un filtre et une entrée de log (par défaut %(action_)s)

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

  • port : le port à bloquer au moyen des règles du pare-feu
  • logpath : l'emplacement des fichiers de log à surveiller
  • backend : la méthode de surveillance des logs

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.

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 journal. Ainsi pour vérifier si des détections ont lieu, il faut regarder dans le fichier /var/log/fail2ban.log.

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

Dans cette exemple, avec les paramètres par défaut, la machine ayant l'adresse IP 192.168.1.8 fait 5 tentatives de connexion SSH échoué (maxretry = 5) en moin de 600 s, soit 10 minutes (findtime = 600) et est bloqué uniquement sur le port spécifique (22) avec le protocole TCP pendant 600 s, soit 10 minutes (bantime = 600).

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 (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 parametres 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 : 
  • 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 : envoye un mail avec le whois et les logs de l'ip bannie

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

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 ...

  • [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)

Dans cette exemple, avec ses parametres, la machine ayant l'adresse IP 192.168.1.8 fait 4 tentatives de connexion SSH échoué (maxretry = 4) en moin de 3600 s, soit 1 heure (findtime = 3600) et est bloqué sur tous les ports (banaction = %(banaction_allports)s) avec tous les protocoles (protocol = all) pendant 86400 s, soit 1 jour (bantime = 86400) et envoye un mail (action = %(action_mwl)s).

Le parametre action correspond à l'execution 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 parametre filter correspond à un fichier de configuration situé dans le dossier /etc/fail2ban/filter.d/, il faut le déclarer SANS le « .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.

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/ (ex: 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.

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 1.2.3.4

Je vais donc créer l'expression régulière me permettant de surveiller l'apparition de cette ligne précise 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

On voit ici que mon expression régulière présente dans filtre-perso.conf a trouvé 2 occurrences dans le fichier de log pointé.

La ligne Lines: 5 lines, 0 ignored, 2 matched, 3 missed nous dit que Fail2ban a analysé les 5 lignes (5 lines) du fichier de log, qu'il n'en a oublié aucune (0 ignored), qu'il a trouvé 2 occurrences (2 matched) et 3 lignes qui ne match pas avec mon expression (3 missed).

Voici mon fichier de log fictif de mon service fictif.

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 besion 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)

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émarrez fail2ban

Pour redémarrer fail2ban :

systemctl restart fail2ban

  • Tester les filtres

Si vous voulez simplement tester un filtre sur un fichier de log particulier, l'outil fail2ban-regex est fait pour vous.
Par exemple, pour tester le filtre apache-badbots sur le fichier journal d'Apache :

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

Cette commande 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

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

fail2ban-client set [nom du jail] unbanip [IP concerné]

  • Bannir manuellement une IP sur l'un de vos jails

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

fail2ban-client set [nom du jail] banip [IP à bannir]

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 pour TOUS les ports d’entrée pour une période plus longue (ici 30 jours (bantime)) si sur 7 jours (findtime), une IP est bannie plus de 3 fois (maxretry). 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.