Vous établissez un tunnel WireGuard. Le handshake a l’air sain. Quelques octets s’incrémentent. Et pourtant, le trafic que vous vouliez voir passer par le VPN
sort toujours par la mauvaise interface, ou pire : disparaît dans un vide silencieux où les pings prennent leur retraite.
Neuf fois sur dix, la cause n’est ni la cryptographie, ni le MTU, ni « internet est en panne ». C’est une mauvaise compréhension de
AllowedIPs : ce que cela signifie, qui l’utilise et comment cela se transforme en routes effectives sur un système d’exploitation réel.
Le modèle mental : AllowedIPs est une politique de routage, pas une ACL
Si vous devez retenir une chose : AllowedIPs est un paramètre d’entrée pour la décision de routage.
Ce n’est pas une règle de pare-feu. Ce n’est pas « qui est autorisé à se connecter ».
Ce n’est pas non plus « quelles adresses IP existent de l’autre côté ».
Dans WireGuard, chaque pair a une liste de AllowedIPs. Cette liste remplit deux rôles :
-
Sélection du pair en sortie. Lorsque l’hôte local veut envoyer un paquet vers une adresse de destination,
WireGuard choisit le pair dont lesAllowedIPscontiennent cette destination. C’est essentiellement
« quel pair doit transporter ce paquet ». -
Validation de source en entrée. Quand un paquet arrive d’un pair, WireGuard vérifie si l’
adresse source du paquet est incluse dans lesAllowedIPsde ce pair. Sinon, WireGuard le rejette.
C’est tout. Cela ne programme pas magiquement tout votre réseau, sauf si quelque chose d’autre (généralement wg-quick)
traduit ces préfixes en routes du noyau. Et même dans ce cas, ce ne sont toujours que des routes.
Voici le mode d’échec qui garde les SRE en poste : les gens supposent que AllowedIPs sont des « sous-réseaux distants ».
Parfois oui. Parfois c’est « sous-réseaux distants plus la route par défaut parce que je veux un tunnel complet ».
Et parfois c’est « l’IP du pair lui-même ». Mais aucune de ces options n’est universelle. Ce sont des intentions,
et les intentions exigent un routage correspondant, du forwarding, du NAT et un comportement DNS cohérent.
Un autre détail clé : WireGuard ne parle pas « routes » directement. Il parle « pairs et préfixes autorisés ».
Le noyau de l’OS parle routes. wg-quick est le traducteur et, parfois, le singe du chaos.
Blague n°1 : AllowedIPs s’appelle « Allowed » parce que « PleaseStopSendingMyPacketsIntoTheWrongTunnelIPs »
ne rentrait pas dans un fichier de configuration.
Faits intéressants et contexte historique
Un peu de contexte rend l’étrangeté moins personnelle.
- WireGuard est entré dans le noyau Linux en 2020 (Linux 5.6). Avant cela, il vivait hors-arbre, ce qui a façonné ses interfaces minimalistes.
- WireGuard évite volontairement les « changements de mode » comme beaucoup de VPN traditionnels (modes transport vs tunnel). Il est toujours L3 : vous routez des paquets IP.
wg(l’outil) n’ajoute pas de routes. C’était une séparation délibérée : le pilote VPN connaît les pairs ; l’OS connaît le routage.wg-quickest un wrapper de commodité qui utilise des outils standards (ip,resolvconf/systemd-resolved,iptables/nft) pour créer une « expérience VPN ».- AllowedIPs ressemble à une table de routage compressée : c’est essentiellement l’équivalent par pair de « ces préfixes vont par ici », plus une vérification anti-usurpation.
- WireGuard utilise un concept de « cryptokey routing » : au lieu de sélectionner un tunnel par interface, il sélectionne un pair par clé publique et par correspondance de préfixe de destination.
- Linux supporte plusieurs tables de routage et règles (policy routing).
wg-quickles utilise pour les configurations full-tunnel afin d’éviter de perturber la table principale. - Les préfixes qui se chevauchent sont légaux dans la configuration WireGuard, mais les règles de sélection (longest prefix match) peuvent vous surprendre dans des déploiements multi-pairs.
- L’IPv6 échoue souvent en premier parce que les gens configurent soigneusement AllowedIPs pour IPv4 et oublient les valeurs par défaut IPv6 ou les réponses DNS AAAA. Le tunnel fonctionne ; le navigateur non.
Comment les paquets circulent réellement : routes du noyau, WireGuard et wg-quick
Les trois couches de routage dont vous dépendez (que ça vous plaise ou non)
Quand vous lancez WireGuard sur Linux, il y a trois points de décision pertinents :
- Routage Linux : choisit une interface de sortie et un prochain saut pour une IP de destination en utilisant les tables de routes et les règles de policy routing.
-
Sélection du pair WireGuard : à l’intérieur de l’interface WireGuard, il choisit quel pair doit porter le paquet en se basant sur la correspondance de destination avec les
AllowedIPs. - Routage/forwarding côté distant : l’extrémité distante doit savoir quoi faire ensuite du paquet (livrer localement, transférer, NAT, etc.).
Si l’une de ces trois couches n’est pas d’accord, vous obtenez l’expérience classique « handshake mais pas de trafic ».
Le handshake prouve seulement que l’UDP peut atteindre le pair et que les clés sont valides. Il ne dit rien sur
le chemin de retour, le NAT ou le forwarding.
Ce que fait réellement wg-quick (et pourquoi vous devriez lire sa sortie)
wg-quick up wg0 est pratique. Il est aussi partial :
- Il crée l’interface (
ip link add wg0 type wireguard). - Il assigne des adresses d’interface depuis
Address =. - Il configure les pairs WireGuard et leurs
AllowedIPs. - Il ajoute des routes pour chaque préfixe AllowedIPs (sauf si le policy routing est utilisé).
- Pour le full-tunnel (0.0.0.0/0 ou ::/0), il ajoute souvent des règles de policy routing et une table séparée.
- Il peut configurer le DNS (selon
DNS =et votre pile de résolution). - Il peut ajouter des règles de pare-feu si vous utilisez
PostUp/PostDownou des intégrations distro.
La partie critique : ces routes ne sont pas des « routes WireGuard ». Ce sont des routes du noyau.
Si vous modifiez ensuite AllowedIPs et ne relancez pas wg-quick (ou n’ajustez pas les routes manuellement),
la table de routage du noyau peut ne plus correspondre à votre intention. Ce décalage est subtil et fréquent.
Le schéma « route par défaut via WireGuard »
Mettre AllowedIPs = 0.0.0.0/0, ::/0 pour un pair dit :
pour toute IP de destination, choisissez ce pair. Mais cela ne signifie pas nécessairement que le noyau enverra
chaque paquet sur l’interface wg0. Ça dépend des règles de routage.
Sur Linux, wg-quick implémente généralement le full-tunnel comme suit :
- Ajouter une route par défaut dans une table de routage séparée (souvent la table 51820).
- Ajouter des entrées
ip ruleafin que le trafic originaire de l’adresse IP de l’interface WireGuard
(ou les paquets marqués) utilise cette table. - Ajouter des exceptions pour que l’IP endpoint du pair sorte toujours via la liaison réelle, pas à travers le tunnel
(pour éviter d’emmener le tunnel dans le tunnel).
Cette exception est la raison pour laquelle « mon VPN s’est levé et s’est immédiatement tué » arrive parfois : si l’exception pour l’endpoint
est incorrecte (à cause de changements DNS, de confusion multi‑pile ou si vous êtes derrière un CGNAT et que l’endpoint varie),
vos paquets UDP vers l’endpoint sont routés dans le tunnel. Le tunnel ne peut alors plus atteindre l’endpoint.
C’est de l’auto-sabotage, avec une logique parfaite.
Réseau de diagnostic rapide
Vous voulez de la vitesse. Vous voulez aussi éviter le piège classique de changer cinq choses à la fois puis
ne pas savoir laquelle a réglé le problème.
Premièrement : établissez si les paquets entrent et sortent de l’interface WireGuard
- Vérifiez le handshake et les compteurs de transfert.
- Vérifiez la décision de routage du noyau pour la destination avec
ip route get(IPv4 et IPv6). - Capturez sur
wg0et sur l’interface physique pour voir où les paquets vont réellement.
Deuxièmement : confirmez que la logique de sélection du pair correspond à l’intention d’AllowedIPs
- Listez les pairs et leurs AllowedIPs.
- Cherchez des chevauchements (par ex., deux pairs revendiquent 10.0.0.0/8).
- Validez que les adresses source des paquets entrants sont incluses dans les AllowedIPs de l’émetteur (rejet anti-usurpation).
Troisièmement : validez le forwarding/NAT et le chemin de retour côté distant
- Le forwarding IP est-il activé sur le « serveur » ou le pair passerelle ?
- Le réseau distant connaît-il une route de retour vers le sous‑réseau du client VPN ?
- Si vous dépendez du NAT, est‑il effectivement appliqué sur la bonne interface et à la bonne plage source ?
Quatrièmement : gérez les tueurs ennuyeux : MTU et DNS
- Testez le PMTU avec
ping -M do(IPv4) et des tailles de paquet réalistes. - Confirmez que les serveurs DNS et les domaines de recherche sont bien ceux que vous attendez après la mise en place du tunnel.
- Confirmez que l’IPv6 ne fuit pas ou ne crée pas de trous noirs (surtout avec tunnel IPv4 complet uniquement).
Tâches pratiques : commandes, sorties et décisions
C’est la partie que vous exécutez pendant un incident. Chaque tâche inclut : la commande, ce que signifie la sortie,
et quelle décision prendre ensuite.
Task 1: Confirm WireGuard sees the peer and is exchanging packets
cr0x@server:~$ sudo wg show
interface: wg0
public key: 9zHhYw...redacted...
private key: (hidden)
listening port: 51820
peer: 2YpG3h...redacted...
endpoint: 203.0.113.50:54022
allowed ips: 10.40.0.2/32, 10.99.0.0/16
latest handshake: 28 seconds ago
transfer: 14.20 MiB received, 18.77 MiB sent
persistent keepalive: every 25 seconds
Signification : le handshake est récent et les compteurs sont non nuls. WireGuard peut atteindre l’endpoint et chiffrer/déchiffrer le trafic.
Ce n’est toujours pas la preuve que l’OS route le trafic dans wg0, ni que l’extrémité distante le transfère.
Décision : si le handshake est périmé (minutes+) ou si le transfert reste à zéro, concentrez‑vous sur la reachabilité UDP, l’adresse de l’endpoint,
et le pare‑feu/NAT. S’il est sain, passez au routage.
Task 2: Check interface addresses (the “what IP am I even using” step)
cr0x@server:~$ ip -brief address show dev wg0
wg0 UP 10.40.0.1/24 fd00:40::1/64
Signification : wg0 a des adresses IPv4 et IPv6. Si votre pair attendait /32 mais que vous avez configuré /24, ce n’est pas automatiquement faux,
mais cela affecte vos hypothèses de routage et ce que vous NATez.
Décision : confirmez que les deux côtés s’accordent sur le schéma d’adressage (routes hôtes vs sous‑réseaux), et que
AllowedIPs inclut les adresses source du pair.
Task 3: Ask the kernel where it will send a specific destination
cr0x@server:~$ ip route get 10.99.10.25
10.99.10.25 dev wg0 src 10.40.0.1 uid 0
cache
Signification : le noyau enverrait des paquets vers 10.99.10.25 via wg0. Bien.
S’il indique dev eth0 ou une autre interface, la table de routage du noyau n’est pas alignée avec votre intention.
Décision : si le routage est incorrect, inspectez les routes et les règles de policy (ip route, ip rule).
Ne touchez pas encore à la configuration WireGuard.
Task 4: Do the same for IPv6 (because dual-stack loves to gaslight you)
cr0x@server:~$ ip -6 route get 2606:4700:4700::1111
2606:4700:4700::1111 via fe80::1 dev eth0 src 2001:db8:12::10 metric 1024 pref medium
Signification : le trafic IPv6 sort par eth0, pas wg0. Si vous attendiez un tunnel complet, vous avez probablement oublié
::/0 dans AllowedIPs ou les règles de policy routing IPv6 n’ont pas été ajoutées.
Décision : décidez si vous voulez que l’IPv6 soit tunnelisé, bloqué ou laissé intact. « Je ne sais pas » est la cause des tunnels à moitié fonctionnels et des pannes confuses.
Task 5: Inspect routes added for AllowedIPs
cr0x@server:~$ ip route show table main | grep -E 'wg0|10\.99\.|10\.40\.'
10.40.0.0/24 dev wg0 proto kernel scope link src 10.40.0.1
10.99.0.0/16 dev wg0 scope link
Signification : vous avez une route directe vers 10.99.0.0/16 via wg0. Cela correspond aux AllowedIPs du pair.
Si la route manque, votre système n’essaiera même pas de mettre le trafic dans le tunnel.
Décision : si les routes manquent, vérifiez si vous avez utilisé wg (pas de routes) vs wg-quick (ajoute des routes),
ou si NetworkManager/systemd-networkd gère les routes ailleurs.
Task 6: Check policy routing rules (full tunnel and “why is only some traffic going via wg0”)
cr0x@server:~$ ip rule show
0: from all lookup local
32764: from all fwmark 0xca6c lookup 51820
32765: from all lookup main suppress_prefixlength 0
32766: from all lookup main
32767: from all lookup default
Signification : le trafic marqué avec fwmark 0xca6c utilise la table 51820.
La règle suppress_prefixlength 0 est une astuce commune de wg-quick pour éviter les boucles de routage.
Décision : si vous attendiez un full-tunnel mais ne voyez pas ces règles, wg-quick ne les a probablement pas appliquées
(ou un autre outil les a supprimées). Corrigez le routage d’abord ; n’élargissez pas AllowedIPs au hasard.
Task 7: Inspect the WireGuard-specific routing table (if used)
cr0x@server:~$ ip route show table 51820
default dev wg0 scope link
203.0.113.50 via 192.0.2.1 dev eth0
Signification : dans la table 51820, la route par défaut va via wg0, mais l’endpoint du pair 203.0.113.50 est explicitement routé via la passerelle de eth0.
C’est l’exception « ne pas tunneliser le tunnel ».
Décision : si l’exception pour l’endpoint manque ou pointe vers la mauvaise passerelle, le tunnel peut osciller ou ne jamais s’établir.
Corrigez le routage de l’endpoint, surtout si l’endpoint est un nom d’hôte qui résout plusieurs IPs.
Task 8: Verify forwarding is enabled on a gateway peer
cr0x@server:~$ sysctl net.ipv4.ip_forward net.ipv6.conf.all.forwarding
net.ipv4.ip_forward = 0
net.ipv6.conf.all.forwarding = 0
Signification : ce nœud ne forwarde pas les paquets entre interfaces. S’il est censé agir comme passerelle site-à-site,
c’est un obstacle majeur.
Décision : activez le forwarding (et persistez la configuration) si cet hôte doit router le trafic ; sinon repensez l’architecture :
gardez‑le en tant que point d’extrémité tunnel uniquement.
Task 9: Confirm firewall/NAT rules match the design (iptables example)
cr0x@server:~$ sudo iptables -t nat -S | grep -E 'POSTROUTING|wg0|eth0'
-A POSTROUTING -s 10.40.0.0/24 -o eth0 -j MASQUERADE
Signification : les paquets provenant de 10.40.0.0/24 sortant par eth0 seront NATés. Si vos clients sont dans 10.40.0.0/24 et que vous voulez qu’ils
atteignent Internet via ce serveur, c’est probablement nécessaire.
Décision : si vous avez besoin d’un site-à-site sans NAT, ne faites pas de masquerading. Ajoutez plutôt des routes sur le réseau distant vers 10.40.0.0/24.
Le NAT « fonctionne » jusqu’à ce qu’il casse l’audit, la connectivité entrante, et votre volonté de vivre.
Task 10: Capture traffic to see the wrong turn
cr0x@server:~$ sudo tcpdump -ni wg0 host 10.99.10.25
tcpdump: verbose output suppressed, use -v[v]... for full protocol decode
listening on wg0, link-type RAW (Raw IP), snapshot length 262144 bytes
12:11:02.100112 IP 10.40.0.1 > 10.99.10.25: ICMP echo request, id 2101, seq 1, length 64
12:11:03.110144 IP 10.40.0.1 > 10.99.10.25: ICMP echo request, id 2101, seq 2, length 64
Signification : des paquets entrent dans wg0. S’il n’y a pas de réponses, le problème est probablement au‑delà de cet hôte :
routage distant, pare‑feu distant, ou validation AllowedIPs côté distant.
Décision : faites une capture aussi sur l’extrémité distante. Si le distant reçoit mais ne répond pas, inspectez ses routes et son pare‑feu.
S’il ne reçoit jamais, vérifiez le NAT de l’endpoint et si vous envoyez au bon pair.
Task 11: Inspect WireGuard peer AllowedIPs overlaps (the stealth foot-gun)
cr0x@server:~$ sudo wg show wg0 allowed-ips
2YpG3h...redacted... 10.40.0.2/32
2YpG3h...redacted... 10.99.0.0/16
7QkLm1...redacted... 10.99.10.0/24
Signification : il y a un chevauchement : un pair revendique 10.99.0.0/16, un autre revendique 10.99.10.0/24.
Le longest prefix match signifie que 10.99.10.x ira au pair /24, pas au /16.
Décision : décidez si c’est intentionnel. Si non, retirez ou resserrez un des préfixes.
Si oui, documentez-le clairement et testez le comportement de bascule, car c’est facile à casser lors d’intégrations.
Task 12: Verify what wg-quick actually applied (audit the “translator”)
cr0x@server:~$ sudo wg-quick up wg0
[#] ip link add wg0 type wireguard
[#] wg setconf wg0 /dev/fd/63
[#] ip -4 address add 10.40.0.1/24 dev wg0
[#] ip link set mtu 1420 up dev wg0
[#] ip -4 route add 10.99.0.0/16 dev wg0
[#] resolvconf -a tun.wg0 -m 0 -x
[#] iptables -A FORWARD -i wg0 -j ACCEPT
[#] iptables -A FORWARD -o wg0 -j ACCEPT
[#] iptables -t nat -A POSTROUTING -s 10.40.0.0/24 -o eth0 -j MASQUERADE
Signification : c’est le véritable jeu de changements. Vous voyez le MTU, les routes, les modifications DNS et les règles iptables.
Si votre modèle mental diffère de cette sortie, votre modèle mental est erroné.
Décision : si la sortie de wg-quick montre des changements que vous n’aviez pas prévus (manipulation DNS, NAT, forwarding),
arrêtez d’utiliser des comportements implicites et fixez-les avec une config explicite ou votre propre orchestration.
Task 13: Check reverse path filtering (a quiet dropper)
cr0x@server:~$ sysctl net.ipv4.conf.all.rp_filter net.ipv4.conf.wg0.rp_filter
net.ipv4.conf.all.rp_filter = 1
net.ipv4.conf.wg0.rp_filter = 1
Signification : le reverse path filtering strict peut jeter des paquets si le noyau estime que la route de retour pour l’adresse source
ne sortirait pas par la même interface. Avec le policy routing et des chemins asymétriques, cela peut casser le trafic WireGuard de façons créatives.
Décision : sur des passerelles à routage intensif, envisagez de régler rp_filter en mode laxiste (2) lorsque approprié,
mais faites‑le de manière intentionnelle et après revue sécurité.
Task 14: Validate MTU/PMTU quickly (don’t guess, measure)
cr0x@server:~$ ping -c 3 -M do -s 1372 10.99.10.25
PING 10.99.10.25 (10.99.10.25) 1372(1400) bytes of data.
1380 bytes from 10.99.10.25: icmp_seq=1 ttl=62 time=31.2 ms
1380 bytes from 10.99.10.25: icmp_seq=2 ttl=62 time=30.9 ms
1380 bytes from 10.99.10.25: icmp_seq=3 ttl=62 time=31.0 ms
--- 10.99.10.25 ping statistics ---
3 packets transmitted, 3 received, 0% packet loss, time 2003ms
Signification : si cela réussit à une taille réaliste, les problèmes de fragmentation sont moins probables.
S’il échoue avec « Message too long », votre MTU est trop élevé quelque part sur le chemin.
Décision : ajustez le MTU sur wg0 (ou laissez wg-quick le définir), surtout à travers PPPoE, LTE, ou tunnels imbriqués.
Task 15: Confirm routes on the remote side (because return paths are a thing)
cr0x@server:~$ ssh ops@remote-gw 'ip route show | grep 10.40.0.0/24'
10.40.0.0/24 dev wg0 scope link
Signification : le côté distant sait que 10.40.0.0/24 est joignable via wg0, donc les réponses peuvent revenir.
Si le distant n’est pas l’endpoint mais un routeur LAN derrière lui, vous avez besoin de routes là aussi.
Décision : si la route de retour manque, ajoutez‑la (préférable) ou utilisez le NAT (dernier recours) selon vos besoins de sécurité et d’observabilité.
Sélection de pair et le piège du « préfixe le plus spécifique gagne »
La sélection de pair de WireGuard est déterministe et simple : il trouve le pair qui a une entrée AllowedIPs
correspondant le mieux à l’adresse de destination en utilisant le longest-prefix match. C’est essentiellement comment fonctionnent aussi les tables de routage.
La simplicité est bonne — jusqu’à ce que vous créiez accidentellement une politique que vous ne vouliez pas.
Que se passe‑t‑il avec des chevauchements
Imaginez que vous avez :
- Pair A :
AllowedIPs = 10.0.0.0/8(un pair « réseau corp entier » qui attrape tout) - Pair B :
AllowedIPs = 10.42.0.0/16(un site‑à‑site spécifique)
Le trafic vers 10.42.x.y va au Pair B. Le trafic vers 10.99.x.y va au Pair A.
C’est correct quand c’est intentionnel. C’est aussi une source d’incidents « pourquoi le trafic prod est allé sur le VPN lab » lorsque quelqu’un copie un bloc de configuration.
Les chevauchements affectent aussi la validation en entrée : si le Pair B envoie un paquet depuis la source 10.99.1.10
mais que Pair B n’a pas 10.99.0.0/16 dans ses AllowedIPs, le destinataire rejette le paquet.
Les chevauchements peuvent donc causer de la redirection sortante et des rejets entrants selon qui croit quoi.
N’utilisez pas AllowedIPs comme « routes annoncées » sauf si vous avez conçu le système ainsi
Dans certains systèmes VPN, le plan de contrôle distribue dynamiquement des routes. WireGuard ne le fait pas.
Si vous voulez un comportement de distribution de routes, il faut le construire (avec gestion de config, template,
ou votre propre contrôleur) et alors gérer les chevauchements comme une priorité.
Une règle pragmatique : évitez les chevauchements sauf si c’est intentionnel et que vous pouvez l’expliquer en une phrase.
Si vous ne le pouvez pas, vous accumulez des pannes futures.
Tunnel split vs tunnel complet : ce qui change et ce qui casse
Tunnel split : n’envoyer que des sous‑réseaux spécifiques via wg0
C’est le défaut raisonnable pour la plupart des cas d’usage corporate et site‑à‑site. Intention exemple :
« Seul 10.99.0.0/16 doit passer par WireGuard. »
Schéma de configuration :
- Le AllowedIPs du pair client inclut seulement les plages privées distantes et peut‑être l’IP wg du serveur.
- Les routes noyau pour ces plages pointent vers wg0.
- La route par défaut reste sur le réseau normal.
Modes d’échec :
- Le distant utilise des noms DNS qui résolvent en IP publiques ; le trafic sort par la route par défaut, pas par le tunnel.
- Les enregistrements AAAA IPv6 contournent votre tunnel uniquement IPv4.
- L’application fixe des IP ; votre hypothèse « seulement le sous‑réseau X » est erronée par rapport au déploiement du service.
Tunnel complet : router Internet via le VPN
Utile pour les réseaux non fiables, le contrôle d’egress, ou une adresse source cohérente. C’est aussi là que
la confusion sur AllowedIPs devient coûteuse.
Schéma de configuration :
- Le AllowedIPs du pair client inclut
0.0.0.0/0et généralement::/0. - Le policy routing est utilisé pour exempter l’IP de l’endpoint et pour que le système ne tunnelise pas son trafic de contrôle.
- Le serveur/passerelle doit effectuer du NAT ou router le trafic des clients en aval.
Modes d’échec :
- DNS casse : votre résolveur n’est joignable qu’à travers le tunnel, mais le tunnel dépend du DNS pour trouver l’endpoint.
- L’endpoint change d’IP ; votre route d’exception pointe vers l’adresse d’hier ; le tunnel meurt à la reconnexion.
- Seul IPv4 est tunnelisé, l’IPv6 fuit ou crée des trous noirs, les navigateurs subissent des timeouts « aléatoires ».
Blague n°2 : Les VPN full-tunnel sont comme déménager : vous découvrez tout ce que vous possédez quand vous devez tout router.
Trois mini-histoires d’entreprise tirées du terrain
Incident : la fausse hypothèse que « AllowedIPs est une ACL »
Une entreprise de taille moyenne a déployé WireGuard pour l’accès des contractuels. Le design était simple : les contractuels devaient atteindre une poignée de services internes
(un serveur Git, un système de tickets, un cache de build). L’équipe sécurité a insisté : « Autorisez seulement ces IPs. »
L’équipe réseau a obtempéré en configurant des AllowedIPs clients étroits : quelques /32 pour les services.
Le tunnel s’est établi. Les handshakes semblaient corrects. Les contractuels n’ont toujours pas pu atteindre les services de manière fiable. Pire, les échecs étaient intermittents,
ce qui coûte cher puisque chacun perd du temps à prouver que ce n’est pas de son fait.
L’on‑call SRE a regardé les statistiques WireGuard : le trafic quittait le client, arrivait sur le serveur, puis… rien.
La cause racine était subtile mais prévisible : les services internes étaient derrière des load balancers et répondaient parfois depuis des IPs différentes.
Les contractuels se connectaient au VIP (un des /32), mais les connexions suivantes étaient redirigées vers des backends dont les IPs n’étaient pas présentes dans AllowedIPs.
Le noyau du client routait ces connexions backend via l’interface normale, pas wg0. Du point de vue du serveur, il n’a même pas vu ces paquets. Du point de vue de l’utilisateur, « le VPN est instable ».
La solution n’a pas été « élargir tout à 0.0.0.0/0 ». La solution a été d’aligner l’intention de routage avec la topologie des services :
ils sont passés de /32 par hôte à des sous‑réseaux internes spécifiques qui contenaient effectivement le load balancer et les backends, et ils ont aussi fixé le DNS
pour ces services vers des adresses internes joignables via le tunnel. Ils ont aussi documenté la règle : AllowedIPs gouverne le routage,
pas l’autorisation. Les règles de pare‑feu s’occupent de l’autorisation.
La leçon : si vous essayez d’utiliser AllowedIPs comme frontière de sécurité, vous construirez une frontière de sécurité peu fiable.
Placez le contrôle d’accès là où il doit être : pare-feu, proxies avec authentification, et authentification des services. Laissez le routage faire son travail.
Optimisation qui s’est retournée contre eux : « simplifier » en effaçant les AllowedIPs
Une autre organisation avait des dizaines de pairs site‑à‑site WireGuard vers un hub central. Chaque pair avait des AllowedIPs soigneusement limitées :
site A possédait 10.10.0.0/16, site B 10.20.0.0/16, etc. Ça fonctionnait, la plupart du temps.
Puis quelqu’un a proposé un « nettoyage » : « Mettons juste 10.0.0.0/8 pour chaque site, ainsi on ne mettra plus à jour les configs quand un nouveau sous‑réseau apparaît. »
Le changement a passé la revue parce que c’était opérationnellement commode. Il a aussi créé des AllowedIPs chevauchants partout.
WireGuard a alors fait des choix déterministes : le pair qui avait la route la plus spécifique pour une destination donnée l’emportait, mais maintenant beaucoup de pairs avaient la
même spécificité. La sélection du hub est devenue sensible à l’ordre de configuration et au timing des mises à jour.
L’incident qui a suivi n’a pas été une panne totale. C’était pire : certains sous‑réseaux étaient intermittents et routés vers le mauvais site, et le pare‑feu du mauvais site les rejetait.
Les applications qui réessaient « fonctionnaient parfois ». Le monitoring s’est embrasé, mais avec des motifs ressemblant à des problèmes de latence.
L’équipe réseau a passé des jours à pourchasser une congestion fantôme.
Le retour en arrière n’a pas été immédiat car des nouveaux sites avaient été déployés en supposant la configuration « simplifiée », et leur routage en dépendait.
La correction finale a été de restaurer une propriété non chevauchante : chaque site a reçu des préfixes explicites, maintenus par infrastructure-as-code.
L’« optimisation » a coûté plus que le travail manuel d’origine.
Pratique ennuyeuse mais correcte qui a sauvé la mise : tests explicites de routes en CI
L’équipe la plus résiliente que j’ai rencontrée traitait les configs WireGuard comme du code, pas comme des œuvres d’art. Chaque changement à un AllowedIPs ou à un endpoint passait par un pipeline qui exécutait une petite batterie d’assertions de routes.
Pas glamour. Juste impitoyable.
Ils avaient un harness de test qui lançait un environnement léger en namespace réseau, appliquait la config proposée, et exécutait
ip route get pour un ensemble de destinations critiques. Il inspectait aussi wg show allowed-ips pour détecter les chevauchements.
Si un nouveau préfixe chevauchait un existant sans exception approuvée, le pipeline échouait.
Un vendredi, un ingénieur bien intentionné a tenté d’ajouter un nouveau sous‑réseau distant et a tapé par erreur 10.0.0.0/8 au lieu de 10.80.0.0/16.
Sur une équipe classique, cela devient un incident de week‑end. Ici, le job CI l’a rejeté immédiatement avec un diff lisible : « Chevauchement avec le pair X ; redirigerait le trafic pour ces destinations. »
Rien de héroïque ne s’est passé. Aucun pager n’a sonné. C’est le but.
La pratique n’était pas glamour, mais elle rendait les changements de routage ennuyeux — et l’ennui est la caractéristique la plus sous‑estimée en production.
Une citation toujours pertinente : Espérer n’est pas une stratégie
— Général Gordon R. Sullivan.
Erreurs courantes : symptômes → cause racine → correction
1) « Le handshake fonctionne, mais je ne peux pinguer rien derrière le pair »
Symptôme : wg show montre un handshake récent ; les pings vers les hôtes du LAN distant échouent.
Cause racine : forwarding manquant sur la passerelle distante, ou route de retour manquante du LAN distant vers votre sous‑réseau VPN.
Correction : activez l’IP forwarding sur la passerelle et ajoutez une route sur le routeur LAN distant pointant votre sous‑réseau VPN via la passerelle WireGuard. N’utilisez le NAT qu’en dernier recours.
2) « Le trafic passe toujours par ma connexion Internet normale » (surprise split tunnel)
Symptôme : trafic attendu via wg0 vers un service interne, mais ip route get montre dev eth0 (ou Wi‑Fi).
Cause racine : route noyau manquante pour la destination, ou l’IP de destination n’est dans les AllowedIPs d’aucun pair.
Correction : assurez‑vous que les préfixes de destination sont dans les AllowedIPs du pair et que les routes existent (via wg-quick ou ip route add manuellement).
3) « Tunnel complet activé, maintenant le tunnel ne monte plus »
Symptôme : après avoir mis AllowedIPs = 0.0.0.0/0, le handshake échoue ou oscille.
Cause racine : le trafic vers l’endpoint est routé dans wg0 (tunneling the tunnel), souvent parce que la route d’exception pour l’endpoint est manquante ou incorrecte.
Correction : utilisez l’approche policy routing de wg-quick ou ajoutez une route explicite pour l’IP de l’endpoint via la passerelle physique. Évitez les hostnames d’endpoint qui changent sans gérer les mises à jour.
4) « Certains sous‑réseaux fonctionnent, un sous‑réseau va mystérieusement vers le mauvais pair »
Symptôme : le trafic vers 10.99.10.0/24 va ailleurs ; d’autres réseaux 10.99.x se comportent différemment.
Cause racine : AllowedIPs chevauchants avec un préfixe plus long qui sélectionne un autre pair.
Correction : retirez les chevauchements ou rendez‑les intentionnels et documentés ; vérifiez avec wg show allowed-ips.
5) « Ça marche en IPv4, mais l’IPv6 est cassé (ou fuit) »
Symptôme : IPv4 atteint les ressources internes, mais les navigateurs timeout sur certains sites ; ip -6 route get montre une sortie non VPN.
Cause racine : vous avez tunnelisé 0.0.0.0/0 mais pas ::/0, ou le DNS renvoie des enregistrements AAAA qui prennent un chemin différent.
Correction : supportez complètement IPv6 via le tunnel (AllowedIPs + routes + pare‑feu) ou désactivez/blackholez explicitement IPv6 pour cet hôte lorsque le VPN est actif.
6) « Les paquets entrent dans wg0 mais ne reçoivent jamais de réponses »
Symptôme : tcpdump sur wg0 montre des paquets sortants ; pas de réponses entrantes.
Cause racine : le côté distant rejette l’entrée parce que l’IP source n’est pas dans ses AllowedIPs (vérification anti-usurpation), ou le pare‑feu distant la bloque.
Correction : assurez‑vous que les AllowedIPs du pair distant incluent votre plage source. Puis vérifiez que le pare‑feu distant autorise le trafic depuis le sous‑réseau VPN.
7) « Tout est lent, surtout les gros téléchargements »
Symptôme : les petits pings fonctionnent ; les gros transferts se bloquent ou ramollissent.
Cause racine : incohérence MTU/PMTU provoquant perte de fragmentation ou ICMP « fragmentation needed » bloqué.
Correction : réduisez le MTU de wg0 ; testez avec ping -M do ; assurez‑vous que l’ICMP n’est pas bloqué sur le chemin.
8) « Après un redémarrage réseau, le routage est faux jusqu’à ce que je redémarre wg0 »
Symptôme : WireGuard est up, mais les routes/policy rules du noyau sont manquantes ou modifiées après des changements de lien.
Cause racine : gestionnaires réseau concurrents (NetworkManager, systemd-networkd, scripts custom) réécrivant routes et règles.
Correction : choisissez une autorité. Si vous utilisez wg-quick, assurez‑vous que c’est lui qui applique les règles ; sinon gérez les routes explicitement dans votre pile réseau.
Listes de contrôle / plan étape par étape
Checklist A: Construire un split tunnel correct (site-à-site ou accès interne)
- Définissez les vrais préfixes de destination (sous‑réseaux, pas des /32 souhaités). Incluez load balancers, backends et résolveurs DNS si nécessaire.
- Configurez les AllowedIPs du pair exactement sur ces préfixes côté client. Gardez‑les non chevauchants autant que possible.
- Montez le tunnel avec wg-quick et confirmez que les routes existent dans
ip route. - Utilisez
ip route getpour confirmer les décisions du noyau pour chaque destination critique. - Vérifiez les routes de retour côté distant pour le sous‑réseau client VPN (ou configurez le NAT délibérément).
- Documentez la propriété : quel pair « possède » quels préfixes. Traitez‑le comme de l’IPAM, car c’en est en pratique.
Checklist B: Construire un full tunnel correct (egress Internet via WireGuard)
- Décidez IPv4 uniquement vs dual‑stack. Si vous ne tunnelisez pas IPv6, désactivez‑le explicitement ou bloquez‑le pour éviter les fuites et les blocages bizarres.
- Réglez AllowedIPs sur les routes par défaut :
0.0.0.0/0et généralement::/0. - Confirmez l’existence du policy routing :
ip ruleet une table dédiée qui inclut une route d’exception pour l’endpoint. - Confirmez le forwarding et le NAT côté serveur si le serveur fournit l’egress.
- Validez le comportement DNS : assurez‑vous que les résolveurs sont joignables après l’activation du tunnel et avant sa déconnexion lors de reconnexions.
- Exécutez des tests PMTU et définissez le MTU explicitement si votre environnement est variable (LTE, PPPoE, tunnels imbriqués).
Checklist C: Configuration hub multi-pairs sans surprises
- Rendez les AllowedIPs non chevauchants par défaut. Les chevauchements nécessitent une note de design explicite et des tests.
- Utilisez la gestion de configuration pour générer les configs de façon cohérente. Les humains copient/colent les erreurs plus vite qu’ils ne les corrigent.
- Exécutez une détection automatisée des chevauchements en validant la sortie de
wg show allowed-ips. - Testez la sélection de route avec
ip route getet capturez au moins une IP par préfixe. - Planifiez la reachabilité des endpoints (IPs statiques, DNS stable, ou exceptions de route d’endpoint explicites).
FAQ
1) AllowedIPs est‑il un pare‑feu ?
Non. Il influence la sélection du pair en sortie et valide les adresses source en entrée. Utilisez des règles de pare‑feu pour l’autorisation.
Si vous « sécurisez » l’accès uniquement en rétrécissant AllowedIPs, vous casserez surtout le routage.
2) Pourquoi mon interface WireGuard a‑t‑elle une IP qui n’est pas dans AllowedIPs ?
Les adresses d’interface (Address =) et AllowedIPs sont des concepts différents. L’adresse d’interface est celle que l’hôte local utilise en source.
AllowedIPs dit ce que chaque pair revendique pour le routage et la validation source. Ils doivent être compatibles, mais ce ne sont pas les mêmes réglages.
3) Dois‑je ajouter des routes manuellement quand je change AllowedIPs ?
Si vous utilisez wg directement : oui, car il ne touchera pas aux routes. Si vous utilisez wg-quick : il ajoutera des routes à la montée,
mais changer AllowedIPs à chaud peut ne pas mettre à jour les routes noyau comme vous vous y attendez. Traitez les changements comme nécessitant un reappli contrôlé.
4) Pourquoi j’ai « handshake mais pas de trafic » ?
Parce que le handshake ne prouve que l’UDP et les clés. Le trafic peut encore échouer à cause de routes noyau manquantes, forwarding manquant, NAT manquant,
rejets pare‑feu distants, ou validation AllowedIPs côté récepteur.
5) Que se passe‑t‑il si deux pairs ont le même préfixe AllowedIPs ?
Le longest prefix match choisit le préfixe le plus spécifique. Si la spécificité est à égalité, le comportement dépend de l’ordre interne et peut être instable lors des mises à jour.
Ne comptez pas sur des égalités ; rendez la propriété explicite.
6) Dois‑je mettre 0.0.0.0/0 dans AllowedIPs sur le serveur ?
En général non. Sur un « serveur » qui accepte beaucoup de clients, vous donnez généralement à chaque client un /32 (et peut‑être des sous‑réseaux client).
Mettre 0.0.0.0/0 sur l’entrée peer d’un client côté serveur dit au serveur d’envoyer tout le trafic à ce client. Ce n’est rarement souhaitable.
7) Pourquoi ajouter ::/0 casse les choses même quand IPv6 « n’est pas utilisé » ?
Parce que les applications utilisent absolument IPv6 quand il existe. Si vous routez l’IPv6 dans le tunnel mais ne fournissez pas forwarding/DNS/egress IPv6 côté distant,
vous créez un trou noir. Décidez délibérément : supportez‑le complètement ou désactivez‑le.
8) Puis‑je utiliser AllowedIPs pour implémenter « seulement ces services passent par le VPN » ?
Seulement si ces services se mappent proprement à des préfixes IP de destination que vous contrôlez. Si le service utilise des CDN, des backends dynamiques, ou des redirections,
les IPs de destination changeront et votre intention de routage sera violée. Dans ces cas, utilisez des contrôles au niveau applicatif et considérez le VPN comme du transport.
9) Pourquoi le ping fonctionne mais TCP non ?
MTU et PMTU sont la réponse classique. L’ICMP est petit ; le TCP avec des problèmes MSS/PMTU peut se bloquer. Vérifiez aussi les pare‑feu stateful et le routage asymétrique.
Confirmez avec des pings PMTU et des captures de paquets.
10) wg-quick est‑il « mauvais » ?
Non. C’est un outil solide. Mais c’est aussi un wrapper qui modifie routes, règles, DNS et parfois l’état du pare‑feu.
En production, standardisez son usage et testez son comportement, ou remplacez‑le par une orchestration explicite.
La pire option est « on croit utiliser wg-quick mais d’autres outils l’annulent ».
Conclusion : prochaines étapes pratiques
Si le trafic WireGuard ne va pas où vous l’attendez, arrêtez de fixer le handshake.
Traitez AllowedIPs comme une entrée de politique de routage, puis vérifiez les couches système dans l’ordre :
décision de route du noyau, sélection du pair WireGuard, et chemin de retour distant.
Prochaines étapes que vous pouvez faire aujourd’hui :
- Choisissez une destination qui échoue et exécutez
ip route get(etip -6 route get) pour elle. Croyez la sortie. - Exécutez
wg show allowed-ipset cherchez les chevauchements. Si vous en trouvez un que vous ne pouvez pas justifier, retirez‑le. - Sur les pairs passerelles, vérifiez le forwarding et la route de retour. Corrigez cela avant de toucher au MTU ou au DNS.
- Décidez explicitement split vs full tunnel, y compris le comportement IPv6. Les demi-décisions créent des pannes complètes.
- Notez la propriété des préfixes. Sérieusement. Votre futur vous remerciera lors du prochain « pourquoi prod va vers staging ».