Due siti, una sottorete, un hub WireGuard: fatelo funzionare
Entrambe le LAN sono su 10.10.7.0/24, quindi l'hub non può scegliere un sito per destinazione. Date a ogni servizio un alias e traducete al suo gateway.
Entrambi i siti usano la stessa gamma LAN, e la sovrapposizione non è ciò che rompe davvero il progetto. L'hub deve scegliere un sito usando solo l'indirizzo di destinazione, e due destinazioni identiche non gli danno nulla con cui scegliere. Rinumerare un ufficio funzionante per soddisfare un tunnel è di solito uno scambio peggiore che dare a ogni servizio pubblicato un indirizzo distinto che il tunnel può trasportare. Il progetto qui sotto pubblica un servizio HTTPS per sito e nient'altro.
Perché la sovrapposizione non è il vero problema
WireGuard inoltra per destinazione: gli AllowedIPs di un peer decidono quale peer riceve un pacchetto. Due peer non possono annunciare entrambi 10.10.7.0/24 senza che uno dei due vinca ogni ricerca. È una proprietà della tabella dei peer e non del tunnel, per questo la soluzione qui è un piano di indirizzi e non un trucco di routing.
Il piano è smettere del tutto di annunciare la LAN. Annunciate invece un alias per servizio, un indirizzo per sito, e lasciate che il gateway di ogni sito traduca quell'alias nella sua applicazione reale.
L'utente instrada due indirizzi unici, non vede mai il prefisso ambiguo, e nulla cambia in nessuno dei due uffici. Questo dice anche il confine con onestà: state pubblicando un servizio HTTPS da ogni sito, non fondendo due reti. Le regole che seguono restano piccole perché l'affermazione è stretta. Un'affermazione più ampia richiederebbe regole più ampie, ed è così che questi progetti diventano complicati.
Date a ogni sito un alias che l'utente possa instradare
Scegliete indirizzi da una gamma che non sia in conflitto con nulla sulla macchina dell'utente, sull'hub o su una delle due LAN. Qui l'hub è 10.66.0.1, l'utente è 10.66.0.10, i gateway sono 10.66.0.21 e 10.66.0.22, e i due alias sono 10.77.1.20 e 10.77.2.20. L'hub pubblica ogni alias attraverso il peer che lo possiede, quindi un pacchetto in uscita indirizzato a un alias può uscire solo dal sito corrispondente:
[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
Il lato utente ha bisogno solo dei due alias, il che mantiene la configurazione del client libera da entrambi i prefissi LAN. Nulla in quella configurazione menziona una delle LAN reali:
[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
Ogni gateway annuncia l'hub e l'origine dell'utente, nient'altro, così un sito non impara mai la LAN dell'altro. Il keepalive mantiene una mappatura NAT sull'uplink del sito; non autorizza il traffico, e il firewall decide comunque cosa viene ammesso. Copiare la configurazione di un gateway nell'altro va bene purché la chiave privata, l'indirizzo dell'interfaccia e l'alias cambino tutti.
Cosa deve consentire l'hub tra due dei suoi peer
L'hub inoltra pacchetti tra due dei suoi peer, che è una decisione della catena forward e non una decisione di input. Abilitate l'inoltro IPv4 tramite il meccanismo abituale della piattaforma, poi consentite esattamente le coppie di cui il progetto ha bisogno.
La regola qui sotto consente all'utente un alias e una porta, e permette il traffico di ritorno tramite il connection tracking. Scarta tutto il resto sul percorso forward, e questo è il punto:
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
Due dettagli meritano di essere detti perché causano guasti silenziosi. Un accept in una catena base non annulla un drop in un'altra, quindi fondete questo con la politica esistente invece di caricarlo accanto. E l'indirizzo di origine identifica il dispositivo, non la persona; tenete l'autenticazione dell'applicazione separata dall'ammissione di rete.
Dove un alias diventa un indirizzo reale
Il sito A riceve una richiesta per 10.77.1.20, riscrive la destinazione verso l'applicazione reale e riscrive l'origine verso il proprio indirizzo LAN così che la risposta possa tornare senza una rotta verso il tunnel. Fare entrambe le traduzioni in un solo posto tiene il resto della rete all'oscuro dell'alias. Le regole qui sotto sono tutto il meccanismo:
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 politica forward del sito A deve poi ammettere il flusso tradotto dall'interfaccia del tunnel all'interfaccia LAN, più la direzione di ritorno. L'hook forward vede la destinazione dopo la traduzione di destinazione e prima della riscrittura dell'origine, per questo la regola nomina l'indirizzo dell'applicazione reale. Leggete questi due hook in quell'ordine ogni volta che una regola sembra non corrispondere a nulla. Una regola forward scritta contro l'alias non può mai corrispondere, perché l'alias non esiste più in quell'hook.
Il sito B ripete questo con il proprio alias e la propria chiave. Non deve riutilizzare la chiave privata del sito A, perché due peer che condividono un'identità sono un errore di configurazione difficile da vedere e facile da creare copiando un file. Mantenete i due documenti del gateway identici tranne i valori che devono differire, così la differenza salta all'occhio in revisione. Un file copiato è l'origine abituale di quel difetto.
La riscrittura dell'origine ha un costo. L'applicazione vede il gateway come proprio client, quindi i suoi log non mostrano più quale utente si è connesso. Conservate la traccia di audit del gateway, e non indebolite il login dell'applicazione per compensare un'identità di rete che la traduzione ha rimosso.
Come dimostrare che entrambi i nomi pubblicati rispondono
Date a ogni alias un nome DNS e configurate l'applicazione e il certificato per quel nome, perché la traduzione non riscrive i reindirizzamenti né gli URL assoluti incorporati. Usate un nome per sito così che una discordanza di certificato non possa mai essere scambiata per un guasto di routing.
Provate dal client reale, confermate quale sito ha risposto, e provate anche una porta non autorizzata. Usate nuove connessioni dopo ogni modifica NAT, perché lo stato stabilito conserva la vecchia mappatura:
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 vuoto o inatteso nel primo comando significa che la selezione del peer è sbagliata prima ancora che conti una regola firewall. Se l'alias è corretto e il nome continua a fallire, il problema si è spostato su DNS e certificati. Quando entrambi i nomi rispondono e la terza porta resta chiusa, il progetto fa ciò che afferma: due servizi pubblicati in modo stretto, non due LAN fuse.