Profil minimal de pare-feu Debian 13 : quoi autoriser et quoi bloquer (sans paranoïa)

Cet article vous a aidé ?

Les pare-feu ne tombent pas en panne de manière bruyante. Ils échouent comme un saboteur poli : votre déploiement « réussit », vos outils de supervision deviennent gris, et votre équipe commence à accuser le DNS par habitude.

Debian 13 vous donne toute la plomberie nécessaire pour une posture de pare-feu propre, minimale et ennuyeuse. Ce guide porte sur laisser passer le bon trafic, bloquer le reste, et diagnostiquer rapidement les ruptures — sans transformer votre serveur en objet d’exposition que personne ne peut faire fonctionner.

Principes : minimal, stateful et observable

Un « profil de pare-feu minimal » n’est pas « tout bloquer et prier ». C’est une politique explicite qui correspond à l’usage de la machine, et elle est implémentée avec un pare-feu stateful pour éviter de bricoler chaque paquet de réponse comme en 1999.

1) Refuser par défaut l’entrée, autoriser les connexions établies

Le trafic entrant doit être refusé à moins d’une raison d’accepter. Mais une fois que vous acceptez une connexion, vous devez accepter le trafic de réponse apparenté. C’est le rôle du suivi d’état. Si vous essayez d’être rusé et bloquez la moitié d’un handshake TCP, vous n’apprendrez que de nouvelles façons de souffrir.

2) Le sortant : de « pas parano » à « pas de surprises »

La plupart des profils minimaux laissent le trafic sortant par défaut. C’est acceptable pour de nombreux serveurs — jusqu’au moment où vous traitez un processus compromis qui exfiltre joyeusement via 443 vers n’importe où. Un compromis sensé : autoriser largement le sortant, mais logger et éventuellement restreindre les destinations/ports « étranges » une fois que vous connaissez le rôle de la machine.

3) La journalisation doit répondre à une question, pas produire de l’art

Si vous journalisez chaque paquet rejeté, vos logs deviennent un moyen coûteux de stocker la météo des botnets. Journalisez avec limites de débit, et seulement aux frontières que vous investiguez vraiment : nouvelles rejets entrants, sorties inattendues, et types ICMP bloqués qui cassent PMTUD.

4) Si ça ne peut pas être testé, ce n’est pas une politique

Un jeu de règles qui n’existe que dans la tête de quelqu’un est une histoire du soir. Votre pare-feu doit être testable depuis l’hôte et depuis le réseau. Vous avez besoin de commandes qui vérifient « SSH fonctionne depuis le sous‑réseau admin », « la supervision peut scraper », et « la résolution DNS n’est pas cassée silencieusement ».

Une citation, parce qu’elle tient encore : « Hope is not a strategy. » — John C. Maxwell. Les opérations la répètent parce que l’alternative, c’est écrire des rapports d’incident sur des « on a supposé ».

Petite blague #1 : Un pare‑feu, c’est comme un videur — s’il ne sait pas qui est sur la liste des invités, il finira par refuser le DJ et laisser entrer le type qui porte un routeur.

Faits intéressants et contexte historique (court, utile)

  • Netfilter est arrivé dans Linux 2.4 (début 2001), remplaçant l’ancien code de filtrage et permettant le modèle conntrack moderne qui fait fonctionner « established/related ».
  • iptables est une interface, pas le moteur. Les hooks noyau sous-jacents sont netfilter ; les outils ont évolué car l’interface devenait lourde et difficile à étendre.
  • nftables a été introduit pour unifier les variantes iptables (iptables, ip6tables, arptables, ebtables) en un seul cadre avec une meilleure évaluation des règles et des structures de données.
  • conntrack est un état partagé, pas de la magie. Il consomme de la mémoire ; sous charge ou attaque, un mauvais réglage peut provoquer des connexions perdues qui ressemblent à des « instabilités réseau aléatoires ».
  • ICMP n’est pas optionnel pour un TCP sain. Bloquer tout ICMP casse PMTUD, provoquant des blocages sur certains chemins et certaines MTU. Les équipes redécouvrent cela tous les quelques années.
  • Les pare‑feu stateful ne servent pas qu’à l’entrée. Les politiques sortantes reposent souvent sur l’état pour autoriser le trafic de retour sans ouvrir de ports entrants.
  • Debian privilégie « faire une chose correctement ». Elle n’impose pas de gestionnaire de pare‑feu ; vous disposez de nftables, de la compatibilité iptables-nft, et vous choisissez le niveau d’opinion de votre wrapper.
  • Les security groups cloud ont changé les attentes. Beaucoup d’équipes considèrent désormais les pare‑feu hôtes comme secondaires. Cela fonctionne jusqu’à ce que quelqu’un migre une VM vers une autre frontière réseau ou mal configure un security group.

Modèle de menace utilisable

