Pare-feu nftables de base pour serveurs Linux
Construire un pare-feu nftables en deny par défaut, durcir les sysctls réseau et réduire la surface des services exposés sur tout serveur Linux.
Un pare-feu est le contrôle le moins coûteux et le plus rentable que vous puissiez placer devant un serveur Linux, et pourtant la plupart des machines acceptent tout par défaut en comptant uniquement sur le fait que les services n'écoutent pas. Cette hypothèse s'effondre dès qu'un démon se lie à 0.0.0.0 par erreur. Ce guide construit un pare-feu inet en deny par défaut avec nftables, ajoute les sysctls réseau que le pare-feu ne peut pas imposer, et montre comment énumérer puis réduire l'ensemble des services réellement exposés. Le résultat est une base que vous pouvez déployer sur tout hôte Debian, Ubuntu, RHEL ou Fedora récent.
Pourquoi le deny par défaut
Il existe deux façons d'écrire une politique de pare-feu. Une liste de blocage accepte tout et bloque le trafic indésirable ; elle échoue en mode ouvert, donc tout service oublié reste joignable. Une liste d'autorisation rejette tout et n'accepte que ce que vous nommez ; elle échoue en mode fermé, donc une erreur coûte la disponibilité d'un seul service au lieu d'un trou silencieux. Pour un serveur, le deny par défaut est le seul choix défendable. Le minimum à autoriser est le trafic loopback, les paquets appartenant à des connexions déjà initiées (established,related), les messages ICMP nécessaires au bon fonctionnement du réseau, et la poignée de services entrants que cet hôte offre réellement, à commencer par SSH.
Un jeu de règles nftables complet
nftables remplace l'ancienne séparation iptables/ip6tables par une unique famille inet qui couvre IPv4 et IPv6 d'un coup. Écrivez la politique dans /etc/nftables.conf :
#!/usr/sbin/nft -f
flush ruleset
table inet filter {
chain input {
type filter hook input priority 0; policy drop;
ct state established,related accept
ct state invalid drop
iif lo accept
# ICMP / ICMPv6 essentiels
ip protocol icmp icmp type { echo-request, destination-unreachable, time-exceeded, parameter-problem } accept
ip6 nexthdr icmpv6 icmpv6 type { echo-request, destination-unreachable, time-exceeded, parameter-problem, packet-too-big, nd-neighbor-solicit, nd-neighbor-advert, nd-router-advert, nd-router-solicit } accept
# SSH
tcp dport ssh ct state new accept
# Journaliser et rejeter le reste
limit rate 5/minute log prefix "nft-drop-in: " flags all counter drop
}
chain forward {
type filter hook forward priority 0; policy drop;
}
chain output {
type filter hook output priority 0; policy accept;
}
}
Chargez-le, activez-le au démarrage et inspectez le jeu de règles actif :
sudo nft -f /etc/nftables.conf
sudo systemctl enable --now nftables
sudo nft list ruleset
Ajoutez les autres services à l'écoute explicitement, une règle chacun, par exemple tcp dport { 80, 443 } ct state new accept pour un serveur web. Gardez une session SSH ouverte pendant l'application pour qu'une erreur ne vous verrouille pas dehors. Voir durcissement du noyau et services & systemd pour les couches voisines.
Les front ends firewalld et ufw
Sur RHEL et Fedora, firewalld est le front end managé au-dessus de nftables. Définissez une zone par défaut en deny et ajoutez les services par nom :
sudo firewall-cmd --set-default-zone=drop
sudo firewall-cmd --zone=drop --add-service=ssh
sudo firewall-cmd --runtime-to-permanent
Sur Ubuntu, ufw est l'enveloppe conviviale :
sudo ufw default deny incoming
sudo ufw allow OpenSSH
sudo ufw enable
Choisissez un seul front end par hôte. N'éditez pas /etc/nftables.conf à la main tant que firewalld ou ufw gère aussi le jeu de règles, sinon les deux s'écraseront mutuellement.
Sysctls de durcissement réseau
Le pare-feu ne peut pas changer la façon dont le noyau lui-même traite les redirections, le routage à la source ou les paquets usurpés. Réglez cela dans un drop-in dédié /etc/sysctl.d/90-network-hardening.conf :
# Filtrage par chemin inverse (anti-usurpation)
net.ipv4.conf.all.rp_filter = 1
net.ipv4.conf.default.rp_filter = 1
# Ignorer et ne jamais envoyer de redirections ICMP
net.ipv4.conf.all.accept_redirects = 0
net.ipv4.conf.default.accept_redirects = 0
net.ipv6.conf.all.accept_redirects = 0
net.ipv4.conf.all.send_redirects = 0
net.ipv4.conf.default.send_redirects = 0
# Rejeter les paquets routés à la source
net.ipv4.conf.all.accept_source_route = 0
net.ipv6.conf.all.accept_source_route = 0
# Protection contre les SYN flood
net.ipv4.tcp_syncookies = 1
# Journaliser les paquets usurpés / martiens
net.ipv4.conf.all.log_martians = 1
# Ignorer les pings broadcast (protection smurf)
net.ipv4.icmp_echo_ignore_broadcasts = 1
# Désactiver les annonces de routeur IPv6 si inutilisées
net.ipv6.conf.all.accept_ra = 0
net.ipv6.conf.default.accept_ra = 0
Appliquez tous les drop-ins et vérifiez une valeur :
sudo sysctl --system
sysctl net.ipv4.tcp_syncookies
Réduire les services exposés
Un pare-feu ne justifie pas de faire tourner des services dont vous n'avez pas besoin. Listez chaque socket en écoute avec le processus propriétaire :
sudo ss -tulpn
Tout ce qui est lié à 0.0.0.0 ou [::] est joignable depuis le réseau. Lorsqu'un service n'est consommé que localement (une base de données, un exporteur de métriques, un cache), liez-le à 127.0.0.1 dans sa configuration au lieu de compter uniquement sur le pare-feu. Désactivez les démons que vous n'utilisez pas du tout plutôt que de les filtrer. Associez ceci à accès & authentification et détection d'intrusion pour une défense en profondeur.
Vérification
Confirmez le pare-feu, les sysctls et les services à l'écoute après chaque modification :
sudo nft list ruleset
sudo systemctl is-enabled nftables
sysctl net.ipv4.conf.all.rp_filter net.ipv4.tcp_syncookies
sudo ss -tulpn
Depuis un hôte externe, scannez un port que vous n'avez pas autorisé et confirmez qu'il est filtré :
nmap -Pn -p 22,80,443,3306 votre.serveur.exemple
Seuls les ports explicitement acceptés doivent apparaître ouverts ; tout le reste doit être filtré ou fermé.