Bærbaren din viser en grønn tunnel, klientloggen melder at ruter ble pushet, og den eneste adressen som svarer, er VPN-serverens egen tunnel-IP. Ping videre dør uansett hva du sikter på, enten det er en ClusterIP, en annen pods adresse eller et offentlig vertsnavn. Den kombinasjonen er diagnostisk og ikke vag: dekapsulering virker, og den andre hoppet gjør det ikke.

Jeg møtte dette på en Debian-node som kjørte et chart-installert OpenVPN-image, og tunnelen var den enkle delen. Klienten fikk en 10.8.0.x-lease, 10.8.0.1 svarte, og 10.96.0.10, klyngens DNS-tjeneste, timet ut. Ingenting i serverloggen så sykt ut, og det er nettopp derfor folk begynner å skrive om iptables-regler de aldri trengte å røre.

En VPN-pod er en ruter, og det er verdt å si rett ut. Krypterte pakker kommer inn, pakkes ut i podens eget nettverksnamespace og må deretter ut gjennom et annet grensesnitt. Linux nekter det andre trinnet med mindre videresending er slått på inne i nettopp det namespace-et.

Hva klienten kan og ikke kan nå

Adressen som svarer, tilhører tunnelens endepunkt, og VPN-prosessen eier den lokalt, så videresending er ikke involvert i det hele tatt. Alt annet, inkludert en annen pod, en tjeneste-VIP eller internett, trenger at kjernen flytter en pakke fra tun0 til eth0. Når den flyttingen nektes, er symptomet ensartet stillhet og ikke en avvisning, fordi ingenting genererer en ICMP-feil tilbake nedover tunnelen. Du får tidsavbrudd, ikke uoppnåelige-meldinger, og det er tegnet på at ingen ruter i det hele tatt.

To minutters klassifisering snevrer inn laget. Hvis DNS-navn feiler mens rå ping mot en tjeneste-IP lykkes, er problemet DNS-røropplegg, ikke videresending. Hvis hver destinasjon utenfor peer-adressen timer ut, også en bar IP, start ved namespace-et.

Les innstillingen inne i namespace-et

Hver pod får sitt eget nettverksnamespace, og net.ipv4.ip_forward er en sysctl per namespace. Å endre den på noden forteller deg ingenting om containeren, og det er en pålitelig måte å bruke en ettermiddag på feil maskin.

kubectl exec -it deploy/openvpn -- sysctl net.ipv4.ip_forward
# net.ipv4.ip_forward = 0

En null bekrefter diagnosen. Verdien arves heller ikke fra nodens kjøretidskonfigurasjon: den starter fra imagets standard hver gang en container opprettes. En rettelse brukt manuelt med kubectl exec ... sysctl -w forsvinner derfor ved neste omstart og kommer tilbake som en feil som virker periodisk.

Slå det på slik at manifestet beholder det

Det varige alternativet er en init-container som kjører i samme pod-sandbox og skriver verdien før VPN-containeren starter. Containere i en pod deler nettverksnamespace, så innstillingen følger med inn i hovedcontaineren.

initContainers:
- name: enable-forwarding
  image: busybox:1.36
  command: ["sysctl", "-w", "net.ipv4.ip_forward=1"]
  securityContext:
    privileged: true

Nettopp privileged: true er linjen anmelderne protesterer mot, og de har rett. Å skrive en sysctl krever enten privilegium eller en smalt avgrenset evne, og en klynge som kjører den restriktive Pod Security Standard kan avvise en privilegert init-container helt. Hvis admission avviser poden, får du vite det ved opprettelsen, noe som i det minste er ærlig og lett å lese.

Det renere alternativet er securityContext.sysctls-listen på pod-nivå, som lar kubelet anvende namespacede sysctler uten å gi privilegier til noen container. Den dekker bare navn på klyngens allowlist. Om net.ipv4.ip_forward står på den listen avhenger av hvordan kubelet ble konfigurert, og en pod som ber om en sysctl utenfor den, avvises ved admission eller henger i CreateContainerConfigError mens sandboxen prøves på nytt. Sjekk allowlisten før du antar at feltet er ødelagt.

Før du bygger noen av tilnærmingene for hånd, se om chartet allerede eksponerer bryteren, ofte som noe i retning av ipForwardInitContainer: true. Å bruke chartverdien holder overstyringsfilen din liten og overlever neste oppgradering, noe håndpatching av Deployment-endringer ikke gjør.

Den andre halvdelen: returvei og policy

Videresending på er nødvendig, ikke tilstrekkelig. Hvis klienter bruker en privat pool som klyngenettet ikke har rute til, finner ikke svar veien tilbake i tunnelen, og poden må maskere den trafikken mot destinasjonen sin.

Policy ligger oppå. NetworkPolicy-objekter og skybrannmurregler vurderes mot kildeadressen en pakke bærer etter oversettelse, så en regel skrevet for klientpoolen kan stille slutte å matche når maskering er slått på.

Når klienter bare trenger å nå tjenester inne i klyngen, er det en mindre konstruksjon å la VPN-en terminere på tjenestens VIP enn å rute inn i podnettet. Det holder også klientpoolen helt utenfor CNI-ens rutetabell.

Isolere det feilende hoppet fra klienten

Arbeid utover og stopp ved det første stille trinnet. Start med VPN-peeren, prøv deretter adressen til en eller annen pod, så en tjeneste-VIP, og først etter det en offentlig destinasjon. Hver suksess flytter grensen ett hopp, og hver feil navngir laget som er verdt å undersøke. Etter enhver utrulling går du inn og leser sysctlen på nytt, fordi en erstattet pod starter fra imagets standard, og en rettelse som aldri var i manifestet, er allerede borte.

Kubernetes-dokumentasjonen om å bruke sysctls i en klynge lister hvilke navn som kan settes gjennom podens sikkerhetskontekst, og det er det første stedet å se når admission avviser endringen.

Relaterte artikler