Un profil de pare‑feu minimal n’est pas une checklist de conformité. C’est une carte du trafic attendu. Commencez par ce contre quoi vous vous défendez :

  • Scans Internet et exploitation opportuniste. Si vous exposez SSH ou un port web, attendez‑vous à du bruit constant et à un flux régulier de mauvaises idées.
  • Mouvement latéral à l’intérieur du réseau. Les réseaux internes ne sont pas magiquement fiables. Ils sont simplement les lieux où les attaques sont plus discrètes.
  • Exposition accidentelle. Un développeur bind un serveur de debug sur 0.0.0.0, ou un paquet ouvre un port dont vous aviez oublié l’existence.
  • Exfiltration de données et command‑and‑control. Les règles sortantes sont le seul endroit où vous pouvez réellement ralentir cela au niveau de l’hôte.
  • Pannes auto‑infligées. La plupart des incidents de pare‑feu ne sont pas des hackers. C’est vous, à 2h du matin, appliquant « un petit changement ».

Minimal ne signifie pas fragile. L’objectif est un jeu de règles assez petit pour être compréhensible et assez strict pour supprimer les surprises.

Ce qu’il faut autoriser vs ce qu’il faut bloquer (serveur Debian 13 typique)

Entrant : refuser par défaut, n’autoriser que ce que vous pouvez nommer

L’entrée est là où vous gagnez en étant ennuyeux. Commencez par une posture « default-drop », puis autorisez explicitement :

  • SSH (TCP/22) depuis un sous‑réseau admin, bastion ou plage VPN. Si vous devez autoriser depuis n’importe où, ajoutez un rate limiting et une authentification forte.
  • HTTP/HTTPS (TCP/80, TCP/443) uniquement si l’hôte est réellement un point d’accès web. Beaucoup de machines n’ont pas besoin d’avoir ces ports ouverts.
  • Ingress de supervision (variable) : par ex. node exporter (9100), SNMP (161/udp), agents personnalisés. Préférez le « pull depuis le sous‑réseau de supervision » plutôt que l’exposition globale.
  • Ports spécifiques aux services pour bases de données et brokers uniquement vers les sous‑réseaux applicatifs qui en ont besoin. Les bases de données ne devraient presque jamais accepter des connexions depuis « anywhere ».
  • ICMP de manière sélective : autorisez echo‑request depuis les réseaux de confiance, et autorisez les erreurs ICMP nécessaires au PMTUD (au moins les messages « fragmentation needed »).

Sortant : commencer permissif, puis resserrer selon la réalité

Le sortant est l’endroit où les gens ne font rien ou font un bunker complet. L’approche pragmatique :

  • Autoriser DNS (UDP/TCP 53) vers vos résolveurs uniquement, ou vers le résolveur local si vous en avez un. Le DNS sortant aléatoire est souvent signe d’un problème.
  • Autoriser NTP (UDP/123) vers vos sources de temps. La dérive temporelle provoque des échecs d’authentification et des logs confus.
  • Autoriser les mises à jour (TCP/80/443) vers le monde si nécessaire, ou vers votre proxy/mirror d’entreprise si vous en avez un.
  • Autoriser l’egress métier : bases de données, bus de messages, stockages objets, API. Documentez‑les ; sinon vous vous optimiserez en panne plus tard.

Ce qu’il faut bloquer sans culpabilité

  • Tout l’entrant qui n’est pas explicitement autorisé.
  • Tous les UDP entrants par défaut sauf si vous hébergez un service UDP (serveur DNS, serveur NTP, point d’accès VPN, récepteur syslog, etc.). L’exposition UDP invite à la bizarrerie.
  • Tout SMB/NFS/RPC entrant sauf si l’hôte est un serveur de fichiers et que vous l’avez strictement restreint. Ces protocoles sont utiles — dans le bon périmètre.
  • Tous les « ports de management » (API Docker, kubelet, dashboards aléatoires) sauf si vous pouvez dire qui en a besoin et d’où.

Petite blague #2 : Si vous « ouvrez temporairement tous les ports », votre pare‑feu devient un poster de motivation : il a l’air protecteur, mais il inspire surtout l’optimisme.

Un profil nftables minimal (avec justification)

Debian 13 exécutera volontiers nftables comme pare‑feu principal. Gardez le jeu de règles lisible, commentez‑le, et résistez à l’envie de construire un second stack réseau à l’intérieur du pare‑feu.

Choix de conception

  • Table inet unique pour la symétrie IPv4+IPv6. Si vous n’écrivez que des règles v4, v6 devient la porte dérobée que vous n’avez pas voulue installer.
  • Input default drop, forward default drop. Output default accept (initialement), avec option de durcissement ultérieur.
  • Autoriser loopback toujours. Casser le trafic localhost est une excellente manière d’inventer de nouveaux modes de panne.
  • Autoriser established/related tôt pour la performance et la raison.
  • Autoriser les essentiels ICMP/ICMPv6 plutôt que « tout » ou « rien ».
  • Journaliser les rejets avec limite de débit. Vous voulez du signal, pas un aquarium de paquets.

Exemple de jeu de règles minimal

cr0x@server:~$ sudo tee /etc/nftables.conf > /dev/null <<'EOF'
#!/usr/sbin/nft -f

flush ruleset

