Din laptop viser en grøn tunnel, klientloggen siger, at ruter blev pushet, og den eneste adresse, der svarer, er VPN-serverens egen tunnel-IP. Ping videre dør uanset hvad du sigter efter, hvad enten det er en ClusterIP, en anden pods adresse eller et offentligt værtsnavn. Den kombination er diagnostisk snarere end vag: decapsulation virker, og det andet hop gør ikke.

Jeg mødte det på en Debian-node, der kørte et chart-installeret OpenVPN-image, og tunnelen var den nemme del. Klienten fik en 10.8.0.x-lease, 10.8.0.1 svarede, og 10.96.0.10, klyngens DNS-tjeneste, timede ud. Intet i serverloggen så usundt ud, og det er præcis derfor, folk begynder at omskrive iptables-regler, de aldrig havde brug for at røre.

En VPN-pod er en router, og det er værd at sige ligeud. Krypterede pakker ankommer, bliver pakket ud i podens eget netværksnamespace og skal derefter forlade den gennem en anden grænseflade. Linux afviser det andet trin, medmindre videresendelse er aktiveret inde i netop det namespace.

Hvad klienten kan og ikke kan nå

Adressen, der svarer, tilhører tunnelens endepunkt, og VPN-processen ejer den lokalt, så videresendelse er slet ikke involveret. Alt andet, inklusive en anden pod, en tjeneste-VIP eller internettet, kræver, at kernen flytter en pakke fra tun0 til eth0. Når den flytning afvises, er symptomet ensartet tavshed snarere end en afvisning, fordi intet genererer en ICMP-fejl tilbage ned ad tunnelen. Du får timeouts, ikke uopnåelige-meddelelser, og det er tegnet på, at ingen overhovedet router.

To minutters klassificering indsnævrer laget. Hvis DNS-navne fejler, mens rå ping til en tjeneste-IP lykkes, er problemet DNS-rørføring, ikke videresendelse. Hvis hver destination ud over peer-adressen timer ud, inklusive en bar IP, så start ved namespace'et.

Læs indstillingen inde i namespace'et

Hver pod får sit eget netværksnamespace, og net.ipv4.ip_forward er en sysctl pr. namespace. At ændre den på noden fortæller dig intet om containeren, og det er en pålidelig måde at bruge en eftermiddag på den forkerte maskine.

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

Et nul bekræfter diagnosen. Værdien arves heller ikke fra nodens runtime-konfiguration: den starter fra imagets standard, hver gang en container oprettes. En rettelse anvendt manuelt med kubectl exec ... sysctl -w forsvinder derfor ved næste genstart og kommer tilbage som en fejl, der virker periodisk.

Aktivere det, så manifestet beholder det

Den holdbare mulighed er en init-container, der kører i samme pod-sandbox og skriver værdien, før VPN-containeren starter. Containere i en pod deler et netværksnamespace, så indstillingen følger med ind i hovedcontaineren.

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

Den privileged: true er den linje, anmeldere protesterer mod, og de har ret. At skrive en sysctl kræver enten privilegium eller en snævert afgrænset capability, og en klynge, der kører den restriktive Pod Security Standard, kan afvise en privilegeret init-container helt. Hvis admission afviser poden, får du det at vide ved oprettelsen, hvilket i det mindste er ærligt og let at læse.

Det renere alternativ er pod-niveauets securityContext.sysctls-liste, som lader kubelet anvende namespacede sysctls uden at give privilegier til nogen container. Den dækker kun navne på klyngens allowlist. Om net.ipv4.ip_forward er på den liste afhænger af, hvordan kubelet blev konfigureret, og en pod, der beder om en sysctl uden for den, afvises ved admission eller hænger i CreateContainerConfigError, mens sandboxen forsøges igen. Tjek allowlisten, før du antager, at feltet er i stykker.

Før du bygger nogen af tilgangene i hånden, så se, om chartet allerede eksponerer kontakten, ofte som noget i retning af ipForwardInitContainer: true. At bruge chartets værdi holder din override-fil lille og overlever næste opgradering, hvilket håndrettede Deployment-ændringer ikke gør.

Den anden halvdel: returvej og politik

Videresendelse slået til er nødvendigt, ikke tilstrækkeligt. Hvis klienter bruger en privat pool, som klyngenetværket ikke har nogen rute til, kan svar ikke finde vej tilbage i tunnelen, og poden skal maskere den trafik mod sin destination.

Politik ligger ovenpå. NetworkPolicy-objekter og cloud-firewallregler vurderes mod kildeadressen, som en pakke bærer efter oversættelse, så en regel skrevet til klientpoolen kan stille holde op med at matche, når maskering er aktiveret.

Når klienter kun skal nå tjenester inde i klyngen, er det en mindre konstruktion at lade VPN'en terminere ved tjenestens VIP end at route ind i podnetværket. Det holder også klientpoolen helt ude af CNI'ens routingtabel.

At isolere det fejlende hop fra klienten

Arbejd udad og stop ved det første tavse trin. Start med VPN-peeren, prøv derefter en eller anden pods adresse, så en tjeneste-VIP, og først efter det en offentlig destination. Hver succes flytter grænsen et hop, og hver fejl navngiver det lag, der er værd at undersøge. Efter enhver udrulning skal du exec'e ind og læse sysctl'en igen, fordi en udskiftet pod starter fra imagets standard, og en rettelse, der aldrig var i manifestet, er allerede væk.

Kubernetes-dokumentationen om at bruge sysctls i en klynge lister, hvilke navne der kan sættes gennem podens sikkerhedskontekst, og det er det første sted at kigge, når admission afviser ændringen.

Relaterede artikler