Ubuntu 24.04 : pare-feu IPv6 oublié — colmatez la vraie brèche (pas seulement IPv4) (cas #72)

Cet article vous a aidé ?

Vous avez verrouillé le serveur. Du moins vous le pensez. L’IPv4 semble propre, UFW indique « active » et le ticket de changement est clos. Puis un scanner cible votre adresse IPv6 et trouve SSH, un endpoint de métriques et quelque chose dont vous aviez oublié l’existence.

C’est le mode d’échec silencieux du dual-stack : vous durcissez l’ancien Internet et laissez par inadvertance le nouveau sur le perron avec une clé de rechange sous le paillasson. Ubuntu 24.04 n’est pas « particulièrement » mauvais ici. Il est simplement assez moderne pour que l’IPv6 soit courant, tandis que les habitudes opérationnelles restent bloquées en 2012.

Le vrai problème : « le pare‑feu est activé » n’est pas une affirmation

Les pare‑feu ne sont pas binaires. Ce sont un empilement de règles à travers les couches :

  • Filtre de paquets du noyau (nftables sur Ubuntu 24.04 ; iptables legacy peut encore traîner).
  • Enveloppe pare‑feu sur l’hôte (UFW est courant, mais ce n’est pas magique).
  • Comportement de liaison des services (écouter sur 0.0.0.0 vs :: a son importance).
  • Sockets systemd qui démarrent des démons à la demande.
  • Groupes de sécurité cloud / ACL réseau / pare‑feu en périphérie qui peuvent traiter IPv6 différemment.
  • Adressage IPv6 réel (global, temporaire, adresses de confidentialité, SLAAC, RA).

Quand les équipes disent « nous avons activé UFW », elles veulent souvent dire « nous avons activé le filtrage IPv4 pour les ports dont nous nous souvenions ». Pendant ce temps, l’hôte a une adresse IPv6 globalement joignable, et votre politique IPv6 est soit manquante, permissive, ou simplement non appliquée à la table/hook correcte.

Conseil engagé : si vous exposez publiquement un hôte Ubuntu 24.04, vous devez traiter l’IPv6 comme une priorité. Soit vous le sécurisez explicitement, soit vous le désactivez explicitement avec un plan. « L’ignorer » n’est qu’une version plus lente de « se faire compromettre ».

Faits & contexte : pourquoi l’IPv6 surprend encore les équipes

Un peu d’historique aide, car beaucoup des erreurs opérationnelles d’aujourd’hui sont le résultat des choix de conception d’hier rencontrant les paramètres par défaut d’aujourd’hui.

  1. L’IPv6 est devenu standard à la fin des années 1990 (ère RFC 2460), mais son déploiement opérationnel large a pris des décennies, si bien que beaucoup d’équipes ont acquis des automatismes centrés sur l’IPv4 seulement.
  2. L’IPv6 a rétabli l’adressage de bout en bout comme modèle « normal » ; le NAT n’est pas une exigence de conception. Cela signifie que « le NAT comme frontière de sécurité » disparaît.
  3. La plupart des services Linux traitent :: comme « écouter toutes les interfaces », ce qui inclut IPv6 et souvent le comportement mapped IPv4 selon les sysctls et les valeurs par défaut des applications.
  4. Le dual‑stack n’est pas un détail de transition ; c’est l’état stable dans de nombreuses entreprises. Désactiver IPv6 casse souvent des services internes (SSO, télémétrie, miroirs de paquets) de façon inattendue.
  5. nftables a remplacé iptables comme cadre moderne de pare‑feu Linux ; les wrappers et migrations peuvent laisser des « règles existantes » qui ne correspondent pas au trafic que vous pensez filtrer.
  6. Les fournisseurs cloud assignent souvent IPv6 par défaut ou le rendent accessible via une case à cocher. Les groupes de sécurité peuvent avoir des sections IPv6 séparées que personne ne complète.
  7. L’IPv6 a plusieurs portées d’adresse (link‑local, ULA, global). Link‑local est toujours présent ; global peut apparaître automatiquement via Router Advertisements ou la configuration cloud.
  8. Des adresses IPv6 de confidentialité/temporaires existent et peuvent tourner, ce qui casse l’hypothèse « attacher cet hôte à une IP connue » pour les clients et la supervision.
  9. Certaines outils de scan et scripts de conformité restent par défaut en IPv4. Cela crée des tableaux de bord « verts » tandis que l’exposition réelle vit sur le v6.

Une citation qui devrait figurer sur tous les murs des opérations, parce qu’elle résume l’histoire du pare‑feu IPv6 en une ligne : « L’espoir n’est pas une stratégie. » — Gene Kranz

Modèle de menace en clair : comment survient la brèche

Le scénario le plus courant que je vois lors des audits ressemble à ceci :

  • UFW activé, règles ajoutées pour les ports IPv4 : 22, 80, 443, peut‑être 9100 verrouillé.
  • IPv6 activé par défaut (parce que oui), et l’hôte possède une adresse IPv6 globale.
  • Soit :
    • UFW IPv6 est désactivé, donc il n’écrit jamais de règles v6, ou
    • UFW écrit des règles v6 mais nftables ne les applique pas comme vous l’attendez (moins courant, mais réel), ou
    • Vous avez une règle v6 « tout autoriser » temporaire qui est devenue permanente.
  • Les services se lient sur :: et sont joignables en v6 même si vous n’avez testé que le v4.

Les attaquants n’ont pas besoin d’être créatifs. Ils ont besoin que vous soyez prévisible. Et « nous avons sécurisé l’IPv4 » est prévisible.

Blague #1 : L’IPv6, c’est comme une seconde porte d’entrée que vous ne saviez pas avoir—sauf qu’elle est équipée d’un panneau néon « BIENVENUE ».

Mode opératoire de diagnostic rapide (faites ceci en premier)

Quand vous suspectez « pare‑feu IPv6 oublié », vous voulez des réponses en minutes, pas un débat philosophique sur le réseau. Voici l’ordre qui trouve le goulot le plus vite.

Première étape : prouvez que l’hôte a effectivement un IPv6 joignable

  • L’hôte a‑t‑il une adresse IPv6 globale ?
  • Y a‑t‑il une route par défaut pour IPv6 ?
  • Pouvez‑vous atteindre Internet en IPv6 ?

Deuxième étape : listez ce qui écoute en IPv6

  • Identifiez les sockets liés à :: ou à une IPv6 globale.
  • Vérifiez les unités socket systemd qui peuvent créer des écouteurs même quand le « service » est arrêté.

Troisième étape : vérifiez que le filtre de paquets applique la politique IPv6

  • État UFW pour v6, et si ses règles existent.
  • Règles nftables : y a‑t‑il une chaîne de type ip6 ou inet pour input ? La politique par défaut est‑elle drop ?
  • Regardez les compteurs en générant du trafic (les paquets doivent s’incrémenter sur la règle attendue).

Quatrième étape : testez depuis l’extérieur, en dual‑stack réel

  • Scannez l’adresse IPv6 depuis un hôte externe à votre périmètre réseau.
  • Confirmez que « fermé » signifie bien filtré/bloqué, pas juste « pas de service sur IPv4 ».

Tâches pratiques : commandes, sorties attendues, et décisions (dual‑stack)

Ci‑dessous des tâches opérateur réelles. Chacune inclut la commande, ce que signifie la sortie, et la décision à prendre. Exécutez les dans l’ordre si vous diagnostiquez ; sélectionnez ce dont vous avez besoin si vous savez déjà où la pourriture se trouve.

Tâche 1 : Confirmer les adresses IPv6 et la portée

cr0x@server:~$ ip -6 addr show
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 state UNKNOWN qlen 1000
    inet6 ::1/128 scope host 
       valid_lft forever preferred_lft forever
2: enp1s0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 state UP qlen 1000
    inet6 fe80::5054:ff:fe12:3456/64 scope link 
       valid_lft forever preferred_lft forever
    inet6 2001:db8:1234:5678:5054:ff:fe12:3456/64 scope global dynamic 
       valid_lft 86395sec preferred_lft 14395sec

Signe : Si vous voyez une adresse scope global, vous êtes joignable en IPv6 si le routage le permet. Link‑local (fe80::) n’implique pas à lui seul une exposition Internet.

Décision : Si global existe et que ce n’est pas voulu, soit (a) verrouillez les règles pare‑feu IPv6 maintenant, soit (b) désactivez IPv6 correctement (section plus bas) après analyse d’impact.

Tâche 2 : Vérifier le routage IPv6 et la route par défaut

cr0x@server:~$ ip -6 route show
2001:db8:1234:5678::/64 dev enp1s0 proto ra metric 100 pref medium
fe80::/64 dev enp1s0 proto kernel metric 256 pref medium
default via fe80::1 dev enp1s0 proto ra metric 100 pref medium

Signe : Une route default via signifie que l’hôte peut envoyer du trafic IPv6 vers l’extérieur. S’il n’y a pas de route par défaut, le trafic entrant peut encore fonctionner dans certains environnements, mais en général pas depuis Internet.

Décision : Route par défaut présente → considérez l’exposition comme réelle et immédiate.

Tâche 3 : Vérifier la connectivité IPv6

cr0x@server:~$ ping -6 -c 2 ipv6.google.com
PING ipv6.google.com(2607:f8b0:4005:80a::200e) 56 data bytes
64 bytes from 2607:f8b0:4005:80a::200e: icmp_seq=1 ttl=117 time=12.3 ms
64 bytes from 2607:f8b0:4005:80a::200e: icmp_seq=2 ttl=117 time=12.1 ms

--- ipv6.google.com ping statistics ---
2 packets transmitted, 2 received, 0% packet loss, time 1002ms

Signe : L’IPv6 sortant fonctionne. Dans beaucoup de réseaux réels, si l’IPv6 sortant fonctionne, l’entrée n’est souvent qu’à une mauvaise configuration de pare‑feu près.

Décision : Passez aux audits des écouteurs et du pare‑feu ; ne supposez pas que l’amont vous bloque.

Tâche 4 : Lister les sockets à l’écoute avec visibilité IPv6

cr0x@server:~$ sudo ss -lntup
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:*       users:(("sshd",pid=1123,fd=3))
tcp   LISTEN 0      4096   [::]:22              [::]:*          users:(("sshd",pid=1123,fd=4))
tcp   LISTEN 0      4096   [::]:9100            [::]:*          users:(("node_exporter",pid=1337,fd=3))
tcp   LISTEN 0      4096   127.0.0.1:8080       0.0.0.0:*       users:(("grafana",pid=1450,fd=9))
tcp   LISTEN 0      4096   [::]:80              [::]:*          users:(("nginx",pid=1200,fd=6))

Signe : Tout écouteur [::]:PORT est joignable en IPv6 (sous réserve du pare‑feu). Notez que 127.0.0.1:8080 est accessible uniquement en loopback et n’est pas exposé.

Décision : Pour chaque écouteur [::], décidez : doit‑il être public, privé ou local seulement ? Si ce n’est pas censé être public, corrigez la liaison et le pare‑feu.

Tâche 5 : Vérifier le paramètre IPv6 d’UFW

cr0x@server:~$ sudo grep -n '^IPV6=' /etc/default/ufw
7:IPV6=yes

Signe : Si IPV6=no, UFW ne gérera pas les règles v6. Si c’est yes, UFW générera des jeux de règles v4 et v6.

Décision : Si c’est no et que vous avez besoin d’IPv6 : passez à yes, puis rechargez UFW et validez. Si vous voulez désactiver IPv6 entièrement, ne vous contentez pas de changer UFW ; gérez les sysctls/netplan et les liaisons d’applications.

Tâche 6 : Inspecter l’état UFW avec verbosité

cr0x@server:~$ sudo ufw status verbose
Status: active
Logging: on (low)
Default: deny (incoming), allow (outgoing), disabled (routed)
New profiles: skip

To                         Action      From
--                         ------      ----
22/tcp                     ALLOW IN    203.0.113.0/24
80/tcp                     ALLOW IN    Anywhere
443/tcp                    ALLOW IN    Anywhere

22/tcp (v6)                ALLOW IN    2001:db8:feed::/48
80/tcp (v6)                ALLOW IN    Anywhere (v6)
443/tcp (v6)               ALLOW IN    Anywhere (v6)

Signe : La présence de règles « (v6) » est bonne ; cela signifie qu’UFW émet au moins une politique IPv6. Mais « Anywhere (v6) » est un choix réel, pas un défaut à accepter aveuglément.

Décision : Si vous n’aviez pas l’intention d’exposer publiquement 80/443/22 en IPv6, resserrez les règles maintenant. Si UFW n’affiche aucune entrée v6, considérez‑le comme une alerte critique.

Tâche 7 : Vérifier que les règles nftables couvrent IPv6

cr0x@server:~$ sudo nft list ruleset
table inet ufw {
	chain input {
		type filter hook input priority filter; policy drop;
		iif "lo" accept
		ct state established,related accept
		ip protocol icmp accept
		ip6 nexthdr ipv6-icmp accept
		tcp dport 22 ip saddr 203.0.113.0/24 accept
		tcp dport 22 ip6 saddr 2001:db8:feed::/48 accept
		tcp dport { 80, 443 } accept
		counter packets 12345 bytes 987654
		reject with icmpx type admin-prohibited
	}
	chain forward {
		type filter hook forward priority filter; policy drop;
	}
	chain output {
		type filter hook output priority filter; policy accept;
	}
}

Signe : Une table inet unique avec des correspondances ip et ip6 est un bon modèle. Notez la policy drop par défaut sur input. Notez aussi les autorisations explicites ICMP/ICMPv6.

Décision : Si vous ne voyez que table ip et rien pour IPv6, vous filtrez probablement l’IPv4 seulement. Corrigez en activant IPv6 dans UFW ou en écrivant des règles nftables explicites pour ip6 / inet.

Tâche 8 : Vérifier les compteurs nftables en générant du trafic IPv6

cr0x@server:~$ sudo nft -a list chain inet ufw input
table inet ufw {
	chain input {
		type filter hook input priority filter; policy drop;
		iif "lo" accept
		ct state established,related accept
		ip6 nexthdr ipv6-icmp accept
		tcp dport 22 ip6 saddr 2001:db8:feed::/48 accept # handle 14
		tcp dport { 80, 443 } accept # handle 15
		reject with icmpx type admin-prohibited # handle 16
	}
}

Signe : Le # handle vous permet de surveiller les compteurs si vous ajoutez des déclarations counter ou si votre chaîne en contient déjà. Si vous ne voyez pas de compteurs s’incrémenter lors d’un test entrant, vous regardez peut‑être le mauvais jeu de règles ou le trafic contourne (rare, mais possible avec routage de politique ou autres hooks).

Décision : Si les compteurs ne bougent pas pendant une tentative connue, confirmez quel backend pare‑feu est actif et si un autre système gère nftables.

Tâche 9 : Confirmer quel backend UFW utilise

cr0x@server:~$ sudo ufw version
ufw 0.36.2
Copyright 2008-2023 Canonical Ltd.

Backend: nf_tables

Signe : Si c’est Backend: nf_tables, UFW génère des règles nftables. Si vous voyez iptables legacy en jeu, vous pouvez avoir un filtrage en split‑brain.

Décision : Standardisez : choisissez nf_tables et supprimez/arrêtez les scripts legacy qui appellent encore iptables directement.

Tâche 10 : Détecter des règles iptables legacy qui donnent une fausse assurance

cr0x@server:~$ sudo iptables -S
-P INPUT ACCEPT
-P FORWARD ACCEPT
-P OUTPUT ACCEPT

Signe : Si les politiques legacy iptables sont ACCEPT alors que vous pensez « refuser par défaut », ce n’est pas nécessairement une erreur — car nftables peut faire le filtrage réel. Mais c’est un indice que vous êtes à une erreur de migration d’un incident.

Décision : Si vous utilisez nftables, ne vous fiez pas à l’output iptables pour l’assurance. Si quelque chose installe toujours des règles iptables, migrez‑le ou supprimez‑le.

Tâche 11 : Vérifier les sysctls IPv6 qui affectent la liaison et l’acceptation

cr0x@server:~$ sysctl net.ipv6.conf.all.disable_ipv6 net.ipv6.conf.default.disable_ipv6 net.ipv6.bindv6only
net.ipv6.conf.all.disable_ipv6 = 0
net.ipv6.conf.default.disable_ipv6 = 0
net.ipv6.bindv6only = 0

Signe : IPv6 est activé. net.ipv6.bindv6only=0 signifie que les sockets IPv6 peuvent accepter du trafic IPv4‑mappé dans certains cas ; cela varie selon l’application et les options de socket.

Décision : Ne « corrigez » pas l’exposition en basculant les sysctls à la légère sans avoir testé le comportement des applications. Préférez corrections de pare‑feu et de liaison.

Tâche 12 : Identifier les services qui se lient à toutes les interfaces et ne devraient pas

cr0x@server:~$ systemctl status node_exporter.service --no-pager
● node_exporter.service - Prometheus Node Exporter
     Loaded: loaded (/lib/systemd/system/node_exporter.service; enabled; preset: enabled)
     Active: active (running) since Mon 2025-12-30 10:18:42 UTC; 2h 11min ago
   Main PID: 1337 (node_exporter)
      Tasks: 4 (limit: 9382)
     Memory: 9.8M
        CPU: 2.1s
     CGroup: /system.slice/node_exporter.service
             └─1337 /usr/bin/node_exporter --web.listen-address=:9100

Signe : --web.listen-address=:9100 signifie « lier sur tout », ce qui inclut IPv6 sur beaucoup de systèmes. Ce n’est souvent pas ce que vous souhaitez sur un hôte exposé publiquement.

Décision : Liez les exporters à une IP de VLAN de gestion, à localhost avec un reverse proxy, ou pare‑feuez‑les vers vos scrapers — sur IPv4 et IPv6.

Tâche 13 : Confirmer que l’activation socket systemd ne crée pas d’écouteurs surprises

cr0x@server:~$ systemctl list-sockets --all --no-pager
LISTEN                         UNIT                     ACTIVATES
[::]:22                        ssh.socket               ssh.service
127.0.0.53%lo:53               systemd-resolved.socket   systemd-resolved.service
/var/run/dbus/system_bus_socket dbus.socket              dbus.service

Signe : Si vous voyez une unité socket à l’écoute sur [::], le noyau accepte des connexions même si le service semble arrêté ; systemd le lancera à la demande.

Décision : Si vous vouliez fermer un port, désactivez l’unité socket, pas seulement le service.

Tâche 14 : Scan IPv6 externe depuis un autre hôte (vérif opérateur)

cr0x@server:~$ nmap -6 -Pn -p 22,80,443,9100 2001:db8:1234:5678:5054:ff:fe12:3456
Starting Nmap 7.94 ( https://nmap.org ) at 2025-12-30 12:35 UTC
Nmap scan report for 2001:db8:1234:5678:5054:ff:fe12:3456
Host is up (0.021s latency).

PORT     STATE    SERVICE
22/tcp   open     ssh
80/tcp   open     http
443/tcp  open     https
9100/tcp filtered jetdirect

Nmap done: 1 IP address (1 host up) scanned in 3.11 seconds

Signe : open signifie joignable et répondant. filtered signifie qu’un pare‑feu bloque (bien, si c’est voulu). Si vous attendiez que le port 22 soit restreint et qu’il apparaît ouvert, c’est tout le problème.

Décision : Considérez les résultats de scan externes comme vérité. Alignez maintenant règles pare‑feu et liaisons de services jusqu’à ce que le scan reflète votre exposition prévue.

Tâche 15 : Vérification rapide des processus à l’écoute et des paquets propriétaires

cr0x@server:~$ sudo lsof -nP -iTCP -sTCP:LISTEN | head
COMMAND     PID USER   FD   TYPE DEVICE SIZE/OFF NODE NAME
sshd       1123 root    3u  IPv4  32249      0t0  TCP *:22 (LISTEN)
sshd       1123 root    4u  IPv6  32251      0t0  TCP *:22 (LISTEN)
nginx      1200 root    6u  IPv6  32999      0t0  TCP *:80 (LISTEN)
node_expo  1337 node    3u  IPv6  33301      0t0  TCP *:9100 (LISTEN)

Signe : lsof vous donne le nom du processus et le PID ; plus besoin de deviner quel service écoute sur quel port.

Décision : Si un écouteur est inconnu, ne vous contentez pas de le pare‑feuer. Identifiez‑le, supprimez‑le ou isolez‑le — les démons mystérieux expliquent comment un « débogage temporaire » devient « incident permanent ».

UFW, nftables et la réalité d’Ubuntu 24.04

Ubuntu 24.04 vit dans le monde nftables. C’est bien. nftables est plus cohérent, prend en charge la famille inet (jeu de règles unique pour v4+v6), et c’est ce que vous voulez pour les hôtes modernes.

UFW reste acceptable — si vous le traitez comme un compilateur de politique et validez la sortie. Là où les gens se trompent, c’est en supposant que l’affichage d’état d’UFW équivaut à l’application. En général c’est vrai, mais « en général » n’est pas un SLO.

Rendez la politique IPv6 explicite (même si vous n’autorisez rien)

Si vous utilisez UFW, ne laissez pas IPv6 en tant que valeur implicite. En pratique, vous voulez trois choses :

  • IPV6=yes dans /etc/default/ufw afin qu’UFW émette les règles v6.
  • Refuser par défaut les entrantes pour les deux piles.
  • Règles d’autorisation explicites pour les ports et sources voulus sur les deux piles.

Privilégiez les règles « allow from » plutôt que les autorisations globales

Sur IPv6, la tentation est d’autoriser largement parce que « c’est compliqué ». Ce n’est pas compliqué ; c’est juste peu familier.

Si SSH est pour les administrateurs, SSH est pour les réseaux d’administration. Cela s’applique aussi à IPv6. Si vous n’avez pas de plages IPv6 admin stables, résolvez‑le avec un VPN/bastion, pas en ouvrant SSH au monde.

ICMPv6 n’est pas une plomberie optionnelle

Les gens adorent bloquer ICMP. Ils entendent « ping » et pensent « reconnaissance ». Avec IPv6, bloquer ICMPv6 casse des mécanismes de protocole réels : découverte de PMTU, Neighbor Discovery, Router Advertisements dans certains environnements. Votre posture « furtive » devient des « pannes aléatoires ».

Blague #2 : Bloquer ICMPv6 pour « être en sécurité » revient à couper vos freins pour éviter d’excéder la vitesse.

Quand écrire nftables directement

Si vous avez un environnement complexe — containers, multiples interfaces, routage de politique, segmentation stricte — vous pouvez dépasser UFW. Ce n’est pas un échec moral. C’est de la maturité.

Mais si vous écrivez nftables directement, gérez tout le cycle de vie : déploiement des règles, chargement atomique, sauvegardes et contrôles CI. « Éditer les règles pare‑feu en production à 2h du matin » est une tradition qu’il faut rompre.

Sockets systemd : le mensonge « le service n’est pas en cours »

Sur Ubuntu, systemd peut écouter un port pour le compte d’un service et ne lancer ce service que lorsqu’une connexion arrive. C’est l’activation par socket. C’est efficace. C’est aussi source de confusion lors d’audits de sécurité.

Mode d’échec : quelqu’un arrête ssh.service et pense que SSH est désactivé. Mais ssh.socket écoute toujours. Le port reste joignable. Le scanner le constate.

Règle opérationnelle : si un port est ouvert, il est ouvert. « Mais le service était arrêté » n’est pas une défense, c’est l’aveu que vous n’avez pas vérifié le niveau sockets.

Utilisez systemctl list-sockets, identifiez les écouteurs sur [::], et désactivez‑les si le port ne doit pas exister.

Cloud et filtrage en amont : ne délocalisez pas votre réflexion

En entreprise, l’exposition IPv6 provient souvent d’un contrôle en amont en split‑brain :

  • Le groupe de sécurité a des règles IPv4 correctement configurées.
  • Les règles IPv6 sont vides (ce qui signifie parfois « tout autoriser » selon la plateforme ou les politiques), ou sont définies par une autre équipe, ou tout simplement oubliées.
  • Le pare‑feu hôte suppose que l’amont bloque ; l’amont suppose que le pare‑feu hôte bloque.

La seule stratégie stable est la défense en profondeur avec des contrôles v6 explicites à chaque couche. Le pare‑feu hôte doit être correct même si l’amont est erroné, parce que l’amont finira par être erroné.

De plus : si vous utilisez des load balancers managés, vérifiez comment ils gèrent la terminaison IPv6 et la connectivité vers les backends. Vous pouvez avoir un hôte parfaitement durci et néanmoins exposer un service admin via un écouteur IPv6 sur la mauvaise interface si votre réseau interne est dual‑stack.

Trois mini‑histoires d’entreprise (anonymisées, douloureusement plausibles)

1) Incident causé par une fausse hypothèse : « Nous n’utilisons pas IPv6 ici »

L’entreprise exploitait une flotte de VMs Ubuntu derrière un pare‑feu en périphérie. Tout était « IPv4 uniquement » selon le schéma réseau. La posture de sécurité était bâtie autour de cela : les règles UFW étaient centrées sur IPv4, et les scans de conformité vérifiaient seulement les enregistrements A.

Lors d’un pentest de routine, le testeur a demandé les plages IPv6. La réponse a été un haussement d’épaules. « Nous n’utilisons pas IPv6. » Le testeur n’avait pas besoin des plages ; il avait besoin d’un nom d’hôte renvoyant des enregistrements AAAA.

Il s’est avéré que le VPC cloud avait activé IPv6 des mois plus tôt pour un projet séparé. Certains sous‑réseaux attribuaient automatiquement des adresses IPv6. Personne n’avait informé l’équipe ops parce que le changement « n’affectait pas la production ». Ça ne l’a pas fait — jusqu’à ce que quelqu’un regarde.

Les constats étaient banals et brutaux : SSH ouvert au monde en IPv6, un panneau d’administration de staging lié à ::, et un endpoint de métriques sans authentification. Rien n’a été exploité ; il n’y avait pas besoin. Le rapport suffisait.

La correction n’a rien d’héroïque. Ils ont activé UFW IPv6, répliqué les allowlists, resserré les liaisons de services, et ajouté des scans dual‑stack dans le CI. La partie difficile fut culturelle : admettre que « nous n’utilisons pas IPv6 » n’était jamais un fait — juste une croyance non testée.

2) Optimisation qui a mal tourné : « Simplifions les règles pare‑feu »

