Un client si collega al server OpenVPN su una VM Compute Engine, la finestra di stato dice connesso, e un ping verso un host nel VPC non arriva comunque da nessuna parte. L’istinto è aggiungere un’altra riga push, e questo non risolve mai. Compute Engine decide dove vanno i pacchetti in base alla propria tabella di routing e agli indirizzi che un’interfaccia della VM detiene davvero, quindi un pool del tunnel che la VM non possiede è un pool a cui nessuno consegna.

Segui il pacchetto che fallisce invece del file di configurazione, e i pezzi mancanti compaiono in ordine.

Partire dal pacchetto che muore

Il SYN lascia il client, entra nel tunnel e raggiunge la VM come pacchetto incapsulato per una destinazione nel VPC. OpenVPN lo decapsula e prova a inoltrarlo da eth0, dove la fabric pone una domanda prima di tutto il resto: questa istanza possiede l’indirizzo di destinazione. Un pool del tunnel ricavato dalla subnet di qualcun altro fallisce quella domanda, e il pacchetto viene scartato prima che qualsiasi route o regola del firewall venga consultata.

La direzione client verso VPC ha quindi due requisiti separati, e nessuno dei due è una direttiva push. La VM ha bisogno di un intervallo alias che copra il pool del tunnel, ed è questo che la rende legittima proprietaria di quegli indirizzi. Il VPC ha bisogno di una route che indichi la VM come next hop per ogni prefisso protetto. Se ne manca uno, il pacchetto muore altrove, mentre il client vede lo stesso silenzio.

Leggi il guasto in quest’ordine, perché dal lato client le due condizioni sono identiche. Un tunnel che dichiara connesso mentre nulla risponde è la firma di un problema di topologia, non di una crittografia scadente.

L’istanza possiede il pool del tunnel

Assegna alla VM un intervallo secondario dentro la sua subnet, poi fai distribuire a OpenVPN indirizzi esattamente da quell’intervallo. Su un’istanza con indirizzo primario 10.156.0.10/20, un alias /28 tiene il pool separato dagli indirizzi che altre istanze detengono già:

gcloud compute instances network-interfaces update openvpn-vm \
  --zone=europe-west1-b \
  --aliases=eth0:10.156.1.0/28

La direttiva server deve quindi descrivere lo stesso blocco. Il suo primo indirizzo diventa il gateway del tunnel, e gli indirizzi rimanenti vengono distribuiti ai client. Qui due numeri descrivono un blocco, una rete e una netmask, ed è la sintassi del pool che OpenVPN si aspetta ancora.

server 10.156.1.0 255.255.255.240

Verifica che l’indirizzo sia davvero finito sull’interfaccia e non solo nella configurazione di OpenVPN. La fabric inoltra ciò che la NIC riporta, non ciò che il demone crede. Un comando basta:

ip -4 addr show dev eth0

Un indirizzo secondario che non raggiunge mai eth0, o un pool che si sovrappone a un’altra subnet, si manifesta più tardi come perdite intermittenti anziché come errore di avvio. Il demone parte, i client si collegano, e solo alcune destinazioni si comportano male. Mantieni piccolo l’intervallo alias così il pool è facile da riconoscere in una tabella di routing. Non ricavarlo mai da una subnet che un’altra istanza usa già.

Dare un next hop al traffico di ritorno

Una risposta da un host del VPC è indirizzata a un indirizzo client nel pool del tunnel, che non appartiene a nessuna subnet conosciuta dal VPC. Senza una route per quel pool, la risposta si ferma al primo hop senza corrispondenza, e la richiesta può benissimo essere riuscita all’altro capo.

gcloud compute routes create openvpn-return \
  --network=prod-vpc \
  --destination-range=192.168.127.0/24 \
  --next-hop-instance=openvpn-vm \
  --next-hop-instance-zone=europe-west1-b \
  --priority=800

La stessa route serve per ogni prefisso che sta dietro un client invece che dentro il VPC. Quei prefissi hanno bisogno anche di una voce iroute nel file ccd di quel client. Quella voce è contabilità lato server: dice al server quale client possiede il prefisso, e non installa nulla sul client stesso.

Tieni la lista push per il lato client della conversazione, perché aggiunge solo route alla macchina che si collega. Una riga push per una subnet del VPC e una route VPC verso il pool sono due metà dello stesso percorso, e una metà da sola produce un tunnel che porta richieste ma non risposte.

Firewall, inoltro e gli hop in mezzo

Il firewall del VPC valuta il pacchetto decapsulato, quindi una regola in ingresso deve ammettere il pool del tunnel e ogni prefisso di sito che raggiunge la VM per quella via. Una postura di default-deny fallisce in silenzio qui: il pacchetto viene scartato dopo la decapsulazione, e il log di OpenVPN mostra una sessione sana.

Su ogni host Linux che inoltra invece di terminare, controlla che net.ipv4.ip_forward sia abilitato. La regola di proprietà vale anche lì: una macchina che inoltra per una subnet che non detiene scarta il pacchetto proprio come farebbe la VM. Leggi il valore prima di dare la colpa al tunnel.

Quando fallisce esattamente un prefisso

Il guasto parziale è il caso più facile da leggere, perché tutto il resto del percorso è già dimostrato. Parti dall’elenco delle route e leggi l’intervallo di destinazione e il next hop della voce che dovrebbe coprire il prefisso, poi leggi la descrizione dell’istanza e confronta il suo intervallo alias con il pool che il server distribuisce.

gcloud compute routes list --filter=destination-range~10.164.0.0
 gcloud compute instances describe openvpn-vm --format=get(networkInterfaces[0].aliasIpRanges)

Una route mancante si mostra come assenza di next hop per il prefisso, mentre un alias mancante si mostra come un pacchetto scartato all’interfaccia; dal lato client le due cose si somigliano e in quei due output sono del tutto diverse. Se ci sono entrambi, il sospetto rimasto è l’iroute ccd del client che rivendica il prefisso.

Annota i quattro valori accanto al tunnel: intervallo alias, pool del server, prefissi push, route VPC. Un alias obsoleto rompe ogni indirizzo del pool, una route obsoleta rompe una direzione, un push mancante nasconde il prefisso al client, e un iroute sbagliato manda il prefisso al peer sbagliato. La prossima persona che aggiunge una subnet ha bisogno di tutti e quattro in un posto solo, e la nota costa meno della serata.

Articoli correlati