Een client belt de OpenVPN-server op een Compute Engine-VM, het statusvenster meldt verbonden, en een ping naar een host in de VPC komt nog steeds nergens aan. De neiging is om nog een push-regel toe te voegen, en dat lost het nooit op. Compute Engine bepaalt waar pakketten heen gaan op basis van zijn eigen routetabel en van de adressen die een VM-interface werkelijk heeft, dus een tunnelpool die de VM niet bezit is een pool waar niemand naartoe levert.

Volg het falende pakket in plaats van het configuratiebestand, en de ontbrekende stukken verschijnen in volgorde.

Begin bij het pakket dat sterft

Het SYN verlaat de client, komt in de tunnel terecht en bereikt de VM als een ingekapseld pakket voor een bestemming in de VPC. OpenVPN pakt het uit en probeert het via eth0 door te sturen, waar de fabric eerst een vraag stelt: bezit deze instantie het bestemmingsadres. Een tunnelpool die uit het subnet van iemand anders is gesneden, zakt voor die vraag, en het pakket wordt weggegooid voordat er ook maar een route of firewallregel wordt geraadpleegd.

De richting van client naar VPC heeft dus twee aparte vereisten, en geen van beide is een push-richtlijn. De VM heeft een aliasbereik nodig dat de tunnelpool dekt, en dat is wat haar een rechtmatige eigenaar van die adressen maakt. De VPC heeft een route nodig die de VM voor elk beschermd prefix als next hop noemt. Mis er een en het pakket sterft op een andere plek, terwijl de client dezelfde stilte ziet.

Lees de storing in die volgorde, want vanaf de clientkant zien de twee voorwaarden er identiek uit. Een tunnel die verbonden meldt terwijl niets antwoordt, is het kenmerk van een topologieprobleem en niet van een slechte cipher.

Bezit de instantie de tunnelpool

Geef de VM een secundair bereik binnen zijn eigen subnet en laat OpenVPN adressen precies uit dat bereik uitdelen. Op een instantie met primair adres 10.156.0.10/20 houdt een /28-alias de pool gescheiden van de adressen die andere instanties al hebben:

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

De server-richtlijn moet dan hetzelfde blok beschrijven. Het eerste adres wordt de tunnelgateway en de overige adressen worden aan clients uitgegeven. Twee getallen beschrijven hier een blok, een netwerk en een netmasker, en dat is de poolsyntaxis die OpenVPN nog verwacht.

server 10.156.1.0 255.255.255.240

Controleer of het adres echt op de interface is beland en niet alleen in de OpenVPN-configuratie staat. De fabric stuurt door wat de NIC meldt, niet wat de daemon gelooft. Een commando beslist het:

ip -4 addr show dev eth0

Een secundair adres dat eth0 nooit bereikt, of een pool die een ander subnet overlapt, verschijnt later als sporadisch wegvallen en niet als een opstartfout. De daemon start, clients verbinden, en alleen sommige bestemmingen gedragen zich verkeerd. Houd het aliasbereik klein zodat de pool in een routetabel herkenbaar blijft. Snijd het nooit uit een subnet dat een andere instantie al gebruikt.

Geef het retourverkeer een next hop

Een antwoord van een host in de VPC is geadresseerd aan een clientadres in de tunnelpool, dat bij geen enkel subnet hoort dat de VPC kent. Zonder route voor die pool stopt het antwoord bij de eerste hop zonder treffer, en het verzoek kan aan de andere kant best zijn geslaagd.

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

Dezelfde route is nodig voor elk prefix dat achter een client ligt in plaats van in de VPC. Die prefixen hebben ook een iroute-regel nodig in het ccd-bestand van die client. Die regel is boekhouding aan de serverkant: hij vertelt de server welke client het prefix bezit, en hij installeert niets op de client zelf.

Houd de push-lijst voor de clientkant van het gesprek, want die voegt alleen routes toe aan de verbindende machine. Een push-regel voor een VPC-subnet en een VPC-route terug naar de pool zijn twee helften van hetzelfde pad, en elke helft alleen levert een tunnel op die verzoeken draagt maar geen antwoorden.

Firewalls, forwarding en de hops ertussen

De VPC-firewall beoordeelt het uitgepakte pakket, dus een ingress-regel moet de tunnelpool toelaten en elk siteprefix dat de VM langs die weg bereikt. Een default-deny-houding faalt hier stil: het pakket wordt na het uitpakken weggegooid en het OpenVPN-log toont een gezonde sessie.

Controleer op elke Linux-host die doorstuurt in plaats van termineert of net.ipv4.ip_forward is ingeschakeld. De eigendomsregel geldt daar ook: een machine die doorstuurt voor een subnet dat hij niet heeft, gooit het pakket net zo weg als de VM. Lees de waarde voordat u de tunnel de schuld geeft.

Wanneer precies een prefix faalt

Gedeeltelijk falen is het gemakkelijkst te lezen geval, omdat al het andere in het pad al bewezen is. Begin bij de routelijst en lees het bestemmingsbereik en de next hop van de regel die het prefix zou moeten dekken, lees dan de instantiebeschrijving en vergelijk het aliasbereik met de pool die de server uitgeeft.

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

Een ontbrekende route uit zich als geen next hop voor het prefix, terwijl een ontbrekende alias zich uit als een pakket dat bij de interface wordt weggegooid; vanaf de client lijken de twee op elkaar en in die twee uitvoer zijn ze volstrekt verschillend. Als beide aanwezig zijn, is de resterende verdachte de ccd-iroute voor de client die het prefix claimt.

Schrijf de vier waarden naast de tunnel: aliasbereik, serverpool, gepushte prefixen, VPC-routes. Een verouderde alias breekt elk pooladres, een verouderde route breekt een richting, een ontbrekende push verbergt het prefix voor de client, en een verkeerde iroute stuurt het prefix naar de verkeerde peer. De volgende persoon die een subnet toevoegt heeft alle vier op een plek nodig, en de notitie is goedkoper dan de avond.

Gerelateerde artikelen