Une équipe plateforme voulait moins de complexité. Lassés d’UFW comme « encore une abstraction », ils ont migré vers un jeu minimal nftables. Une table, une chaîne, accept par défaut. Ils compteraient sur les groupes de sécurité en amont. Propre. Élégant. Rapide.

Puis ils ont eu un incident de production : des échecs de connectivité sporadiques pour un sous‑ensemble de clients utilisant IPv6. L’ingénieur d’astreinte a supposé un problème de load balancer. Ce n’était pas ça. Le pare‑feu autorisait l’entrée, mais le trafic de retour était impacté par une modification de routage de politique, et ICMPv6 nécessaire à la découverte PMTU était bloqué en amont.

L’« optimisation » avait supprimé la journalisation locale et l’habitude de regarder les compteurs. L’équipe n’avait plus de moyen rapide de prouver ce que faisait l’hôte. Ils ont dû déboguer à l’aveugle, par captures de paquets, sous pression.

Ils ont finalement restauré un pare‑feu hôte plus strict : drop par défaut inbound, autorisations explicites, gestion explicite d’ICMPv6, et journalisation à un débit raisonnable. La leçon ironique : moins de règles n’a pas signifié moins de complexité. Ça l’a juste déplacée vers un endroit avec moins de visibilité.

3) Pratique ennuyeuse mais correcte qui a sauvé la situation : « Nous scannons les deux piles, tout le temps »

