OpenVPN pod u Kubernetesu ne prosljeđuje ništa? Provjerite ip_forward
Klijenti pingaju VPN pod i ništa dalje. Namespace ima isključeno prosljeđivanje, a popravka mora preživjeti admission, restarte i povratni put.
Vaš laptop prikazuje zeleni tunel, klijentski log javlja da su rute poslane, a jedina adresa koja odgovara je vlastiti tunelski IP VPN servera. Pingovi dalje umiru bez obzira na to u šta ciljate, bilo da je to ClusterIP, adresa drugog poda ili javno ime hosta. Ta kombinacija je dijagnostička, a ne nejasna: dekapsulacija radi, a drugi hop ne.
Na to sam naišao na Debian čvoru sa OpenVPN imageom instaliranim putem charta, a tunel je bio lakši dio. Klijent je dobio lease 10.8.0.x, 10.8.0.1 je odgovorio, a 10.96.0.10, klaster DNS servis, je istekao. Ništa u serverskom logu nije izgledalo bolesno, i upravo zato ljudi počinju prepisivati iptables pravila koja nikada nisu trebali dirati.
VPN pod je ruter, i to vrijedi reći otvoreno. Šifrovani paketi stižu, raspakuju se u vlastitom mrežnom namespaceu poda, a zatim moraju izaći kroz drugi interfejs. Linux odbija taj drugi korak osim ako je prosljeđivanje omogućeno unutar tog istog namespacea.
Šta klijent može i šta ne može dosegnuti
Adresa koja odgovara pripada tunelskoj krajnjoj točki, a VPN proces je posjeduje lokalno, pa prosljeđivanje uopće nije uključeno. Sve ostalo, uključujući drugi pod, VIP servisa ili internet, zahtijeva da kernel premjesti paket sa tun0 na eth0. Kada je taj prelaz odbijen, simptom je jednolična tišina, a ne odbijanje, jer ništa ne generira ICMP grešku natrag niz tunel. Dobijate timeoutove, a ne poruke o nedostupnosti, i to je znak da niko uopće ne rutira.
Dvije minute klasifikacije sužavaju sloj. Ako DNS imena padaju dok sirovi pingovi na IP servisa prolaze, problem je u DNS vodovodu, ne u prosljeđivanju. Ako svaka destinacija iza adrese peera istekne, uključujući goli IP, počnite od namespacea.
Pročitajte postavku unutar namespacea
Svaki pod dobija vlastiti mrežni namespace, a net.ipv4.ip_forward je sysctl po namespaceu. Mijenjanje na čvoru vam ne govori ništa o kontejneru, i to je pouzdan način da provedete popodne na pogrešnoj mašini.
kubectl exec -it deploy/openvpn -- sysctl net.ipv4.ip_forward
# net.ipv4.ip_forward = 0
Nula potvrđuje dijagnozu. Vrijednost se također ne nasljeđuje iz runtime konfiguracije čvora: počinje od zadanog u imageu svaki put kada se kreira kontejner. Zato popravka primijenjena ručno sa kubectl exec ... sysctl -w nestaje pri sljedećem restartu i vraća se kao kvar koji izgleda povremen.
Omogućiti to tako da manifest to zadrži
Trajna opcija je init kontejner koji radi u istom pod sandboxu i upisuje vrijednost prije nego što se VPN kontejner pokrene. Kontejneri u podu dijele mrežni namespace, pa se postavka prenosi u glavni kontejner.
initContainers:
- name: enable-forwarding
image: busybox:1.36
command: ["sysctl", "-w", "net.ipv4.ip_forward=1"]
securityContext:
privileged: true
Taj privileged: true je linija na koju recenzenti prigovaraju, i s pravom. Pisanje sysctla zahtijeva ili privilegiju ili usko ograničenu sposobnost, a klaster s restriktivnim Pod Security Standardom može privilegirani init kontejner odbiti odmah. Ako admission odbije pod, saznajete u trenutku kreiranja, što je barem iskreno i lako čitljivo.
Čistija alternativa je lista securityContext.sysctls na nivou poda, koja omogućava kubeletu da primijeni namespaced sysctls bez davanja privilegija bilo kojem kontejneru. Pokriva samo imena sa allowlist klastera. Da li je net.ipv4.ip_forward na toj listi zavisi od toga kako je kubelet konfigurisan, a pod koji traži sysctl izvan nje se odbija pri admissionu ili zaglavi u CreateContainerConfigError dok se sandbox ponavlja. Provjerite allowlist prije nego pretpostavite da je polje pokvareno.
Prije nego ručno izgradite bilo koji pristup, pogledajte da li chart već izlaže prekidač, često kao nešto poput ipForwardInitContainer: true. Korištenje vrijednosti iz charta drži vaš override fajl malim i preživljava sljedeći upgrade, što ručno zakrpljene izmjene Deploymenta ne čine.
Druga polovina: povratni put i politika
Uključeno prosljeđivanje je neophodno, ne i dovoljno. Ako klijenti koriste privatni pool za koji klaster mreža nema rutu, odgovori ne mogu naći put natrag u tunel, i pod mora maskirati taj promet prema svojoj destinaciji.
Politika stoji iznad toga. NetworkPolicy objekti i pravila cloud firewalla se ocjenjuju prema izvornoj adresi koju paket nosi nakon translacije, pa pravilo napisano za klijentski pool može tiho prestati da se poklapa kada se maskiranje omogući.
Kada klijenti trebaju dosegnuti samo servise unutar klastera, završavanje VPN-a na VIP-u servisa je manji dizajn od rutiranja u mrežu podova. Također drži klijentski pool potpuno izvan CNI tabele rutiranja.
Izolovati hop koji pada od klijenta
Radite prema van i zaustavite se na prvom tihom koraku. Počnite s VPN peerom, zatim probajte adresu nekog poda, pa VIP servisa, i tek nakon toga javnu destinaciju. Svaki uspjeh pomjera granicu za jedan hop, a svaki neuspjeh imenuje sloj koji vrijedi pregledati. Nakon svakog rollouta uđite i ponovo pročitajte sysctl, jer zamijenjeni pod počinje od zadanog u imageu, a popravka koja nikada nije bila u manifestu je već otišla.
Kubernetes dokumentacija o korištenju sysctls u klasteru navodi koja imena se mogu postaviti kroz sigurnosni kontekst poda, i to je prvo mjesto na koje treba pogledati kada admission odbije promjenu.