table inet filter {
  set admin_v4 {
    type ipv4_addr
    flags interval
    elements = { 192.0.2.0/24, 198.51.100.10 }
  }

  chain input {
    type filter hook input priority 0; policy drop;

    # Always allow loopback
    iif "lo" accept

    # Allow established/related traffic
    ct state established,related accept

    # Drop invalid packets early
    ct state invalid drop

    # ICMP/ICMPv6: keep the network healthy
    ip protocol icmp icmp type { echo-request, echo-reply, destination-unreachable, time-exceeded, parameter-problem } accept
    ip6 nexthdr icmpv6 icmpv6 type { echo-request, echo-reply, destination-unreachable, time-exceeded, packet-too-big, parameter-problem } accept

    # SSH from admin networks only
    ip saddr @admin_v4 tcp dport 22 ct state new accept

    # Example: HTTPS if this host is a web endpoint
    tcp dport 443 ct state new accept

    # Log & drop everything else (rate-limited)
    limit rate 10/second burst 20 packets log prefix "nft-in-drop " level info
    drop
  }

  chain forward {
    type filter hook forward priority 0; policy drop;
  }

  chain output {
    type filter hook output priority 0; policy accept;

    # Optional: tighten later once you know your egress
    # Example patterns shown in the tasks section.
  }
}
EOF

Ceci est volontairement simple. Il n’essaie pas de résoudre un DDoS. Il ne micro‑gère pas chaque connexion sortante. Il empêche l’exposition accidentelle, réduit le rayon d’impact d’un « oops j’ai installé un démon », et rend l’accès entrant traçable.

Deux notes opérationnelles qui évitent des douleurs :

  • IPv6 existe. Si votre hôte a IPv6 activé (fréquent), mais que votre pare‑feu ne couvre que l’IPv4, vous avez une contournement non intentionnel.
  • N’oubliez pas la persistance. Un jeu de règles appliqué manuellement à 15h et disparu au redémarrage n’est pas un pare‑feu ; c’est une œuvre de performance.

Tâches pratiques (commandes, sorties, décisions)

Voici les choses que vous faites réellement sur une machine Debian 13 quand vous voulez un pare‑feu minimal qui ne génère pas de tickets. Chaque tâche inclut : la commande, ce que signifie la sortie, et la décision à prendre.

Task 1: Confirmer quel backend de pare‑feu vous utilisez réellement

cr0x@server:~$ sudo update-alternatives --display iptables
iptables - auto mode
  link best version is /usr/sbin/iptables-nft
  link currently points to /usr/sbin/iptables-nft
  link iptables is /usr/sbin/iptables
/usr/sbin/iptables-legacy - priority 10
/usr/sbin/iptables-nft - priority 20

Ce que ça signifie : Vous utilisez le backend nftables via la compat iptables. C’est acceptable, mais mélanger des règles iptables natives et des jeux de règles nftables peut rapidement devenir confus.

Décision : Préférez des règles nftables natives dans /etc/nftables.conf. Si iptables legacy est en cours d’utilisation, planifiez une fenêtre de migration.

Task 2: Vérifier si nftables est actif et persistant

cr0x@server:~$ systemctl status nftables
● nftables.service - nftables
     Loaded: loaded (/lib/systemd/system/nftables.service; enabled)
     Active: active (exited) since Mon 2025-12-30 09:11:10 UTC; 2min ago
       Docs: man:nft(8)

Ce que ça signifie : Le service est activé et a chargé votre jeu de règles. « active (exited) » est normal ; il charge les règles puis sort.

Décision : S’il est désactivé/inactif, activez‑le après validation des règles : sudo systemctl enable --now nftables.

Task 3: Lister le jeu de règles actif (faire confiance, mais vérifier)

cr0x@server:~$ sudo nft list ruleset
table inet filter {
	set admin_v4 {
		type ipv4_addr
		flags interval
		elements = { 192.0.2.0/24, 198.51.100.10 }
	}

	chain input {
		type filter hook input priority filter; policy drop;
		iif "lo" accept
		ct state established,related accept
		ct state invalid drop
		ip protocol icmp icmp type { echo-request, echo-reply, destination-unreachable, time-exceeded, parameter-problem } accept
		ip6 nexthdr icmpv6 icmpv6 type { echo-request, echo-reply, destination-unreachable, time-exceeded, packet-too-big, parameter-problem } accept
		ip saddr @admin_v4 tcp dport 22 ct state new accept
		tcp dport 443 ct state new accept
		limit rate 10/second burst 20 packets log prefix "nft-in-drop " level info
		drop
	}
}

Ce que ça signifie : Le noyau a actuellement exactement ce que vous pensez avoir chargé. C’est la vérité terrain.

Décision : Si vous voyez des tables/chains inattendues, d’autres outils écrivent des règles (agent cloud, plateforme de conteneurs, vieux scripts). Décidez qui possède le pare‑feu.

Task 4: Valider la syntaxe de la config avant application (éviter de se verrouiller)

cr0x@server:~$ sudo nft -c -f /etc/nftables.conf

Ce que ça signifie : Pas de sortie = bien ; la vérification de syntaxe est passée. Si une erreur apparaît, elle indique le numéro de ligne et le token.