Une autre organisation avait une habitude ennuyeuse : chaque pipeline de build lançait un scan externe contre l’hôte candidat, en IPv4 et IPv6, depuis un runner extérieur au VPC de production. Ce n’était pas sophistiqué. C’était cohérent.

Un jour, une mise à jour d’image de base a changé l’adresse d’écoute par défaut d’un service de 127.0.0.1 à ::. Le service devait être interne uniquement, scrappé via un sidecar proxy. En IPv4, tout paraissait encore correct à cause du routage interne. En IPv6, il est devenu subitement joignable depuis des endroits où il n’aurait pas dû l’être.

Le scan dual‑stack a fait échouer la build. Le ticket n’a jamais atteint la production. Personne n’a eu à rédiger un rapport d’incident ni à expliquer à la direction pourquoi « interne seulement » était sur l’internet public.

C’est la valeur des pratiques ennuyeuses : elles n’empêchent pas toutes les erreurs, mais elles rendent les erreurs peu coûteuses. Vous voulez des erreurs peu coûteuses.

Erreurs courantes : symptômes → cause racine → correctif

1) Symptom : « Les ports IPv4 sont fermés, mais le scan IPv6 les montre ouverts »

Cause racine : Règles IPv6 manquantes ou permissives (UFW IPv6 désactivé, ou nftables sans couverture ip6/inet).

