Två platser, ett subnät, en WireGuard-hubb: få det att fungera
Båda LANen ligger på 10.10.7.0/24, så hubben kan inte välja plats efter destination. Ge varje tjänst ett alias och översätt vid dess gateway.
Båda platserna använder samma LAN-intervall, och överlappningen är inte det som egentligen bryter designen. Hubben måste välja plats enbart utifrån destinationsadressen, och två identiska destinationer ger den ingenting att välja med. Att numrera om ett kontor som fungerar för att tillfredsställa en tunnel är oftast ett sämre byte än att ge varje publicerad tjänst en egen adress som tunneln kan bära. Designen nedan publicerar en HTTPS-tjänst per plats och ingenting annat.
Varför överlappningen inte är det egentliga problemet
WireGuard vidarebefordrar efter destination: en peers AllowedIPs avgör vilken peer ett paket går till. Två peers kan inte båda annonsera 10.10.7.0/24 utan att en av dem vinner varje sökning. Det är en egenskap hos peertabellen och inte hos tunneln, därför är lösningen här en adressplan och inte ett routingtrick.
Planen är att sluta annonsera LANet helt. Annonsera i stället ett alias per tjänst, en adress per plats, och låt varje plats gateway översätta aliaset till sin riktiga applikation.
Användaren routar två unika adresser, ser aldrig det tvetydiga prefixet, och ingenting ändras i något av de två kontoren. Det säger också gränsen ärligt: du publicerar en HTTPS-tjänst från varje plats, inte slår ihop två nätverk. Reglerna nedan förblir små eftersom påståendet är smalt. Ett bredare påstående skulle kräva bredare regler, och det är så dessa designer blir komplicerade.
Ge varje plats ett alias som användaren kan routa
Välj adresser från ett intervall som inte krockar med något på användarens maskin, hubben eller något av de två LANen. Här är hubben 10.66.0.1, användaren 10.66.0.10, gatewayerna 10.66.0.21 och 10.66.0.22, och de två aliasen 10.77.1.20 och 10.77.2.20. Hubben publicerar varje alias via den peer som äger det, så ett utgående paket adresserat till ett alias kan bara lämna via den matchande platsen:
[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
Användarsidan behöver bara de två aliasen, vilket håller klientkonfigurationen fri från båda LAN-prefixen. Ingenting i den konfigurationen nämner något av de riktiga LANen:
[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
Varje gateway annonserar hubben och användarens källa, ingenting annat, så en plats lär sig aldrig den andras LAN. Keepalive upprätthåller en NAT-mappning på platsens uplänk; det auktoriserar ingen trafik, och brandväggen avgör fortfarande vad som släpps in. Att kopiera en gateways konfiguration till den andra är okej så länge den privata nyckeln, gränssnittsadressen och aliaset alla ändras.
Vad hubben måste tillåta mellan två av sina peers
Hubben vidarebefordrar paket mellan två av sina egna peers, vilket är ett beslut i forward-kedjan och inte ett inbeslut. Aktivera IPv4-vidarebefordran via plattformens vanliga mekanism och tillåt sedan exakt de par som designen behöver.
Regeln nedan tillåter användaren ett alias och en port, och tillåter returtrafik via anslutningsspårning. Den släpper allt annat på forward-vägen, och det är poängen:
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
Två detaljer är värda att nämna eftersom de orsakar tysta fel. En accept i en baskedja åsidosätter inte en drop i en annan, så slå ihop detta med den befintliga policyn i stället för att läsa in det bredvid. Och källadressen identifierar enheten, inte personen; håll applikationsautentisering åtskild från nätverkstillträde.
Där ett alias blir en riktig adress
Plats A tar emot en begäran till 10.77.1.20, skriver om destinationen till den riktiga applikationen och skriver om källan till sin egen LAN-adress så att svaret kan komma tillbaka utan en route till tunneln. Att göra båda översättningarna på ett ställe håller resten av nätverket ovetande om aliaset. Reglerna nedan är hela mekanismen:
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
Plats A:s forward-policy måste sedan tillåta det översatta flödet från tunnelgränssnittet till LAN-gränssnittet, plus returriktningen. Forward-hooken ser destinationen efter destinationsöversättningen och före källskrivningen, därför namnger regeln den riktiga applikationens adress. Läs de två hookarna i den ordningen när en regel verkar inte matcha något. En forward-regel skriven mot aliaset kan aldrig matcha, eftersom aliaset inte längre finns i den hooken.
Plats B upprepar detta med sitt eget alias och sin egen nyckel. Den får inte återanvända plats A:s privata nyckel, eftersom två peers som delar en identitet är ett konfigurationsfel som är svårt att se och lätt att skapa genom att kopiera en fil. Håll båda gatewaydokumenten identiska utom de värden som måste skilja sig, så att skillnaden sticker ut vid granskningen. En kopierad fil är det vanliga ursprunget till det felet.
Källskrivningen har ett pris. Applikationen ser gatewayen som sin klient, så dess loggar visar inte längre vilken användare som anslöt. Behåll gatewayens revisionsspår, och försvaga inte applikationsinloggningen för att kompensera för en nätverksidentitet som översättningen tog bort.
Hur du bevisar att båda publicerade namnen svarar
Ge varje alias ett DNS-namn och konfigurera applikationen och certifikatet för det namnet, eftersom översättning inte skriver om omdirigeringar eller inbäddade absoluta URLer. Använd ett namn per plats så att en certifikatavvikelse aldrig kan förväxlas med ett routingfel.
Testa från den riktiga klienten, bekräfta vilken plats som svarade, och testa även en otillåten port. Använd nya anslutningar efter varje NAT-ändring, eftersom etablerat tillstånd behåller den gamla mappningen:
wg show wg0 allowed-ips
sudo nft list ruleset
curl -sS -o /dev/null -w "%{http_code}\n" https://site-a.example.net/
Ett tomt eller oväntat alias i det första kommandot betyder att peer-valet är fel innan någon brandväggsregel spelar roll. Om aliaset är rätt och namnet fortfarande misslyckas har problemet flyttat till DNS och certifikat. När båda namnen svarar och den tredje porten förblir stängd gör designen det den påstår: två smalt publicerade tjänster, inte två sammanslagna LAN.