Décision : N’appliquez jamais de configs de pare‑feu non validées sur SSH sauf si vous avez une console hors bande ou un filet de sécurité.

Task 5: Trouver les services réellement à l’écoute (arrêtez de deviner)

cr0x@server:~$ sudo ss -lntu
Netid State  Recv-Q Send-Q Local Address:Port  Peer Address:Port Process
tcp   LISTEN 0      4096   0.0.0.0:22         0.0.0.0:*
tcp   LISTEN 0      4096   0.0.0.0:443        0.0.0.0:*
udp   UNCONN 0      0      127.0.0.53:53      0.0.0.0:*

Ce que ça signifie : Seuls SSH et HTTPS sont exposés sur toutes les interfaces ; DNS est lié au résolveur stub local seulement. Bonne base.

Décision : Si vous voyez un port surprise écoutant sur 0.0.0.0 ou :::, fermez‑le côté service (préféré) ou parez‑le explicitement jusqu’à compréhension.

Task 6: Identifier le processus propriétaire d’un port

cr0x@server:~$ sudo ss -lntup 'sport = :443'
Netid State  Recv-Q Send-Q Local Address:Port Peer Address:Port Process
tcp   LISTEN 0      4096   0.0.0.0:443       0.0.0.0:*     users:(("nginx",pid=1187,fd=6))

Ce que ça signifie : nginx est à l’écoute. Utile pour décider si ouvrir 443 est nécessaire.

Décision : Si ce n’est pas un service que vous voulez exposer sur Internet, corrigez l’adresse de bind du service ou désactivez‑le.

Task 7: Vérifier la route par défaut et les interfaces (les règles de pare‑feu sont sensibles à l’interface)

cr0x@server:~$ ip -br addr
lo               UNKNOWN        127.0.0.1/8 ::1/128
ens3             UP             203.0.113.20/24 2001:db8:1234::20/64

cr0x@server:~$ ip route
default via 203.0.113.1 dev ens3
203.0.113.0/24 dev ens3 proto kernel scope link src 203.0.113.20

Ce que ça signifie : ens3 est l’interface réelle ; vous avez aussi IPv6. Si votre pare‑feu ne couvre pas inet, il vous manque la moitié de l’histoire.

Décision : Utilisez table inet sauf raison délibérée de faire autrement.

Task 8: Confirmer que vous ne forwardez pas des paquets par erreur

cr0x@server:~$ sysctl net.ipv4.ip_forward net.ipv6.conf.all.forwarding
net.ipv4.ip_forward = 0
net.ipv6.conf.all.forwarding = 0

Ce que ça signifie : Cet hôte n’agit pas comme routeur. Bon pour des serveurs typiques.

Décision : Si le forwarding est activé involontairement, désactivez‑le ou assurez‑vous que la policy forward est explicite et sûre.

Task 9: Surveiller les rejets en direct (prouver que le pare‑feu est le problème)

cr0x@server:~$ sudo journalctl -f -k | grep -E 'nft-in-drop|IN='
Dec 30 09:15:22 server kernel: nft-in-drop IN=ens3 OUT= MAC=... SRC=198.51.100.77 DST=203.0.113.20 LEN=60 TOS=0x00 PREC=0x00 TTL=49 ID=4242 DF PROTO=TCP SPT=51234 DPT=22 WINDOW=64240 SYN

Ce que ça signifie : Quelqu’un depuis 198.51.100.77 a tenté un SYN vers SSH et a été rejeté par vos règles (non accepté par le set admin_v4).

Décision : Si c’est un accès admin légitime, ajoutez l’IP/plage source à la liste blanche. Sinon, ignorez et conservez des logs limités en débit.

Task 10: Vérifier que l’état conntrack fonctionne (les règles stateful en dépendent)

cr0x@server:~$ sudo conntrack -S
cpu=0 found=412 new=37 invalid=2 ignore=0 delete=12 delete_list=12 insert=37 insert_failed=0 drop=0 early_drop=0 error=0 search_restart=0

Ce que ça signifie : conntrack fonctionne ; un faible drop/early_drop est sain.

Décision : Si vous voyez beaucoup de drop ou early_drop, vous pouvez épuiser la table conntrack sous charge ou attaque. Envisagez un tuning et réduisez l’exposition inutile.

Task 11: Vérifier la capacité de la table conntrack (coupable classique des échecs aléatoires)

cr0x@server:~$ sysctl net.netfilter.nf_conntrack_count net.netfilter.nf_conntrack_max
net.netfilter.nf_conntrack_count = 1832
net.netfilter.nf_conntrack_max = 262144

Ce que ça signifie : Vous êtes loin de la capacité. Si le count approche le max, le suivi d’état devient un goulot.

Décision : Si vous êtes près du max en charge normale, augmentez nf_conntrack_max et assurez‑vous d’avoir de la mémoire disponible ; réduisez aussi l’exposition entrante superflue.

Task 12: Confirmer que le DNS fonctionne avec votre posture de pare‑feu