Fix : Activez IPv6 dans UFW (IPV6=yes), rechargez, et vérifiez que nftables a table inet ou des chaînes ip6 explicites avec drop par défaut. Rescannez en externe en IPv6.

2) Symptom : « UFW est actif mais IPv6 reste joignable »

Cause racine : Outils pare‑feu en split‑brain ; UFW gère nftables mais un autre outil charge un jeu permissif après, ou vous regardez iptables alors que nftables applique.

Fix : Inspectez nft list ruleset. Assurez‑vous que vos règles se chargent au boot et que rien ne les écrase. Standardisez sur un seul gestionnaire.

3) Symptom : « J’ai arrêté le service, mais le port est toujours ouvert »

Cause racine : Activation socket systemd ; l’unité socket écoute toujours.

Fix : Désactivez l’unité .socket : systemctl disable --now name.socket. Vérifiez avec ss et un scan externe.

4) Symptom : « Après avoir resserré le pare‑feu IPv6, des connexions aléatoires plantent »

Cause racine : ICMPv6 bloqué trop agressivement, cassant PMTU ou Neighbor Discovery.

Fix : Autorisez les types ICMPv6 essentiels. Si vous utilisez UFW, assurez‑vous qu’il permet IPv6‑ICMP. Si vous écrivez nftables, acceptez explicitement ip6 nexthdr ipv6-icmp et affinez plus tard.

