Deux clients peuvent tous deux ouvrir l’hôte de rebond et n’avoir néanmoins aucunement à s’ouvrir l’un l’autre. Atteindre un service est une décision de transfert, tandis qu’atteindre un pair est une décision de politique, et la plupart des piles VPN gardent ces deux choses dans des objets séparés. Rien de ce que vous configurez pour la première n’impose la seconde. Le travail n’est donc pas d’ajouter une règle, mais de trouver l’objet qui décide du trafic entre pairs sur ce serveur, d’y écrire le refus et de le prouver depuis un client.

Une route vers le service partagé n’est pas une autorisation entre pairs

Annoncer le sous-réseau des clients indique à un pair comment poser un paquet sur le fil vers l’adresse d’un autre client. La livraison de ce paquet se décide ensuite, par ce qui le transfère. Sur une passerelle Linux, c’est la chaîne FORWARD ; dans un démon en espace utilisateur, c’est la table de sessions du tunnel lui-même. Une route répond à l’accessibilité et laisse l’autorisation intacte.

C’est pourquoi un contrôle d’isolement qui ne lit que les routes ne prouve rien. Un /24 peut être poussé à chaque client alors que chaque paquet entre pairs est abandonné au crochet de transfert. Le cas dangereux est l’inverse : aucune règle explicite, une valeur par défaut permissive et un isolement qui n’existe que parce que personne ne l’a testé.

Écrivez l’exigence en une ligne avant d’ouvrir un terminal. Atteignez le bloc de services et l’hôte de rebond, n’atteignez rien d’autre à l’intérieur du bloc des clients.

Déterminez qui transfère réellement le paquet entre pairs

Deux comportements du serveur se ressemblent côté client et exigent des règles différentes. Soit le noyau transfère à nouveau le paquet hors de l’interface du tunnel, soit le démon le copie entre sessions et le noyau ne le voit jamais.

WireGuard appartient au premier groupe : il n’a pas de commutateur entre pairs, donc un paquet de 10.8.0.4 vers 10.8.0.5 arrive sur wg0, heurte le crochet de transfert et est de nouveau routé hors de wg0 quand AllowedIPs couvre les deux adresses. OpenVPN est le second groupe dès que client-to-client est défini dans la configuration du serveur, car cette directive remet le paquet entre sessions en espace utilisateur. Vérifiez la configuration chargée pour cette directive avant d’écrire quoi que ce soit. Une règle du noyau qui ne voit jamais de trafic est indiscernable d’une règle qui fonctionne, et c’est ainsi qu’un déploiement finit sans aucun isolement.

Lisez la configuration effective plutôt que le fichier que vous supposez chargé, car les paquets de distribution apportent leurs propres inclusions. Si le démon fait le transfert, le refus appartient à ses propres contrôles par client, et un pare-feu d’hôte ne filtre que le trafic adressé à l’hôte. Si le noyau transfère, le crochet de transfert est le seul endroit qui compte.

Les déploiements routés et traduits demandent une vérification de plus : la source que voit un client distant n’est peut-être pas celle que vous attendez. Alors une règle qui correspond au sous-réseau des clients ne correspond à rien. Notez l’adresse qui survit à la traduction avant d’écrire la correspondance, et préférez faire correspondre la paire d’interfaces plutôt que deviner des adresses NAT.

Donnez à chaque adresse une identité révocable isolément

L’isolement s’effondre dès que deux appareils partagent un même identifiant. Une règle liée à cette identité ne peut pas les séparer, et révoquer un portable perdu révoque tout le groupe. Des certificats par appareil ou des clés par pair gardent la révocation locale et la politique lisible, car chaque adresse correspond exactement à une personne ou une machine. Là où la conception ne le permet pas, dites-le dans le runbook au lieu de décrire la règle comme fine.

L’attribution des adresses doit s’accorder avec la politique. Réservez un bloc pour les services, un bloc pour les clients, et distribuez les adresses des clients depuis un ensemble que vous contrôlez plutôt qu’une plage du premier arrivé. Si le serveur traduit ou pont, gardez la table de correspondance à côté de la configuration, car c’est elle dont le prochain lecteur a besoin pour redériver la règle.

Placez le refus là où le paquet traverse le tunnel

Sur une passerelle qui transfère le trafic WireGuard, deux règles couvrent le cas : autorisez le bloc de services, puis abandonnez le reste du bloc des clients. La paire d’interfaces compte autant que les adresses, car une correspondance sur la seule destination attrape aussi le trafic venant du LAN. Chargez-les dans cet ordre pour que l’autorisation soit évaluée en premier.

Avec nftables, la paire entre dans une table inet filter existante, l’autorisation d’abord et l’abandon ensuite. Les deux correspondances épinglent la paire d’interfaces ainsi que les adresses.

nft add rule inet filter forward iifname "wg0" oifname "wg0" ip saddr 10.8.0.0/24 ip daddr 10.8.2.0/24 accept
nft add rule inet filter forward iifname "wg0" oifname "wg0" ip saddr 10.8.0.0/24 ip daddr 10.8.0.0/24 drop

Relisez la chaîne après le chargement au lieu de vous fier au statut de sortie, et confirmez que les deux règles sont dans l’ordre voulu. Ajoutez des règles ip6 correspondantes pour le pool IPv6, sinon la paire v4 n’est que décorative sur un tunnel double pile. Si le serveur a déjà une politique de transfert permissive, ajoutez l’abandon au lieu de remplacer la chaîne entièrement.

Quand client-to-client est activé sur OpenVPN, ces règles de transfert ne correspondent jamais au trafic entre pairs et le refus doit vivre dans les contrôles propres du démon. Gardez les règles du noyau pour le trafic adressé à l’hôte, mais ne les comptez pas comme le contrôle d’isolement.

Prouvez le refus depuis un client, pas depuis le serveur

Tester depuis la passerelle ne prouve rien, car le trafic généré localement prend le chemin de sortie et ne traverse jamais le crochet de transfert. Utilisez deux vrais clients : un qui doit atteindre le service, un qui doit être refusé. Exécutez d’abord le cas autorisé, pour qu’un tunnel cassé ne soit pas pris pour une politique qui fonctionne.

Depuis le client autorisé, confirmez que le service répond sur son port. Depuis le même client, essayez l’adresse du pair et attendez un abandon silencieux plutôt qu’un refus :

ping -c 3 -W 2 10.8.0.5
nc -z -w 2 10.8.0.5 22
nft list chain inet filter forward
iptables -vnL FORWARD
ping -6 -c 3 -W 2 fd00:8::5

Un paquet abandonné et un pair hors ligne ressemblent tous deux à un délai d’attente, alors vérifiez les compteurs avant de conclure quoi que ce soit. Confirmez que le compteur de la règle d’abandon augmente pendant que le pair est manifestement actif. Répétez en IPv6, où une règle ip6 absente laisse le refus v4 paraître efficace. Notez les résultats acceptés et refusés dans le runbook avec la date, car la prochaine migration redérivera la règle.

Articles similaires