cr0x@server:~$ resolvectl status
Global
       Protocols: -LLMNR -mDNS -DNSOverTLS DNSSEC=no/unsupported
resolv.conf mode: stub
Current DNS Server: 192.0.2.53
       DNS Servers: 192.0.2.53 192.0.2.54

cr0x@server:~$ dig +short debian.org
151.101.2.132

Ce que ça signifie : Le résolveur système utilise votre DNS interne, et les résolutions réussissent.

Décision : Si le DNS échoue après durcissement du sortant, autorisez UDP/TCP 53 vers les résolveurs listés (pas « anywhere »).

Task 13: Tester l’accessibilité entrante depuis l’hôte lui‑même (contrôle de bon sens)

cr0x@server:~$ nc -vz 127.0.0.1 22
Connection to 127.0.0.1 22 port [tcp/ssh] succeeded!

cr0x@server:~$ nc -vz 127.0.0.1 443
Connection to 127.0.0.1 443 port [tcp/https] succeeded!

Ce que ça signifie : Les services sont opérationnels localement. Si l’accès distant échoue, c’est territoire pare‑feu/routage/security‑group, pas le démon.

Décision : Ne « corrigez » pas nginx quand le problème est un SYN rejeté.

Task 14: Appliquer les règles en sécurité avec un garde‑temps de rollback automatique

cr0x@server:~$ sudo bash -c 'nft -c -f /etc/nftables.conf && (sleep 20; nft flush ruleset) & nft -f /etc/nftables.conf'

Ce que ça signifie : Cela applique les règles, mais planifie un flush dans 20 secondes. Si vous vous verrouillez, les règles s’autodétruisent.

Décision : Utilisez un garde comme celui‑ci lors d’éditions sur SSH. Si tout fonctionne, annulez le rollback en tuant le process sleep en arrière‑plan (ou réappliquez proprement et redémarrez nftables).

Task 15: Rendre les règles persistantes et contrôlées par systemd

cr0x@server:~$ sudo systemctl enable --now nftables
Synchronizing state of nftables.service with SysV service script with /lib/systemd/systemd-sysv-install.
Executing: /lib/systemd/systemd-sysv-install enable nftables

Ce que ça signifie : Les règles se chargeront au boot ; vous êtes passé de l’état runtime bricolé à un service géré.

Décision : Désormais, les changements passent par la gestion de configuration ou au moins par un contrôle de version.

Task 16: Durcir le sortant sans casser les mises à jour (exemple)

C’est là où les équipes paniquent et ne font rien. Voici un modèle viable : garder la policy output accept, mais autoriser explicitement les ports nécessaires et logger le reste pendant un temps avant de passer à drop.

cr0x@server:~$ sudo nft add rule inet filter output ct state established,related accept
cr0x@server:~$ sudo nft add rule inet filter output oif "lo" accept
cr0x@server:~$ sudo nft add rule inet filter output udp dport 53 ip daddr { 192.0.2.53, 192.0.2.54 } accept
cr0x@server:~$ sudo nft add rule inet filter output tcp dport 53 ip daddr { 192.0.2.53, 192.0.2.54 } accept
cr0x@server:~$ sudo nft add rule inet filter output udp dport 123 ip daddr 192.0.2.123 accept
cr0x@server:~$ sudo nft add rule inet filter output tcp dport { 80, 443 } accept

Ce que ça signifie : Vous avez énuméré DNS, NTP et egress web. Si vous changez ensuite la policy output vers drop, ces règles gardent la machine fonctionnelle.

Décision : Recueillez ce dont vous avez besoin ensuite (backends de métriques, endpoints de stockage objet, relais mail) avant d’appliquer drop.

Trois petites histoires d’entreprise du terrain

Incident : une mauvaise hypothèse (IPv6 « pas utilisé »)

Une équipe gérait une flotte Debian propre derrière un load balancer cloud. Ils ont écrit un pare‑feu IPv4 propre : default drop entrant, autoriser 443, autoriser SSH depuis la plage VPN. Ils se sont félicités et sont passés à autre chose. La fenêtre de changement s’est terminée tôt, ce qui est toujours suspect.

Une semaine plus tard, la sécurité a signalé du trafic entrant qui n’aurait pas dû être possible. Pas parce que le pare‑feu était « cassé », mais parce qu’il était hors sujet. Les hôtes avaient des adresses IPv6 globales attribuées automatiquement, et les règles ne couvraient que l’IPv4. Le service était accessible via IPv6 directement, contournant le chemin du load balancer et le périmètre prévu.

Ce n’était pas une attaque exotique. C’était Internet faisant son travail : scanner tout ce qui a une adresse routable. Les logs étaient maigres parce qu’ils ne journalisaient que les rejets IPv4. Pendant ce temps, l’équipe applicative chassait des fantômes dans la config du load balancer.

La correction n’a pas été héroïque. Ils ont déplacé le jeu de règles vers une table inet, ont autorisé explicitement ce qu’ils voulaient pour v6, et ont tout rejeté le reste. Puis ils ont audité l’adressage : soit garder IPv6 et le maîtriser, soit le désactiver intentionnellement. La vraie leçon n’était pas « IPv6 est effrayant ». C’était « si vous n’avez pas écrit de règle pour IPv6, vous ne le contrôlez pas ».