5) Symptom : « Le service est lié à 0.0.0.0, pourquoi est‑il sur IPv6 ? »

Cause racine : Le service se lie séparément à IPv6 :: ou utilise un socket dual‑stack selon l’exécution et les sysctls.

Fix : Confirmez avec ss -lntup. Définissez des adresses d’écoute explicites dans la config du service (v4 et v6 selon besoin), ou liez‑le à une interface/IP spécifique.

6) Symptom : « Le scan de conformité est vert, mais un chercheur externe nous a contactés pour exposition IPv6 »

Cause racine : Les outils de scan n’ont testé que l’IPv4 (ou seulement les enregistrements DNS A).

Fix : Ajoutez la découverte d’actifs AAAA et le scan IPv6 au contrôle. Traitez le dual‑stack comme baseline.

7) Symptom : « Nous avons désactivé IPv6, et maintenant apt ou des services internes cassent »

Cause racine : Votre environnement utilise IPv6 pour certains chemins (miroirs, proxies, SSO, découverte de services). Désactiver IPv6 n’est pas toujours « sans danger ».

Fix : Préférez le pare‑feu plutôt que la désactivation. Si vous devez désactiver, testez en staging avec la même configuration DNS et proxy.

Checklists / plan étape par étape

Checklist A : Réponse d’urgence (vous avez trouvé une exposition IPv6 aujourd’hui)

  1. Identifiez l(es) adresse(s) IPv6 exposée(s) : ip -6 addr. Déterminez lesquelles sont globales.
  2. Listez les écouteurs : ss -lntup. Notez les [::]:PORT.
  3. Bloquez l’entrée IPv6 au pare‑feu hôte immédiatement : si vous n’êtes pas sûr, refusez par défaut l’inbound et n’autorisez que SSH depuis vos plages admin.
  4. Confirmez l’application : nft list ruleset et scan externe avec nmap -6.
  5. Corrigez les liaisons : reconfigurez les services pour n’écouter que sur les interfaces prévues.
  6. Laissez la journalisation activée (modérée) : suffisante pour voir si vous bloquez du trafic légitime.

