Deux sites, un sous-réseau, un concentrateur WireGuard : faites-le fonctionner
Les deux LAN sont sur 10.10.7.0/24, donc le concentrateur ne peut pas choisir un site par destination. Donnez à chaque service un alias et traduisez à sa passerelle.
Les deux sites utilisent la même plage LAN, et le chevauchement n’est pas ce qui casse réellement la conception. Le concentrateur doit choisir un site uniquement à partir de l’adresse de destination, et deux destinations identiques ne lui donnent rien pour choisir. Renuméroter un bureau qui fonctionne pour satisfaire un tunnel est généralement un pire échange que de donner à chaque service publié une adresse distincte que le tunnel peut transporter. La conception ci-dessous publie un service HTTPS par site et rien d’autre.
Pourquoi le chevauchement n’est pas le vrai problème
WireGuard transmet selon la destination : les AllowedIPs d’un peer décident quel peer reçoit un paquet. Deux peers ne peuvent pas tous deux annoncer 10.10.7.0/24 sans que l’un d’eux gagne chaque recherche. C’est une propriété de la table des peers et non du tunnel, c’est pourquoi la solution ici est un plan d’adresses et non une astuce de routage.
Le plan consiste à cesser complètement d’annoncer le LAN. Annoncez plutôt un alias par service, une adresse par site, et laissez la passerelle de chaque site traduire cet alias vers son application réelle.
L’utilisateur route deux adresses uniques, ne voit jamais le préfixe ambigu, et rien ne change dans l’un ou l’autre bureau. Cela énonce aussi la limite honnêtement : vous publiez un service HTTPS depuis chaque site, vous ne fusionnez pas deux réseaux. Les règles qui suivent restent petites parce que l’énoncé est étroit. Un énoncé plus large demanderait des règles plus larges, et c’est ainsi que ces conceptions se compliquent.
Donnez à chaque site un alias que l’utilisateur peut router
Choisissez des adresses dans une plage qui n’entre en conflit avec rien sur la machine de l’utilisateur, le concentrateur ou l’un des deux LAN. Ici le concentrateur est 10.66.0.1, l’utilisateur 10.66.0.10, les passerelles 10.66.0.21 et 10.66.0.22, et les deux alias 10.77.1.20 et 10.77.2.20. Le concentrateur publie chaque alias via le peer qui le possède, donc un paquet sortant adressé à un alias ne peut partir que par le site correspondant :
[Interface]
Address = 10.66.0.1/32
ListenPort = 51820
PrivateKey = HUB_KEY
[Peer]
PublicKey = USER_PUBLIC_KEY
AllowedIPs = 10.66.0.10/32
[Peer]
PublicKey = SITE_A_PUBLIC_KEY
AllowedIPs = 10.66.0.21/32, 10.77.1.20/32
[Peer]
PublicKey = SITE_B_PUBLIC_KEY
AllowedIPs = 10.66.0.22/32, 10.77.2.20/32
Le côté utilisateur n’a besoin que des deux alias, ce qui garde la configuration du client exempte des deux préfixes LAN. Rien dans cette configuration ne mentionne l’un ou l’autre LAN réel :
[Interface]
Address = 10.66.0.10/32
PrivateKey = USER_KEY
[Peer]
PublicKey = HUB_PUBLIC_KEY
Endpoint = hub.example.net:51820
AllowedIPs = 10.77.1.20/32, 10.77.2.20/32
PersistentKeepalive = 25
Chaque passerelle annonce le concentrateur et la source de l’utilisateur, rien d’autre, si bien qu’un site n’apprend jamais le LAN de l’autre. Le keepalive maintient une correspondance NAT sur la liaison montante du site ; il n’autorise pas le trafic, et le pare-feu décide toujours de ce qui est admis. Copier la configuration d’une passerelle vers l’autre est acceptable à condition que la clé privée, l’adresse d’interface et l’alias changent tous.
Ce que le concentrateur doit autoriser entre deux de ses peers
Le concentrateur transmet des paquets entre deux de ses propres peers, ce qui est une décision de la chaîne forward et non une décision d’entrée. Activez le transfert IPv4 via le mécanisme habituel de la plateforme, puis autorisez exactement les paires dont la conception a besoin.
La règle ci-dessous autorise l’utilisateur vers un alias et un port, et permet le trafic de retour via le suivi de connexion. Elle abandonne tout le reste sur le chemin forward, et c’est là le but :
nft add table inet hub_transit
nft add chain inet hub_transit forward '{ type filter hook forward priority 0 ; policy drop ; }'
nft add rule inet hub_transit forward ct state established,related accept
nft add rule inet hub_transit forward iifname wg0 oifname wg0 tcp dport 443 ip saddr 10.66.0.10 ip daddr 10.77.1.20 accept
Deux détails méritent d’être signalés car ils provoquent des défaillances silencieuses. Un accept dans une chaîne de base n’annule pas un drop dans une autre, donc fusionnez ceci avec la politique existante plutôt que de le charger à côté. Et l’adresse source identifie l’appareil, pas la personne ; gardez l’authentification applicative séparée de l’admission réseau.
Où un alias devient une adresse réelle
Le site A reçoit une requête pour 10.77.1.20, réécrit la destination vers l’application réelle et réécrit la source vers sa propre adresse LAN afin que la réponse puisse revenir sans route vers le tunnel. Faire les deux traductions au même endroit garde le reste du réseau ignorant de l’alias. Les règles ci-dessous sont tout le mécanisme :
nft add table ip site_a_nat
nft add chain ip site_a_nat pre '{ type nat hook prerouting priority -100 ; policy accept ; }'
nft add chain ip site_a_nat post '{ type nat hook postrouting priority 100 ; policy accept ; }'
nft add rule ip site_a_nat pre iifname wg0 tcp dport 443 ip saddr 10.66.0.10 ip daddr 10.77.1.20 dnat to 10.10.7.20:443
nft add rule ip site_a_nat post iifname wg0 oifname lan0 tcp dport 443 ip saddr 10.66.0.10 ip daddr 10.10.7.20 snat to 10.10.7.2
La politique forward du site A doit ensuite admettre le flux traduit de l’interface du tunnel vers l’interface LAN, plus la direction de retour. Le hook forward voit la destination après la traduction de destination et avant la réécriture de source, c’est pourquoi la règle nomme l’adresse de l’application réelle. Lisez ces deux hooks dans cet ordre dès qu’une règle semble ne correspondre à rien. Une règle forward écrite contre l’alias ne peut jamais correspondre, car l’alias n’existe plus à ce hook.
Le site B répète cela avec son propre alias et sa propre clé. Il ne doit pas réutiliser la clé privée du site A, car deux peers partageant une identité sont une erreur de configuration difficile à voir et facile à créer en copiant un fichier. Gardez les deux documents de passerelle identiques sauf pour les valeurs qui doivent différer, afin que la différence ressorte en revue. Un fichier copié est l’origine habituelle de cette faute.
La réécriture de source a un coût. L’application voit la passerelle comme son client, donc ses journaux ne montrent plus quel utilisateur s’est connecté. Conservez la piste d’audit de la passerelle, et n’affaiblissez pas la connexion applicative pour compenser une identité réseau que la traduction a supprimée.
Comment prouver que les deux noms publiés répondent
Donnez à chaque alias un nom DNS et configurez l’application et le certificat pour ce nom, car la traduction ne réécrit pas les redirections ni les URL absolues intégrées. Utilisez un nom par site afin qu’une incohérence de certificat ne soit jamais prise pour une panne de routage.
Testez depuis le client réel, confirmez quel site a répondu, et testez aussi un port non autorisé. Utilisez de nouvelles connexions après tout changement NAT, car l’état établi conserve l’ancienne correspondance :
wg show wg0 allowed-ips
sudo nft list ruleset
curl -sS -o /dev/null -w "%{http_code}\n" https://site-a.example.net/
Un alias vide ou inattendu dans la première commande signifie que la sélection de peer est fausse avant même qu’une règle de pare-feu compte. Si l’alias est correct et que le nom échoue encore, le problème s’est déplacé vers DNS et les certificats. Une fois que les deux noms répondent et que le troisième port reste fermé, la conception fait ce qu’elle annonce : deux services publiés étroitement, pas deux LAN fusionnés.