Optimisation qui s’est retournée contre eux (bloquer ICMP pour « réduire le bruit »)

Une équipe plateforme a fini par en avoir assez des « tempêtes de ping » et des logs ICMP aléatoires. Quelqu’un a proposé une politique propre : bloquer tout ICMP entrant et sortant. Moins de bruit, moins de débats sur la surface d’attaque, plus de temps pour des choses importantes — comme des réunions.

Un temps, tout semblait bien. Puis certains clients ont commencé à signaler des timeouts intermittents sur de grosses réponses. Pas tous les clients. Pas tous les chemins. Juste assez pour en faire un casse‑tête rotatif. La première réponse fut de blâmer l’application. La seconde, le réseau. La troisième, d’augmenter les timeouts, qui est une façon honorable de cacher un problème jusqu’à ce qu’il devienne inavouable.

Le vrai problème : la découverte de la MTU de chemin (PMTUD). Certains itinéraires nécessitaient la gestion de la fragmentation, et les serveurs devaient recevoir les ICMP « packet too big » (IPv6) ou les messages d’erreur correspondants (IPv4). Avec ICMP bloqué, les connexions s’enlisent avec des paquets noirs. Les petites requêtes fonctionnent. Les grosses échouent lentement.

Ils ont annulé le blocage blanket d’ICMP et l’ont remplacé par « autoriser l’essentiel, limiter les echo ». L’incident n’a pas été coûteux en matériel ou support. Il a coûté en attention. Le retour de bâton n’était pas l’optimisation elle‑même ; c’était optimiser la mauvaise chose.

Pratique ennuyeuse mais correcte qui a sauvé la mise (déploiement par étapes + rejets journalisés)

Une entreprise avec une équipe SRE modérément saine voulait des pare‑feu hôtes sur des centaines de serveurs Debian. L’expression clé ici est « modérément saine » : ils n’ont pas essayé de le faire parfaitement en une fois. Ils ont écrit une politique minimale default‑drop entrante, puis l’ont déployée en mode observation d’abord avec logs de reje t limités et un tableau de bord résumant les ports bloqués par sous‑réseau.

La première semaine a été ennuyeuse. Les bots ont frappé SSH ; le pare‑feu les a rejetés. Quelques IP admin légitimes manquaient dans la liste blanche ; ils ont corrigé. Quelques vérifications de supervision legacy venaient encore d’anciens réseaux ; ils ont migré ces vérifications. Personne n’a paniqué car le déploiement était progressif, et parce qu’ils pouvaient voir ce qui était rejeté.

La deuxième semaine a montré où le travail « ennuyeux » a payé. Lors d’un incident séparé — mauvaise configuration d’une appli causant des floods de connexions sortantes — l’équipe a pu prouver rapidement que ce n’était pas un événement entrant. Les logs du pare‑feu étaient calmes. La table conntrack était stable. Le réseau était sain. Ils se sont concentrés sur la bonne couche et ont résolu plus vite.

Voici le cheat code opérationnel : un pare‑feu minimal + observabilité, déployé progressivement, est moins excitant qu’une refonte mais ça marche.

Playbook de diagnostic rapide

Quand « le réseau est cassé », vous voulez une séquence qui rétrécit la recherche en quelques minutes, pas une visite d’une heure des opinions de tout le monde.

Premier : le service écoute‑t‑il vraiment ?

  • Exécutez ss -lntu. Si rien n’écoute sur le port attendu, arrêtez de blâmer le pare‑feu.
  • Exécutez systemctl status <service>. S’il est planté ou lié à localhost, le pare‑feu est spectateur.

Deuxième : le trafic atteint‑il l’hôte ?

  • Vérifiez l’interface/adresse : ip -br addr.
  • Depuis un client distant, tentez une connexion TCP. Sur le serveur, écoutez avec tcpdump sur l’interface. Si les SYN n’arrivent jamais, c’est en amont : routage/security group/NACL.

Troisième : le pare‑feu le rejette‑t‑il ?

  • Vérifiez les logs : journalctl -k | grep nft-in-drop.
  • Lister les règles et compteurs : nft list ruleset. Si vous ne comptez pas, commencez ; les compteurs transforment les suppositions en chiffres.

Quatrième : si c’est « intermittent », vérifiez conntrack et ICMP

  • conntrack -S et sysctl net.netfilter.nf_conntrack_count pour symptômes de capacité.
  • Vérifiez la politique ICMP. Si vous avez bloqué packet-too-big/time-exceeded, vous vous êtes assuré une panne étrange.

Cinquième : valider les dépendances sortantes

  • DNS : resolvectl status et dig.
  • Heure : timedatectl et l’état de votre client NTP.
  • Mises à jour/proxies : tentez apt-get update et regardez les rejets.

Erreurs courantes : symptôme → cause racine → réparation

1) « SSH fonctionnait avant, maintenant je suis verrouillé »