Checklist B : Durcissement correct (assurez‑vous que ça reste après reboot et mises à jour)

  1. Choisissez un gestionnaire de pare‑feu : UFW sur nftables, ou nftables directement. Ne laissez pas deux « propriétaires ».
  2. Rendez les règles dual‑stack symétriques : chaque autorisation inbound doit exister pour IPv4 et IPv6 sauf divergence intentionnelle (rare).
  3. Gardez ICMPv6 fonctionnel : autorisez‑le de façon appropriée.
  4. Auditez les sockets systemd : systemctl list-sockets ; désactivez les écouteurs inattendus.
  5. Ajoutez un scan dual‑stack à votre pipeline : point de vue externe, stockez les résultats, échouez les builds sur ouvertures inattendues.
  6. Documentez l’exposition prévue : port, protocole, plages sources et justification. Traitez‑la comme un contrat d’API.

Checklist C : Si vous insistez pour désactiver IPv6 (faites‑le comme un adulte)

  1. Inventoriez les dépendances : usage DNS AAAA, services internes, proxies, monitoring. Ne devinez pas.
  2. Désactivez via sysctl avec persistance : définissez net.ipv6.conf.all.disable_ipv6=1 et default dans /etc/sysctl.d/, puis rebootez et testez.
  3. Vérifiez que c’est réellement désactivé : ip -6 addr ne doit montrer que ::1 ou aucune adresse sur les interfaces.
  4. Revérifiez les services : certaines applications se comportent différemment quand IPv6 disparaît ; testez les health checks et la connectivité des clients.

