
Pare-feu et Fail2ban : verrouiller les accès réseau du NAS
Pourquoi un pare-feu sur un NAS domestique
Un NAS est un serveur qui tourne 24h/24 et héberge des données sensibles : partages de fichiers, media server, parfois de la domotique. Sans pare-feu, tous les ports sont ouverts par défaut et n'importe quel appareil du réseau peut y accéder. Dès qu'un port est exposé vers l'extérieur pour de l'accès distant, la surface d'attaque explose.
Deux couches complémentaires sur ce TerraMaster F4-424 : UFW pour filtrer les ports, Fail2ban pour détecter et bannir les tentatives d'intrusion.
UFW : un pare-feu lisible
UFW est un frontend pour iptables/nftables dont l'avantage principal est la lisibilité des règles, face à la syntaxe cryptique d'iptables.
Politique par défaut — tout verrouiller d'abord :
ufw default deny incoming
ufw default allow outgoing
Tout le trafic entrant est bloqué sauf autorisation explicite, tandis que le NAS peut communiquer vers l'extérieur (mises à jour, DNS, NTP).
SSH — plutôt qu'un simple allow, limit restreint à 3 connexions par minute depuis la même IP, ce qui constitue une première défense contre le brute-force avant même Fail2ban :
ufw limit ssh
Services LAN uniquement — les partages de fichiers n'ont pas besoin d'être joignables depuis Internet :
# Samba (Windows/macOS)
ufw allow from 192.168.1.0/24 to any port 445
ufw allow from 192.168.1.0/24 to any port 139
# NFS (Linux)
ufw allow from 192.168.1.0/24 to any port 2049
Services Docker exposés — certains conteneurs doivent rester accessibles, y compris via VPN :
ufw allow 8096/tcp # Jellyfin
ufw allow 6881/tcp # qBittorrent
ufw allow 22000/tcp # Syncthing
ufw allow 8123/tcp # Home Assistant
Un ufw status verbose donne l'état complet :
Status: active
Logging: on (low)
Default: deny (incoming), allow (outgoing), disabled (routed)
To Action From
-- ------ ----
22/tcp LIMIT Anywhere
445 ALLOW 192.168.1.0/24
139 ALLOW 192.168.1.0/24
2049 ALLOW 192.168.1.0/24
8096/tcp ALLOW Anywhere
6881/tcp ALLOW Anywhere
22000/tcp ALLOW Anywhere
8123/tcp ALLOW Anywhere
Le piège Docker + UFW
Docker bypasse UFW. Quand Docker publie un port (-p 8080:80), il injecte ses règles directement dans iptables avant UFW. Résultat : les conteneurs sont accessibles depuis partout même si UFW bloque le port.
Option 1 — désactiver iptables dans Docker, via /etc/docker/daemon.json :
{
"iptables": false
}
Attention : Docker ne gère alors plus le NAT des conteneurs, il faut le configurer manuellement.
Option 2, préférable — ajouter des règles dans DOCKER-USER, qui s'évalue avant les règles Docker :
# /etc/ufw/after.rules (à la fin du fichier)
*filter
:DOCKER-USER - [0:0]
-A DOCKER-USER -s 192.168.1.0/24 -j ACCEPT
-A DOCKER-USER -j DROP
COMMIT
Docker reste fonctionnel, mais les conteneurs sont limités au LAN.
Fail2ban : bannir les intrus
UFW filtre les ports mais ne détecte pas les tentatives de brute-force. Fail2ban surveille les logs et bannit temporairement les IP suspectes.
La jail SSH, dans /etc/fail2ban/jail.local :
[sshd]
enabled = true
port = ssh
filter = sshd
logpath = /var/log/auth.log
backend = systemd
# 3 tentatives max avant ban
maxretry = 3
# Fenêtre de détection : 10 minutes
findtime = 600
Bans progressifs
Plutôt qu'un ban fixe, une stratégie progressive : une erreur de mot de passe coûte dix minutes, un attaquant qui insiste se retrouve banni de plus en plus longtemps.
# Ban progressif
bantime.increment = true
bantime.multipliers = 1 5 30 60 180 360 720
bantime = 600
| Récidive | Multiplicateur | Durée du ban |
|---|---|---|
| 1er ban | x1 | 10 minutes |
| 2e ban | x5 | 50 minutes |
| 3e ban | x30 | 5 heures |
| 4e ban | x60 | ~10 heures |
| 5e ban | x180 | ~30 heures |
| 6e ban | x360 | ~2.5 jours |
| 7e ban | x720 | ~5 semaines |
Un bot qui insiste finit banni cinq semaines ; en pratique, la quasi-totalité abandonne avant.
L'action par défaut bloque l'IP via iptables. action = %(action_mwl)s ajoute un email avec les logs et le whois de l'attaquant, utile pour monitorer.
Vérification de l'état de la jail :
fail2ban-client status sshd
Status for the jail: sshd
|- Filter
| |- Currently failed: 0
| |- Total failed: 47
| `- File list: /var/log/auth.log
`- Actions
|- Currently banned: 2
|- Total banned: 12
`- Banned IP list: 203.0.113.42 198.51.100.7
Automatisation Ansible
Le pare-feu et Fail2ban sont déployés via un rôle Ansible idempotent :
# roles/firewall/tasks/main.yml
- name: Install UFW and Fail2ban
ansible.builtin.apt:
name:
- ufw
- fail2ban
state: present
tags: [firewall]
- name: Set UFW default policies
community.general.ufw:
direction: '{{ item.direction }}'
policy: '{{ item.policy }}'
loop:
- { direction: incoming, policy: deny }
- { direction: outgoing, policy: allow }
tags: [firewall, ufw]
- name: Configure UFW rules
community.general.ufw:
rule: '{{ item.rule }}'
port: '{{ item.port }}'
proto: "{{ item.proto | default('tcp') }}"
from_ip: "{{ item.from_ip | default('any') }}"
loop: '{{ firewall_rules }}'
tags: [firewall, ufw]
- name: Deploy Fail2ban jail configuration
ansible.builtin.template:
src: jail.local.j2
dest: /etc/fail2ban/jail.local
mode: '0644'
notify: Restart fail2ban
tags: [firewall, fail2ban]
Les règles vivent dans les variables du rôle : déclaratif et versionnable dans Git.
Conclusion
UFW rend le filtrage de ports accessible, Fail2ban ajoute une détection active, et Ansible garantit que tout survit aux réinstallations. Le piège Docker/UFW reste le point le plus critique : sans l'avoir adressé, les conteneurs sont probablement exposés sans qu'on le sache.
Articles similaires