# Fail2Ban

Fail2Ban est un outil de protection qui analyse les logs des services exposés (SSH, applications web, reverse proxy, etc.) et bannit automatiquement les adresses IP qui présentent un comportement suspect : tentatives de connexion échouées répétées, scan d'endpoints, brute-force, etc.

# Présentation

<span style="color:rgb(0,0,0);">[![fail2ban_2.png](https://docs.rakouns.bzh/uploads/images/gallery/2026-06/scaled-1680-/fail2ban-2.png)](https://docs.rakouns.bzh/uploads/images/gallery/2026-06/fail2ban-2.png)</span>

## <span style="color:rgb(0,0,0);">Qu'est ce que Fail2Ban ?</span>

<span style="color:rgb(0,0,0);">Fail2Ban est un outil de protection qui analyse les logs des services exposés (SSH, applications web, reverse proxy, etc.) et bannit automatiquement les adresses IP qui présentent un comportement suspect : tentatives de connexion échouées répétées, scan d'endpoints, brute-force, etc.</span>

<span style="color:rgb(0,0,0);">Concrètement, Fail2Ban fonctionne en trois briques :</span>

<table class="MsoNormalTable" id="bkmrk-brique-r%C3%B4le-filter-u" style="width:985px;border-collapse:collapse;height:157px;border:medium none;"><thead><tr><td style="width:118.953px;border:1pt solid rgb(204,204,204);background:rgb(31,45,61);padding:4pt 7pt;"><span style="color:rgb(255,255,255);">**<span style="font-size:10.5pt;">Brique</span>**</span>

</td><td style="width:720.047px;border-width:1pt 1pt 1pt medium;border-style:solid solid solid none;border-color:rgb(204,204,204) rgb(204,204,204) rgb(204,204,204);background:rgb(31,45,61);padding:4pt 7pt;"><span style="color:rgb(255,255,255);">**<span style="font-size:10.5pt;">Rôle</span>**</span>

</td></tr></thead><tbody><tr><td style="width:118.953px;border-width:medium 1pt 1pt;border-style:none solid solid;border-color:rgb(204,204,204) rgb(204,204,204);padding:4pt 7pt;"><span style="font-size:10.5pt;color:rgb(0,0,0);">Filter</span>

</td><td style="width:720.047px;border-width:medium 1pt 1pt medium;border-style:none solid solid none;border-color:rgb(204,204,204) rgb(204,204,204);padding:4pt 7pt;"><span style="font-size:10.5pt;color:rgb(0,0,0);">Une expression régulière qui repère une ligne de log correspondant à une tentative échouée</span>

</td></tr><tr><td style="width:118.953px;border-width:medium 1pt 1pt;border-style:none solid solid;border-color:rgb(204,204,204) rgb(204,204,204);padding:4pt 7pt;"><span style="font-size:10.5pt;color:rgb(0,0,0);">Jail</span>

</td><td style="width:720.047px;border-width:medium 1pt 1pt medium;border-style:none solid solid none;border-color:rgb(204,204,204) rgb(204,204,204);padding:4pt 7pt;"><span style="font-size:10.5pt;color:rgb(0,0,0);">La configuration qui associe un filter à un service, une durée de ban, un nombre d'essais max, et une action</span>

</td></tr><tr><td style="width:118.953px;border-width:medium 1pt 1pt;border-style:none solid solid;border-color:rgb(204,204,204) rgb(204,204,204);padding:4pt 7pt;"><span style="font-size:10.5pt;color:rgb(0,0,0);">Action</span>

</td><td style="width:720.047px;border-width:medium 1pt 1pt medium;border-style:none solid solid none;border-color:rgb(204,204,204) rgb(204,204,204);padding:4pt 7pt;"><span style="font-size:10.5pt;color:rgb(0,0,0);">Ce qui se passe quand le seuil est dépassé (le plus souvent : bannir l'IP via le pare-feu)</span>

</td></tr></tbody></table>

<span style="color:rgb(0,0,0);">Le flux est donc : **log → filter (regex) → jail (seuils) → action (ban pare-feu).**</span>

<span style="color:rgb(0,0,0);">Sur une infra exposée sur Internet (Rakouns), chaque service accessible publiquement (Vaultwarden, Emby, Matrix, NPM, etc.) est une cible potentielle de scan automatisé et de brute-force. Sans fail2ban :</span>

<span style="color:rgb(0,0,0);"><span>•<span style="font:7pt 'Times New Roman';"> </span></span>Les logs d'authentification se remplissent de tentatives parasites.</span>

<span style="color:rgb(0,0,0);"><span>•<span style="font:7pt 'Times New Roman';"> </span></span>Les services restent exposés à du brute-force lent et discret (peu de requêtes par minute, sous le radar d'un rate-limiting applicatif).</span>

<span style="color:rgb(0,0,0);"><span>•<span style="font:7pt 'Times New Roman';"> </span></span>Aucune réponse automatique n'existe en cas d'attaque ciblée.</span>

## <span style="color:rgb(0,0,0);">Spécificités de l'infra Rakouns</span>

<span style="color:rgb(0,0,0);">Sur l'infra Rakouns, la quasi-totalité des services tournent en conteneurs Docker derrière NPM (Nginx Proxy Manager) comme reverse proxy. Cela introduit deux contraintes particulières :</span>

<span style="color:rgb(0,0,0);"><span>1.<span style="font:7pt 'Times New Roman';"> </span></span>**Le ban classique d'iptables ne suffit pas avec Docker.** Docker manipule ses propres règles iptables et les insère avant les règles fail2ban standards (chaîne <span style="font-size:10.5pt;line-height:115%;font-family:Consolas;background-image:initial;background-position:initial;background-size:initial;background-repeat:initial;background-attachment:initial;">INPUT</span>). Il faut donc cibler explicitement la chaîne <span style="font-size:10.5pt;line-height:115%;font-family:Consolas;background-image:initial;background-position:initial;background-size:initial;background-repeat:initial;background-attachment:initial;">DOCKER-USER</span>, via une action personnalisée (<span style="font-size:10.5pt;line-height:115%;font-family:Consolas;background-image:initial;background-position:initial;background-size:initial;background-repeat:initial;background-attachment:initial;">iptables-docker</span>), pour qu'un ban soit réellement effectif sur le trafic redirigé vers les conteneurs.</span>

<span style="color:rgb(0,0,0);"><span>2.<span style="font:7pt 'Times New Roman';"> </span></span>Le format des logs Docker (<span style="font-size:10.5pt;line-height:115%;font-family:Consolas;background-image:initial;background-position:initial;background-size:initial;background-repeat:initial;background-attachment:initial;">json-file</span>**) nécessite le backend <span style="font-size:10.5pt;line-height:115%;font-family:Consolas;background-image:initial;background-position:initial;background-size:initial;background-repeat:initial;background-attachment:initial;">polling</span>** dans la configuration jail, car le backend par défaut (<span style="font-size:10.5pt;line-height:115%;font-family:Consolas;background-image:initial;background-position:initial;background-size:initial;background-repeat:initial;background-attachment:initial;">auto</span>/<span style="font-size:10.5pt;line-height:115%;font-family:Consolas;background-image:initial;background-position:initial;background-size:initial;background-repeat:initial;background-attachment:initial;">systemd</span>) ne lit pas correctement ce format.</span>

<span style="color:rgb(0,0,0);">Sur le host AlmaLinux (Comms / OVH VPS), une bascule vers <span style="font-size:10.5pt;line-height:120%;font-family:Consolas;background-image:initial;background-position:initial;background-size:initial;background-repeat:initial;background-attachment:initial;">iptables-legacy</span> a également été nécessaire pour la compatibilité avec les actions fail2ban, et un contexte SELinux dédié (<span style="font-size:10.5pt;line-height:120%;font-family:Consolas;background-image:initial;background-position:initial;background-size:initial;background-repeat:initial;background-attachment:initial;">var\_log\_t</span>) a dû être appliqué aux chemins de logs Docker pour autoriser leur lecture.</span>

## <span style="color:rgb(0,0,0);">Convention de nommage Rakouns</span>

<span style="color:rgb(0,0,0);">Toutes les jails créées sur l'infra Rakouns sont préfixées <span style="font-size:10.5pt;line-height:120%;font-family:Consolas;background-image:initial;background-position:initial;background-size:initial;background-repeat:initial;background-attachment:initial;">rakouns-</span> (ex : <span style="font-size:10.5pt;line-height:120%;font-family:Consolas;background-image:initial;background-position:initial;background-size:initial;background-repeat:initial;background-attachment:initial;">rakouns-vaultwarden</span>, <span style="font-size:10.5pt;line-height:120%;font-family:Consolas;background-image:initial;background-position:initial;background-size:initial;background-repeat:initial;background-attachment:initial;">rakouns-emby</span>, <span style="font-size:10.5pt;line-height:120%;font-family:Consolas;background-image:initial;background-position:initial;background-size:initial;background-repeat:initial;background-attachment:initial;">rakouns-npm</span>) afin de les distinguer clairement des jails par défaut fournies avec le paquet (<span style="font-size:10.5pt;line-height:120%;font-family:Consolas;background-image:initial;background-position:initial;background-size:initial;background-repeat:initial;background-attachment:initial;">sshd</span>, <span style="font-size:10.5pt;line-height:120%;font-family:Consolas;background-image:initial;background-position:initial;background-size:initial;background-repeat:initial;background-attachment:initial;">recidive</span>, etc.).</span>

# Installation

[![fail2ban_2.png](https://docs.rakouns.bzh/uploads/images/gallery/2026-06/scaled-1680-/fail2ban-2.png)](https://docs.rakouns.bzh/uploads/images/gallery/2026-06/fail2ban-2.png)

## Installation générique (Debian/Ubuntu)

```bash
sudo apt update
sudo apt install fail2ban -y
```

<span style="color:#1a1a1a;">Vérifier que le service est actif :</span>

```
sudo systemctl status fail2ban
sudo systemctl enable --now fail2ban
```

## Installation sur AlmaLinux/RHEL

```
sudo dnf install epel-release -y
sudo dnf install fail2ban fail2ban-systemd -y
sudo systemctl enable --now fail2ban
```

### Bascule iptables-legacy (requis sur AlmaLinux)

<span style="color:#1a1a1a;">Sur AlmaLinux, le mode </span><span style="font-size:10.5pt;line-height:120%;font-family:Consolas;color:#ae3a78;background:#F7F0F4;">nftables</span><span style="color:#1a1a1a;"> par défaut pose des soucis de compatibilité avec certaines actions fail2ban orientées iptables. Bascule en mode legacy :</span>

```
sudo dnf install iptables-services -y
sudo alternatives --set iptables /usr/sbin/iptables-legacy
sudo alternatives --set ip6tables /usr/sbin/ip6tables-legacy
sudo systemctl enable --now iptables
sudo systemctl restart fail2ban
```

<span style="color:#1a1a1a;">Vérifier la bascule :</span>

```
sudo alternatives --display iptables
```

## Arborescence de configuration

<span style="color:#1a1a1a;">Fail2ban utilise deux types de fichiers, à ne **jamais** modifier dans </span><span style="font-size:10.5pt;line-height:120%;font-family:Consolas;color:#ae3a78;background:#F7F0F4;">/etc/fail2ban/jail.conf</span><span style="color:#1a1a1a;"> ou </span><span style="font-size:10.5pt;line-height:120%;font-family:Consolas;color:#ae3a78;background:#F7F0F4;">/etc/fail2ban/filter.d/\*.conf</span><span style="color:#1a1a1a;"> (écrasés lors des mises à jour). Toujours passer par les fichiers </span><span style="font-size:10.5pt;line-height:120%;font-family:Consolas;color:#ae3a78;background:#F7F0F4;">.local</span><span style="color:#1a1a1a;"> :</span>

```
/etc/fail2ban/
├── jail.conf          # NE PAS MODIFIER (fichier par défaut)
├── jail.local          # Config globale perso (créé manuellement)
├── jail.d/
│   └── rakouns-*.conf  # Une jail par service, convention Rakouns
├── filter.d/
│   ├── *.conf          # Filtres fournis par défaut
│   └── rakouns-*.conf  # Filtres personnalisés
└── action.d/
    ├── *.conf
    └── iptables-docker.conf  # Action custom pour cibler DOCKER-USER
```

<span style="color:#1a1a1a;">Créer la config globale de base si elle n'existe pas :</span>

<table class="MsoNormalTable" id="bkmrk-sudo-touch-%2Fetc%2Ffail" style="width:468pt;border-collapse:collapse;border:none;"><tbody><tr><td style="width:468pt;border:solid #D9D9D9 1pt;background:#F2F2F2;padding:6pt 8pt 6pt 8pt;"><span lang="en-gb" style="font-size:9.5pt;line-height:110%;font-family:Consolas;color:#1a1a1a;">sudo touch /etc/fail2ban/jail.local</span>

</td></tr></tbody></table>

<span style="color:#1a1a1a;">Exemple de socle dans </span><span style="font-size:10.5pt;line-height:120%;font-family:Consolas;color:#ae3a78;background:#F7F0F4;">jail.local</span><span style="color:#1a1a1a;"> (valeurs par défaut appliquées à toutes les jails, sauf surcharge) :</span>

```
[DEFAULT]
bantime  = 1h
findtime = 10m
maxretry = 5
backend  = auto
ignoreip = 127.0.0.1/8 192.168.1.0/24
```

<p class="callout info">**<span style="font-size:10.5pt;line-height:115%;color:#1f2d3d;">Note — </span>**<span style="font-size:10.5pt;line-height:115%;color:#1a1a1a;">ignoreip doit inclure ton réseau local pour éviter de te bannir toi-même pendant les tests.</span></p>

## Cas Docker : l'action iptables-docker

<span style="color:#1a1a1a;">Comme évoqué en page 1, le ban standard via la chaîne </span><span style="font-size:10.5pt;line-height:120%;font-family:Consolas;color:#ae3a78;background:#F7F0F4;">INPUT</span><span style="color:#1a1a1a;"> n'a aucun effet sur le trafic redirigé vers des conteneurs Docker, car Docker insère ses propres règles dans la chaîne </span><span style="font-size:10.5pt;line-height:120%;font-family:Consolas;color:#ae3a78;background:#F7F0F4;">DOCKER-USER</span><span style="color:#1a1a1a;"> avant que la chaîne </span><span style="font-size:10.5pt;line-height:120%;font-family:Consolas;color:#ae3a78;background:#F7F0F4;">INPUT</span><span style="color:#1a1a1a;"> ne soit évaluée.</span>

<span style="color:#1a1a1a;">Créer </span><span style="font-size:10.5pt;line-height:120%;font-family:Consolas;color:#ae3a78;background:#F7F0F4;">/etc/fail2ban/action.d/iptables-docker.conf</span><span style="color:#1a1a1a;"> :</span>

```
[Definition]
actionstart = iptables -N f2b-<name>
              iptables -A f2b-<name> -j RETURN
              iptables -I DOCKER-USER -j f2b-<name>
 
actionstop = iptables -D DOCKER-USER -j f2b-<name>
             iptables -F f2b-<name>
             iptables -X f2b-<name>
 
actioncheck = iptables -n -L DOCKER-USER | grep -q 'f2b-<name>[ \t]'
 
actionban = iptables -I f2b-<name> 1 -s <ip> -j DROP
 
actionunban = iptables -D f2b-<name> -s <ip> -j DROP
 
[Init]
name = default
```

<span style="color:#1a1a1a;">Cette action sera référencée dans chaque jail concernée (voir Page 4).</span>

## Vérification rapide de l'installation

```
sudo fail2ban-client status
sudo fail2ban-client version
```

# Filter

[![fail2ban_2.png](https://docs.rakouns.bzh/uploads/images/gallery/2026-06/scaled-1680-/fail2ban-2.png)](https://docs.rakouns.bzh/uploads/images/gallery/2026-06/fail2ban-2.png)

## <span>Principe</span>

Un filter est un fichier <span style="font-size:10.5pt;line-height:120%;font-family:Consolas;color:#000000;background-image:initial;background-position:initial;background-size:initial;background-repeat:initial;background-attachment:initial;">.conf</span> dans <span style="font-size:10.5pt;line-height:120%;font-family:Consolas;color:#000000;background-image:initial;background-position:initial;background-size:initial;background-repeat:initial;background-attachment:initial;">/etc/fail2ban/filter.d/</span> qui contient une (ou plusieurs) expression(s) régulière(s) capable(s) de repérer, dans une ligne de log, une tentative échouée, et d'en extraire l'adresse IP via le groupe nommé <span style="font-size:10.5pt;line-height:120%;font-family:Consolas;color:#000000;background-image:initial;background-position:initial;background-size:initial;background-repeat:initial;background-attachment:initial;">&lt;HOST&gt;</span>.

Structure minimale :

```
[Definition]
failregex = <ta regex avec <HOST>>
ignoreregex =
```

<span style="font-size:10.5pt;line-height:120%;font-family:Consolas;color:#000000;background-image:initial;background-position:initial;background-size:initial;background-repeat:initial;background-attachment:initial;">&lt;HOST&gt;</span> est une macro fail2ban qui correspond à une regex IPv4/IPv6 déjà prête à l'emploi — pas besoin de l'écrire toi-même.

## <span>Méthode générale pour écrire un filter</span>

<span>1.<span style="font:7pt 'Times New Roman';"> </span></span>**Identifier une ligne de log représentative** d'un échec d'authentification.

<span>2.<span style="font:7pt 'Times New Roman';"> </span></span>**Repérer ce qui varie** (timestamp, IP, user) vs ce qui est fixe (le message d'erreur).

<span>3.<span style="font:7pt 'Times New Roman';"> </span></span>**Écrire la regex**, en remplaçant l'IP par <span style="font-size:10.5pt;line-height:115%;font-family:Consolas;color:#000000;background-image:initial;background-position:initial;background-size:initial;background-repeat:initial;background-attachment:initial;">&lt;HOST&gt;</span> et en échappant les caractères spéciaux (<span style="font-size:10.5pt;line-height:115%;font-family:Consolas;color:#000000;background-image:initial;background-position:initial;background-size:initial;background-repeat:initial;background-attachment:initial;">.</span>, <span style="font-size:10.5pt;line-height:115%;font-family:Consolas;color:#000000;background-image:initial;background-position:initial;background-size:initial;background-repeat:initial;background-attachment:initial;">\[</span>, <span style="font-size:10.5pt;line-height:115%;font-family:Consolas;color:#000000;background-image:initial;background-position:initial;background-size:initial;background-repeat:initial;background-attachment:initial;">\]</span>, etc.).

<span>4.<span style="font:7pt 'Times New Roman';"> </span></span>**Tester** avec <span style="font-size:10.5pt;line-height:115%;font-family:Consolas;color:#000000;background-image:initial;background-position:initial;background-size:initial;background-repeat:initial;background-attachment:initial;">fail2ban-regex</span> avant de créer la jail.

## <span>Exemple générique : filter SSH (fourni par défaut, pour référence)</span>

<span style="font-size:10.5pt;line-height:120%;font-family:Consolas;color:#000000;background-image:initial;background-position:initial;background-size:initial;background-repeat:initial;background-attachment:initial;">/etc/fail2ban/filter.d/sshd.conf</span> (déjà présent, à ne pas modifier) repère une ligne du type :

```
Jun 20 10:15:32 host sshd[1234]: Failed password for invalid user admin from 203.0.113.42 port 51234 ssh2
```

avec une regex de la forme :

```
failregex = ^%(__prefix_line)sFailed \S+ for .* from <HOST>(?: port \d+)?(?: ssh2)?\s*$
```

## <span>Fil rouge : filter Vaultwarden</span>

Vaultwarden journalise les échecs de connexion via Docker (stdout → <span style="font-size:10.5pt;line-height:120%;font-family:Consolas;color:#000000;background-image:initial;background-position:initial;background-size:initial;background-repeat:initial;background-attachment:initial;">json-file</span>). Une ligne typique ressemble à :

```
[2026-06-20 10:15:32.123][vaultwarden::api::identity][WARN] Username or password is incorrect. Try again. IP: 203.0.113.42. Username: user@example.com.
```

Créer <span style="font-size:10.5pt;line-height:120%;font-family:Consolas;color:#000000;background-image:initial;background-position:initial;background-size:initial;background-repeat:initial;background-attachment:initial;">/etc/fail2ban/filter.d/rakouns-vaultwarden.conf</span> :

```
[Definition]
failregex = ^.*Username or password is incorrect\. Try again\. IP: <HOST>\..*$
            ^.*Username or password is incorrect\. IP: <HOST>\..*$
ignoreregex =
datepattern = ^\[%%Y-%%m-%%d %%H:%%M:%%S
```

<p class="callout info">**<span style="font-size:10.5pt;line-height:115%;color:#000000;">Note — </span>**<span style="font-size:10.5pt;line-height:115%;color:#000000;">Plusieurs lignes dans failregex (une par ligne) sont évaluées en OU logique — utile quand le message d'erreur varie légèrement selon la version du service.</span></p>

## <span>Tester un filter avant de créer la jail</span>

**Toujours** valider un filter sur un vrai log (ou un extrait) avant de l'attacher à une jail, pour éviter de générer un faux sentiment de sécurité avec un filter qui ne matche jamais — ou pire, qui matche trop large.

### <span>Test sur un fichier de log classique</span>

```
sudo fail2ban-regex /var/log/auth.log /etc/fail2ban/filter.d/sshd.conf
```

### <span>Test sur les logs Docker (cas Vaultwarden)</span>

Les logs Docker ne sont pas dans un fichier classique par défaut, il faut soit extraire un échantillon, soit pointer directement sur le fichier json-file du conteneur :

```
# Trouver le chemin du log JSON du conteneur
docker inspect --format='{{.LogPath}}' vaultwarden
 
# Tester le filter contre ce fichier
sudo fail2ban-regex /var/lib/docker/containers/<container_id>/<container_id>-json.log /etc/fail2ban/filter.d/rakouns-vaultwarden.conf
```

### <span>Lecture du résultat</span>

fail2ban-regex affiche un résumé du type :

```
Results
=======
 
Failregex: 3 total
|-  #) [# of hits] regular expression
|   1) [3] ^.*Username or password is incorrect\. Try again\. IP: <HOST>\..*$
`-
 
Ignoreregex: 0 total
 
Lines: 150 lines, 0 ignored, 3 matched, 147 missed
```

<span style="font-size:10.5pt;line-height:120%;font-family:Consolas;color:#000000;background-image:initial;background-position:initial;background-size:initial;background-repeat:initial;background-attachment:initial;">3 matched</span> confirme que le filter fonctionne. Si tu obtiens <span style="font-size:10.5pt;line-height:120%;font-family:Consolas;color:#000000;background-image:initial;background-position:initial;background-size:initial;background-repeat:initial;background-attachment:initial;">0 matched</span> alors que tu sais qu'il y a des échecs dans le log, retravaille la regex (espace en trop, caractère spécial non échappé, format de date différent, etc.).

# Jail

[![fail2ban_2.png](https://docs.rakouns.bzh/uploads/images/gallery/2026-06/scaled-1680-/fail2ban-2.png)](https://docs.rakouns.bzh/uploads/images/gallery/2026-06/fail2ban-2.png)

## <span>Principe</span>

La jail relie un filter à :

<span>•<span style="font:7pt 'Times New Roman';"> </span></span>une source de log (logpath ou backend pour Docker),

<span>•<span style="font:7pt 'Times New Roman';"> </span></span>des seuils (maxretry, findtime, bantime),

<span>•<span style="font:7pt 'Times New Roman';"> </span></span>une action (action, par défaut iptables classique, ou iptables-docker pour les conteneurs).

Convention Rakouns : un fichier par jail dans <span style="font-size:10.5pt;line-height:120%;font-family:Consolas;color:#000000;background-image:initial;background-position:initial;background-size:initial;background-repeat:initial;background-attachment:initial;">/etc/fail2ban/jail.d/</span>, nommé <span style="font-size:10.5pt;line-height:120%;font-family:Consolas;color:#000000;background-image:initial;background-position:initial;background-size:initial;background-repeat:initial;background-attachment:initial;">rakouns-&lt;service&gt;.conf</span>.

## <span>Structure générale d'une jail</span>

```
[rakouns-<service>]
enabled  = true
filter   = rakouns-<service>
logpath  = <chemin ou source du log>
backend  = polling          ; obligatoire pour les logs Docker json-file
maxretry = 5
findtime = 10m
bantime  = 1h
action   = iptables-docker[name=<service>]
```

<p class="callout info">**<span style="font-size:10.5pt;line-height:115%;color:#000000;">Note — </span>**<span style="font-size:10.5pt;line-height:115%;color:#000000;">backend = polling est requis pour tout service conteneurisé dont les logs sont au format json-file : le backend auto/systemd ne détecte pas les nouvelles lignes correctement dans ce format.</span></p>

## <span>Exemple générique : jail SSH</span>

```
[sshd]
enabled  = true
filter   = sshd
logpath  = /var/log/auth.log
maxretry = 5
findtime = 10m
bantime  = 1h
```

C'est le cas le plus simple : pas de Docker, pas d'action custom, le ban standard sur la chaîne INPUT suffit.

## <span>Fil rouge : jail Vaultwarden</span>

Créer <span style="font-size:10.5pt;line-height:120%;font-family:Consolas;color:#000000;background-image:initial;background-position:initial;background-size:initial;background-repeat:initial;background-attachment:initial;">/etc/fail2ban/jail.d/rakouns-vaultwarden.conf</span> :

```
[rakouns-vaultwarden]
enabled  = true
filter   = rakouns-vaultwarden
logpath  = /var/lib/docker/containers/<container_id>/<container_id>-json.log
backend  = polling
maxretry = 5
findtime = 10m
bantime  = 24h
action   = iptables-docker[name=vaultwarden]
```

Points clés :

<span>•<span style="font:7pt 'Times New Roman';"> </span></span><span style="font-size:10.5pt;line-height:115%;font-family:Consolas;color:#000000;background-image:initial;background-position:initial;background-size:initial;background-repeat:initial;background-attachment:initial;">backend = polling</span> → indispensable, sinon la jail reste en <span style="font-size:10.5pt;line-height:115%;font-family:Consolas;color:#000000;background-image:initial;background-position:initial;background-size:initial;background-repeat:initial;background-attachment:initial;">0 currently failed</span> même en cas d'attaque réelle.

<span>•<span style="font:7pt 'Times New Roman';"> </span></span><span style="font-size:10.5pt;line-height:115%;font-family:Consolas;color:#000000;background-image:initial;background-position:initial;background-size:initial;background-repeat:initial;background-attachment:initial;">action = iptables-docker\[name=vaultwarden\]</span> → utilise l'action custom créée en Page 2, qui cible <span style="font-size:10.5pt;line-height:115%;font-family:Consolas;color:#000000;background-image:initial;background-position:initial;background-size:initial;background-repeat:initial;background-attachment:initial;">DOCKER-USER</span> avec une chaîne dédiée <span style="font-size:10.5pt;line-height:115%;font-family:Consolas;color:#000000;background-image:initial;background-position:initial;background-size:initial;background-repeat:initial;background-attachment:initial;">f2b-vaultwarden</span>.

<span>•<span style="font:7pt 'Times New Roman';"> </span></span><span style="font-size:10.5pt;line-height:115%;font-family:Consolas;color:#000000;background-image:initial;background-position:initial;background-size:initial;background-repeat:initial;background-attachment:initial;">bantime = 24h</span> plus long que la valeur par défaut, car Vaultwarden contient des coffres de mots de passe : la tolérance au brute-force doit être minimale.

<p class="callout info"><span>**<span style="font-size:10.5pt;line-height:115%;color:#000000;">Note — </span>**<span style="font-size:10.5pt;line-height:115%;color:#000000;">Le container\_id change si le conteneur est recréé (mise à jour d'image, docker compose up -d --force-recreate). Un script de détection automatique du chemin de log peut éviter d'avoir à mettre à jour la jail manuellement à chaque recréation.</span></span></p>

## <span>Jail recidive</span>

Recommandé en complément de toutes les jails de service : bannit plus longtemps une IP déjà bannie plusieurs fois.

```
[recidive]
enabled  = true
filter   = recidive
logpath  = /var/log/fail2ban.log
banaction = iptables-allports
bantime  = 1w
findtime = 1d
maxretry = 3
```

## <span>Recharger et activer une jail</span>

```
sudo fail2ban-client reload
# ou, pour recharger une jail spécifique sans tout relancer :
sudo fail2ban-client reload rakouns-vaultwarden
```

Vérifier qu'elle est bien prise en compte :

```
sudo fail2ban-client status
Status

|- Number of jail:      3

`- Jail list:   sshd, recidive, rakouns-vaultwarden
```

Puis le détail d'une jail précise :

```
sudo fail2ban-client status rakouns-vaultwarden
Status for the jail: rakouns-vaultwarden
|- Filter
|  |- Currently failed: 0
|  |- Total failed:     0
|  `- File list:        /var/lib/docker/containers/.../....log
`- Actions
   |- Currently banned: 0
   |- Total banned:     0
   `- Banned IP list:
```

# Vérifier le pare-feu

## <span>[![fail2ban_2.png](https://docs.rakouns.bzh/uploads/images/gallery/2026-06/scaled-1680-/fail2ban-2.png)](https://docs.rakouns.bzh/uploads/images/gallery/2026-06/fail2ban-2.png)</span>

## <span>Pourquoi cette étape est indispensable</span>

Une jail «active» côté fail2ban (<span style="font-size:10.5pt;line-height:120%;font-family:Consolas;color:#000000;background-image:initial;background-position:initial;background-size:initial;background-repeat:initial;background-attachment:initial;">fail2ban-client status</span> qui répond) ne garantit **pas** que le ban est réellement appliqué au niveau du pare-feu — surtout sur l'infra Rakouns où Docker manipule ses propres règles iptables. C'est l'erreur la plus fréquente : croire qu'une jail fonctionne juste parce qu'elle est listée comme <span style="font-size:10.5pt;line-height:120%;font-family:Consolas;color:#000000;background-image:initial;background-position:initial;background-size:initial;background-repeat:initial;background-attachment:initial;">enabled</span>.

## <span>Vérification générique : ban classique</span>

Pour une jail standard (ex : <span style="font-size:10.5pt;line-height:120%;font-family:Consolas;color:#000000;background-image:initial;background-position:initial;background-size:initial;background-repeat:initial;background-attachment:initial;">sshd</span>), vérifier que la règle de ban apparaît bien dans iptables :

```
sudo iptables -L f2b-sshd -n
```

Résultat attendu après un ban :

```
Chain f2b-sshd (1 references)
target     prot opt source               destination
DROP       all  --  203.0.113.42         0.0.0.0/0
RETURN     all  --  0.0.0.0/0            0.0.0.0/0
```

## <span>Vérification Docker : chaîne DOCKER-USER</span>

Pour les jails utilisant l'action <span style="font-size:10.5pt;line-height:120%;font-family:Consolas;color:#000000;background-image:initial;background-position:initial;background-size:initial;background-repeat:initial;background-attachment:initial;">iptables-docker</span> (cas Vaultwarden et tous les services conteneurisés), c'est la chaîne <span style="font-size:10.5pt;line-height:120%;font-family:Consolas;color:#000000;background-image:initial;background-position:initial;background-size:initial;background-repeat:initial;background-attachment:initial;">DOCKER-USER</span> qu'il faut inspecter, **pas** <span style="font-size:10.5pt;line-height:120%;font-family:Consolas;color:#000000;background-image:initial;background-position:initial;background-size:initial;background-repeat:initial;background-attachment:initial;">INPUT</span> :

```
sudo iptables -L DOCKER-USER -n --line-numbers
```

La chaîne dédiée du service doit apparaître en première position (insérée avec -I, donc évaluée avant le reste) :

```
Chain DOCKER-USER (1 references)
num  target          prot opt source               destination
1    f2b-vaultwarden all  --  0.0.0.0/0            0.0.0.0/0
2    RETURN          all  --  0.0.0.0/0            0.0.0.0/0
```

Puis inspecter la sous-chaîne pour voir si une IP y est effectivement droppée :

```
sudo iptables -L f2b-vaultwarden -n

Chain f2b-vaultwarden (1 references)
target     prot opt source               destination
DROP       all  --  203.0.113.42         0.0.0.0/0
RETURN     all  --  0.0.0.0/0            0.0.0.0/0
```

Si la chaîne <span style="font-size:10.5pt;line-height:120%;font-family:Consolas;color:#000000;background-image:initial;background-position:initial;background-size:initial;background-repeat:initial;background-attachment:initial;">f2b-vaultwarden</span> n'apparaît pas du tout dans <span style="font-size:10.5pt;line-height:120%;font-family:Consolas;color:#000000;background-image:initial;background-position:initial;background-size:initial;background-repeat:initial;background-attachment:initial;">DOCKER-USER</span>, l'action <span style="font-size:10.5pt;line-height:120%;font-family:Consolas;color:#000000;background-image:initial;background-position:initial;background-size:initial;background-repeat:initial;background-attachment:initial;">iptables-docker</span> n'a pas pu s'initialiser correctement : vérifier <span style="font-size:10.5pt;line-height:120%;font-family:Consolas;color:#000000;background-image:initial;background-position:initial;background-size:initial;background-repeat:initial;background-attachment:initial;">actionstart</span> dans <span style="font-size:10.5pt;line-height:120%;font-family:Consolas;color:#000000;background-image:initial;background-position:initial;background-size:initial;background-repeat:initial;background-attachment:initial;">iptables-docker.conf</span> (page 2) et relire les logs fail2ban (section suivante).

## <span>Provoquer un ban de test (en sécurité)</span>

Pour valider toute la chaîne sans attendre une vraie attaque, depuis une machine **différente** de celle utilisée pour administrer le service (sinon tu te bannis toi-même de ton accès SSH/admin) :

```
# Déclencher volontairement des échecs d'auth (exemple Vaultwarden via curl)
for i in {1..6}; do
  curl -s -o /dev/null -w "%{http_code}\n" \
    -X POST https://vault.rakouns.bzh/identity/connect/token \
    -d "username=test@test.com&password=wrongpassword&grant_type=password"
done
```

Puis vérifier côté fail2ban :

```
sudo fail2ban-client status rakouns-vaultwarden
```

L'IP de test doit apparaître dans <span style="font-size:10.5pt;line-height:120%;font-family:Consolas;color:#000000;background-image:initial;background-position:initial;background-size:initial;background-repeat:initial;background-attachment:initial;">Banned IP list</span>. Pour débannir manuellement après test :

```
sudo fail2ban-client set rakouns-vaultwarden unbanip <IP_DE_TEST>
```

## <span>Logs fail2ban : diagnostic en cas de doute</span>

```
sudo tail -f /var/log/fail2ban.log
```

Lignes à surveiller :

<span>•<span style="font:7pt 'Times New Roman';"> </span></span><span style="font-size:10.5pt;line-height:115%;font-family:Consolas;color:#000000;background-image:initial;background-position:initial;background-size:initial;background-repeat:initial;background-attachment:initial;">\[rakouns-vaultwarden\] Found &lt;IP&gt;</span> → un échec a été détecté par le filter (le filter fonctionne).

<span>•<span style="font:7pt 'Times New Roman';"> </span></span><span style="font-size:10.5pt;line-height:115%;font-family:Consolas;color:#000000;background-image:initial;background-position:initial;background-size:initial;background-repeat:initial;background-attachment:initial;">\[rakouns-vaultwarden\] Ban &lt;IP&gt;</span> → le seuil maxretry a été atteint et le ban a été déclenché (la jail fonctionne).

<span>•<span style="font:7pt 'Times New Roman';"> </span></span>Absence totale de Found malgré des échecs visibles dans les logs applicatifs → revenir à la Page 3 et retester le filter avec fail2ban-regex.

<span>•<span style="font:7pt 'Times New Roman';"> </span></span>Found présent mais jamais de Ban → vérifier maxretry/findtime, ou que ignoreip (jail.local) n'exclut pas l'IP de test par erreur.

## <span>Vérification post-reboot / post-recreate</span>

Deux cas fréquents sur Rakouns où le ban peut «disparaître» silencieusement :

<span>1.<span style="font:7pt 'Times New Roman';"> </span></span>**Reboot du host** : les règles iptables ne sont pas persistées par défaut. Vérifier que fail2ban redémarre bien après le pare-feu/Docker (<span style="font-size:10.5pt;line-height:115%;font-family:Consolas;color:#000000;background-image:initial;background-position:initial;background-size:initial;background-repeat:initial;background-attachment:initial;">systemctl status fail2ban</span>), et que <span style="font-size:10.5pt;line-height:115%;font-family:Consolas;color:#000000;background-image:initial;background-position:initial;background-size:initial;background-repeat:initial;background-attachment:initial;">DOCKER-USER</span> est repeuplée par actionstart au démarrage du service.

<span>2.<span style="font:7pt 'Times New Roman';"> </span></span>**Recréation d'un conteneur** (mise à jour d'image) : le container\_id change, donc le logpath de la jail devient invalide. Penser à relancer le script de détection automatique du chemin de log (mentionné en Page 4) puis <span style="font-size:10.5pt;line-height:115%;font-family:Consolas;color:#000000;background-image:initial;background-position:initial;background-size:initial;background-repeat:initial;background-attachment:initial;">fail2ban-client reload &lt;jail&gt;</span>.

## <span>Checklist de vérification rapide</span>

```
# 1. La jail est listée et active
sudo fail2ban-client status
 
# 2. Le filter remonte des "Found" sur le service concerné
sudo fail2ban-client status rakouns-vaultwarden
 
# 3. La chaîne f2b-<service> existe dans DOCKER-USER (cas Docker)
sudo iptables -L DOCKER-USER -n
 
# 4. Les logs confirment Found -> Ban en cas d'incident réel
sudo grep "rakouns-vaultwarden" /var/log/fail2ban.log | tail -20
```