Mon biais : le pare‑feu est généralement plus sûr que la désactivation. Désactiver IPv6 est un gros marteau qui finit souvent par se cogner les pouces.

FAQ

1) Pourquoi mon serveur a‑t‑il IPv6 du tout ? Je ne l’ai jamais configuré.

Parce que les réseaux modernes le fournissent souvent automatiquement (paramètres cloud, Router Advertisements, DHCPv6). Ubuntu l’utilisera volontiers quand il est disponible.

2) Si je ne publie pas d’enregistrements AAAA, suis‑je en sécurité ?

Non. Les attaquants peuvent découvrir des adresses IPv6 via de nombreux chemins : logs, certificats, découverte de voisins sur des réseaux internes, métadonnées cloud, ou simplement en scannant des préfixes connus dans certains environnements.

3) UFW bloque‑t‑il IPv6 par défaut ?

Seulement si le support IPv6 est activé dans UFW et que des règles sont générées pour v6. Vérifiez /etc/default/ufw et ufw status verbose pour des règles « (v6) ».

4) Dois‑je répliquer exactement mes règles IPv4 pour IPv6 ?

Presque toujours, oui. La divergence est un choix d’architecture conscient. Si vous ne pouvez pas expliquer pourquoi IPv6 est plus ouvert que l’IPv4, c’est un accident.

