Impedire ai client VPN di raggiungersi tra loro sul tunnel
Raggiungere un servizio è una rotta, raggiungere un altro client è una politica. Trovate il punto di inoltro che decide il traffico tra pari, poi dimostrate il blocco da un client.
Due client possono entrambi aprire l’host di salto e non avere comunque alcun motivo di aprirsi a vicenda. Raggiungere un servizio è una decisione di inoltro, mentre raggiungere un pari è una decisione di politica, e la maggior parte degli stack VPN le tiene in oggetti separati. Nulla di ciò che configurate per la prima impone la seconda. Il compito non è quindi aggiungere una regola, ma trovare l’oggetto che decide il traffico tra pari su questo server, scrivervi il blocco e dimostrarlo da un client.
Una rotta verso il servizio condiviso non è un permesso tra pari
Annunciare la sottorete dei client dice a un pari come mettere un pacchetto sul filo verso l’indirizzo di un altro client. Se quel pacchetto verrà consegnato si decide dopo, da ciò che lo inoltra. Su un gateway Linux è la catena FORWARD; dentro un demone in spazio utente è la tabella delle sessioni del tunnel stesso. Una rotta risponde alla raggiungibilità e lascia intatto il permesso.
Per questo un controllo di isolamento che legge solo le rotte non dimostra nulla. Una /24 può essere inviata a ogni client mentre ogni pacchetto tra pari viene scartato all’uncino di inoltro. Il caso pericoloso è l’opposto: nessuna regola esplicita, un valore predefinito permissivo e un isolamento che esiste solo perché nessuno l’ha provato.
Scrivete il requisito in una riga prima di aprire un terminale. Raggiungete il blocco dei servizi e l’host di salto, non raggiungete nient’altro dentro il blocco dei client.
Scoprite chi inoltra davvero il pacchetto tra pari
Due comportamenti del server sembrano uguali dal lato client e richiedono regole diverse. O il kernel inoltra di nuovo il pacchetto fuori dall’interfaccia del tunnel, oppure il demone lo copia tra sessioni e il kernel non lo vede mai.
WireGuard appartiene al primo gruppo: non ha alcun commutatore tra pari, quindi un pacchetto da 10.8.0.4 a 10.8.0.5 arriva su wg0, colpisce l’uncino di inoltro e viene instradato di nuovo fuori da wg0 quando AllowedIPs copre entrambi gli indirizzi. OpenVPN è il secondo gruppo appena client-to-client è impostato nella configurazione del server, perché quella direttiva consegna il pacchetto tra sessioni in spazio utente. Controllate la configurazione caricata per quella direttiva prima di scrivere qualsiasi cosa. Una regola del kernel che non vede mai traffico è indistinguibile da una regola che funziona, ed è così che un rilascio finisce senza alcun isolamento.
Leggete la configurazione effettiva invece del file che supponete caricato, perché i pacchetti delle distribuzioni portano le proprie inclusioni. Se il demone fa l’inoltro, il blocco appartiene ai suoi controlli per client, e un firewall dell’host filtra solo il traffico indirizzato all’host. Se il kernel inoltra, l’uncino di inoltro è l’unico punto che conta.
I rilasci instradati e tradotti richiedono un controllo in più: la sorgente che vede un client remoto potrebbe non essere quella che vi aspettate. Allora una regola che corrisponde alla sottorete dei client non corrisponde a nulla. Annotate l’indirizzo che sopravvive alla traduzione prima di scrivere la corrispondenza, e preferite far corrispondere la coppia di interfacce invece di indovinare indirizzi NAT.
Date a ogni indirizzo un’identità revocabile da sola
L’isolamento crolla appena due dispositivi condividono una credenziale. Una regola legata a quell’identità non può separarli, e revocare un portatile smarrito revoca l’intero gruppo. Certificati per dispositivo o chiavi per pari mantengono la revoca locale e la politica leggibile, perché ogni indirizzo corrisponde esattamente a una persona o macchina. Dove il progetto non può farlo, ditelo nel runbook invece di descrivere la regola come granulare.
L’assegnazione degli indirizzi deve concordare con la politica. Riservate un blocco per i servizi, un blocco per i client, e distribuite indirizzi dei client da un pool che controllate invece che da un intervallo del primo arrivato. Se il server traduce o fa da ponte, tenete la tabella di mappatura accanto alla configurazione, perché è quella che serve al lettore successivo per ricavare di nuovo la regola.
Mettete il blocco dove il pacchetto attraversa il tunnel
Su un gateway che inoltra traffico WireGuard, due regole coprono il caso: consentite il blocco dei servizi, poi scartate il resto del blocco dei client. La coppia di interfacce conta quanto gli indirizzi, perché una corrispondenza solo sulla destinazione cattura anche il traffico in arrivo dalla LAN. Caricatele in quest’ordine perché il permesso sia valutato per primo.
Con nftables la coppia entra in una tabella inet filter esistente, prima il permesso e poi lo scarto. Entrambe le corrispondenze fissano la coppia di interfacce oltre agli indirizzi.
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
Rileggete la catena dopo il caricamento invece di fidarvi dello stato di uscita, e confermate che entrambe le regole stiano nell’ordine voluto. Aggiungete regole ip6 corrispondenti per il pool IPv6, altrimenti la coppia v4 è solo decorativa su un tunnel a doppio stack. Se il server ha già una politica di inoltro permissiva, aggiungete lo scarto invece di sostituire l’intera catena.
Quando client-to-client è attivo su OpenVPN, queste regole di inoltro non corrispondono mai al traffico tra pari e il blocco deve vivere nei controlli propri del demone. Mantenete le regole del kernel per il traffico indirizzato all’host, ma non contatele come controllo di isolamento.
Dimostrate il blocco da un client, non dal server
Provare dal gateway non dimostra nulla, perché il traffico generato localmente prende il percorso di uscita e non attraversa mai l’uncino di inoltro. Usate due client reali: uno che dovrebbe raggiungere il servizio e uno che dovrebbe essere rifiutato. Eseguite prima il caso consentito, così un tunnel rotto non venga scambiato per una politica funzionante.
Dal client consentito, confermate che il servizio risponde sulla sua porta. Dallo stesso client, provate l’indirizzo del pari e aspettatevi uno scarto silenzioso invece di un rifiuto:
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 pacchetto scartato e un pari offline sembrano entrambi un timeout, quindi controllate i contatori prima di concludere qualcosa. Confermate che il contatore della regola di scarto aumenti mentre il pari è dimostrabilmente attivo. Ripetete su IPv6, dove una regola ip6 mancante lascia il blocco v4 come se fosse efficace. Annotate i risultati accettati e rifiutati nel runbook con la data, perché la prossima migrazione ricondurrà la regola.