Symptôme : SSH timeout après application des règles.

Cause racine : Vous avez autorisé SSH seulement depuis un sous‑réseau qui n’inclut pas votre IP actuelle, ou vous avez oublié les chemins d’accès SSH via IPv6.

Réparation : Utilisez une console hors bande ou le guard rollback. Ajoutez votre plage source admin à un nft set ; appliquez via nft -c d’abord. Assurez‑vous que les règles sont dans table inet pour gérer v6.

2) « HTTPS est ouvert mais les clients plantent sur de grosses réponses »

Symptôme : Petites requêtes réussissent ; gros téléchargements se bloquent ou reset de manière imprévisible.

Cause racine : ICMP « packet too big » (IPv6) ou messages PMTUD bloqués ; problèmes de fragmentation noirs.

Réparation : Autorisez les types ICMP/ICMPv6 essentiels, pas seulement echo. Gardez des logs limités en débit.

3) « La supervision ne voit plus rien soudainement »

Symptôme : Scrapes de métriques échouent ou agents ne peuvent se connecter après changements du pare‑feu.

Cause racine : Les IP sources de supervision ont changé (nouveaux collecteurs, NAT, nouvelle plage) et n’étaient pas dans les allowlists.

Réparation : Utilisez des nft sets pour les sous‑réseaux de supervision et tenez‑les à jour. Préférez autoriser depuis les réseaux de supervision, pas « any ».

4) « DNS échoue aléatoirement seulement sur cet hôte »

Symptôme : Certaines résolutions time out ; d’autres réussissent.

Cause racine : UDP/53 autorisé mais TCP/53 bloqué ; grosses réponses DNS ou fallback DNSSEC nécessitent TCP.

Réparation : Autorisez à la fois UDP et TCP 53 vers vos résolveurs.

5) « Les connexions sont instables sous charge »

Symptôme : Échecs de connexion aléatoires entrant ou sortant pendant des pics.

Cause racine : Exhaustion de la table conntrack ou churn élevé ; le pare‑feu stateful ne peut pas allouer d’entrées.

Réparation : Tenez nf_conntrack_max et envisagez de réduire l’exposition ou d’utiliser un SYN proxy en amont. Vérifiez aussi que vous ne tracez pas du trafic inutilement (ex. interfaces locales uniquement).

6) « J’ai autorisé le port 443, mais il est toujours bloqué »

Symptôme : Les clients distants ne peuvent pas se connecter ; la connexion locale fonctionne.

Cause racine : Security group/NACL en amont le bloque, ou le service est lié à localhost, ou vous testez IPv6 alors que vous n’autorisez que l’IPv4.

Réparation : Confirmez l’adresse de bind via ss -lntup. Confirmez que les paquets arrivent via tcpdump. Utilisez inet pour la parité v4/v6.

7) « Docker/Kubernetes change mon pare‑feu à ma place »

Symptôme : Le jeu de règles diffère de /etc/nftables.conf ; des règles accept inattendues apparaissent.

Cause racine : Les outils conteneurs manipulent netfilter pour implémenter NAT/forwarding.

Réparation : Décidez de la propriété : laissez la plateforme gérer des tables/chains spécifiques, ou isolez votre politique hôte dans une table dédiée et évitez d’écraser les chains plateforme. Validez après déploiement.

Listes de contrôle / plan étape par étape

Checklist A : Politique inbound minimale pour un serveur typique

  1. Inventaire des listeners : exécutez ss -lntu. Si un service ne doit pas être public, corrigez le service d’abord (bind à localhost ou désactiver).
  2. Décidez du chemin d’accès admin : VPN/bastion/sous‑réseau. Notez‑le. Vraiment.
  3. Écrivez des règles nftables dans une table inet : accept loopback, accept established/related, drop invalid.
  4. Autorisez SSH seulement depuis les réseaux admin : utilisez un set pour que les changements n’exigent pas de réécrire les règles.
  5. Autorisez seulement les ports de service requis : 443 pour le web, peut‑être rien d’autre.
  6. Autorisez les types essentiels ICMP/ICMPv6 : gardez PMTUD fonctionnel.
  7. Limitez le débit des logs de reje t : sinon vous finirez par couper la journalisation.
  8. Validez la syntaxe : nft -c -f /etc/nftables.conf.
  9. Appliquez avec un garde‑temps si distant : planifiez un flush si vous êtes nerveux.
  10. Activez le service nftables : persistant au reboot.

Checklist B : Posture sortante sensée sans s’auto‑sabot er

  1. Mesurez d’abord : journalisez l’egress inattendu pendant une semaine avant d’appliquer drop.
  2. Autorisez DNS vers les résolveurs : UDP/TCP 53 vers vos serveurs connus.
  3. Autorisez NTP vers les sources de temps : ne laissez pas le temps dériver et inventer des problèmes d’auth.
  4. Autorisez les mises à jour : TCP 80/443 vers proxy ou mirror ; sinon vous ouvrirez « temporairement » pour toujours.
  5. Autorisez les dépendances métier : bases de données, queues, endpoints de stockage objet.
  6. Ensuite seulement envisagez output policy drop : et gardez un chemin break‑glass d’urgence.