5) Pourquoi certains ports apparaissent « filtered » sur des scans IPv6 ?

Cela indique généralement que le pare‑feu laisse tomber les paquets (bon pour « bloqué »). Cela peut aussi signifier un filtrage en amont. Validez en regardant les compteurs et logs du pare‑feu hôte.

6) Puis‑je simplement mettre IPV6=no dans UFW pour corriger l’exposition ?

Cela aggrave généralement la situation : vous demandez à UFW de cesser de gérer l’IPv6, pas de désactiver le réseau IPv6. Vous aurez toujours des adresses IPv6 et des écouteurs ; vous aurez juste moins de protections.

7) Quelle est la posture IPv6 la plus simple et sûre pour un serveur web public ?

Refuser par défaut inbound. Autoriser 80/443 depuis n’importe où sur les deux piles. Autoriser SSH seulement depuis des plages admin ou via VPN/bastion. Autoriser ICMPv6 essentiel.

8) Je suis derrière un load balancer cloud. Ai‑je quand même besoin d’un pare‑feu hôte ?

Oui. Les load balancers se malconfigurent, et des chemins internes peuvent les contourner. Les pare‑feu hôtes sont une assurance peu coûteuse et attrapent les erreurs de liaison à ::.

9) Comment savoir si une appli écoute en IPv6 ?

Utilisez ss -lntup et cherchez [::]:PORT ou une adresse IPv6 spécifique. Ne vous fiez pas à la documentation d’application ; faites confiance à la liste des sockets.

10) Bloquer ICMPv6 est‑il acceptable ?

Pas en politique globale. Vous pouvez restreindre certains types plus tard avec précaution, mais vous devez préserver les fonctionnalités de base sinon vous créerez des pannes qui se présentent comme « instabilités réseau aléatoires ».

Prochaines étapes que vous pouvez réellement exécuter

Faites trois choses cette semaine, et vous éliminerez la plupart des incidents « pare‑feu IPv6 oublié » :

  1. Auditez les écouteurs avec ss -lntup et tuez ou reconfigurez tout ce qui ne doit pas être public sur [::].
  2. Rendez la politique pare‑feu dual‑stack : confirmez qu’UFW IPv6 est activé (ou écrivez des règles nftables en inet), et assurez‑vous d’un drop inbound par défaut pour IPv4 et IPv6.
  3. Validez depuis l’extérieur avec un scan IPv6 réel et stockez le résultat. Si vous ne testez pas en externe, vous ne le savez pas.

Ubuntu 24.04 n’essaie pas de vous tromper. Il fait simplement ce que font les systèmes modernes : fournir IPv6 prêt à l’usage. Votre travail est de faire en sorte que « prêt » signifie « sécurisé », pas « étonnamment joignable ».

← Précédent
MySQL vs TiDB : compatibilité MySQL vs complexité opérationnelle — à quoi vous vous engagez
Suivant →
Proxmox « qemu-img: Could not create » : permissions, chemins et correctifs de système de fichiers qui fonctionnent réellement

Laisser un commentaire