Checklist C : Gestion des changements sans créer d’incident

  1. Déployez par étapes : canarisez un petit pourcentage d’hôtes.
  2. Ayez un chemin hors bande : console, série, ou au moins un timer de rollback.
  3. Utilisez des compteurs et des logs : sinon vous déboguerez à l’intuition.
  4. Consignez l’intention : un commentaire par règle coûte moins cher qu’un postmortem.
  5. Testez depuis les bons endroits : réseau admin, réseau de supervision, et un réseau hostile externe (ou au moins un sous‑réseau différent).

FAQ

1) Dois‑je utiliser nftables directement ou un outil wrapper ?

Si vous gérez des serveurs de production et voulez un comportement prévisible, utilisez nftables directement. Les wrappers peuvent convenir, mais ils cachent souvent les règles réelles et compliquent le débogage.

2) « Refuser par défaut l’entrée » suffit‑il comme sécurité ?

C’est une base solide, pas un programme de sécurité complet. Cela réduit l’exposition accidentelle et limite les scans opportunistes. Il vous faut toujours patcher, avoir une authentification saine, le principe du moindre privilège et de la supervision.

3) Dois‑je filtrer le trafic sortant ?

Pas forcément dès le premier jour. Mais vous devriez au moins comprendre vos dépendances sortantes et journaliser l’egress inhabituel. Les règles sortantes valent le coup une fois le rôle de l’hôte stabilisé.

4) Pourquoi autoriser un peu d’ICMP ?

Parce que les réseaux utilisent ICMP pour fonctionner correctement, pas seulement pour le « ping ». PMTUD et les signaux d’erreur en dépendent. Bloquez echo si nécessaire, mais ne détruisez pas packet-too-big et consorts.

5) Quel est l’ensemble minimal entrant pour un serveur sans interface ?

Loopback, established/related, ICMP/ICMPv6 essentiels, et SSH depuis un réseau admin. C’est tout, sauf si l’hôte sert du trafic.

6) Comment éviter de me verrouiller hors de SSH ?

Validez avec nft -c, appliquez avec un timer de rollback, et gardez une console hors bande. Aussi, ne testez pas de nouvelles règles pour la première fois sur l’unique hôte que vous ne pouvez pas redémarrer.

7) IPv6 — le désactiver ou le filtrer ?

Filtrez‑le. Désactiver IPv6 peut être acceptable dans certains environnements, mais c’est souvent un jeu du chat et de la souris avec des outils et des valeurs par défaut. Si l’hôte a IPv6, votre politique doit en tenir compte.

8) Dois‑je ouvrir les ports de base de données au public si le mot de passe est fort ?

Non. Une authentification forte est bonne ; l’exposition inutile reste dangereuse. Restreignez les ports DB aux sous‑réseaux applicatifs ou aux réseaux privés. Pour un accès distant, utilisez un bastion ou un VPN.

9) Puis‑je me reposer sur les security groups cloud au lieu des pare‑feu hôtes ?

Vous pouvez, jusqu’à ce que vous ne puissiez plus. Les pare‑feu hôtes sont un filet de sécurité local et une garde‑fou contre des listeners accidentels. Utilisez les deux quand c’est possible ; à minima, mettez des pare‑feu hôtes sur les systèmes à haute valeur.

10) Quelle quantité de journalisation activer pour les paquets rejetés ?

Assez pour diagnostiquer : logs limités en débit pour les nouveaux rejets entrants, et éventuellement pour l’egress inattendu. Si vos logs deviennent un journal de botnet, vous cesserez de les lire — et alors ils deviennent inutiles.

Prochaines étapes sans ruiner votre week-end

Faites trois choses dans cet ordre, et vous obtiendrez 80 % de la valeur avec 20 % du risque :

  1. Inventoriez les listeners avec ss -lntu et arrêtez tout ce qui ne doit pas être exposé. Cela réduit la politique de pare‑feu nécessaire.
  2. Déployez le profil inbound nftables minimal (table inet, loopback, established/related, ICMP/ICMPv6 essentiel, SSH depuis sous‑réseau admin, ports de service réellement servis). Activez la persistance via systemd.
  3. Ajoutez de l’observabilité : logs de reje t limités en débit, et une habitude de diagnostic rapide (état d’écoute → arrivée des paquets → décision pare‑feu → conntrack/ICMP).

Une fois stable, décidez jusqu’où aller sur les restrictions sortantes. Commencez par la journalisation et la allowlist DNS/NTP/mises à jour. Durcissez uniquement après avoir observé le trafic réel. « Pas de paranoïa » ne signifie pas « pas de politique ». Cela signifie que votre politique est ancrée dans ce que font réellement vos serveurs, pas dans ce que votre anxiété imagine.

← Précédent
MySQL vs PostgreSQL — Incidents de disque plein : qui récupère plus proprement et plus vite
Suivant →
Ubuntu 24.04 : Docker + UFW = ports ouverts à la surprise — colmatez la brèche sans casser les conteneurs

Laisser un commentaire