OpenVPN podas Kubernetes aplinkoje nieko nepersiunčia? Patikrinkite ip_forward
Klientai pingina VPN podą ir toliau nieko. Namespace'e persiuntimas išjungtas, o pataisa turi išgyventi admission, perkrovimus ir grįžimo kelią.
Jūsų nešiojamasis kompiuteris rodo žalią tunelį, kliento žurnalas praneša, kad maršrutai buvo įstumti, o vienintelis atsakantis adresas yra paties VPN serverio tunelio IP. Pingai už jo miršta, kad ir į ką taikytumėte, ar tai ClusterIP, kito podo adresas, ar viešas prieglobos vardas. Šis derinys yra diagnostinis, o ne neaiškus: dekapsuliavimas veikia, o antrasis šuolis ne.
Su tuo susidūriau Debian mazge, kuriame veikė per chart įdiegtas OpenVPN atvaizdas, ir tunelis buvo lengvoji dalis. Klientas gavo 10.8.0.x nuomą, 10.8.0.1 atsakė, o 10.96.0.10, klasterio DNS paslauga, baigėsi laiku. Serverio žurnale niekas neatrodė sergantis, ir būtent todėl žmonės pradeda perrašinėti iptables taisykles, kurių niekada nereikėjo liesti.
VPN podas yra maršrutizatorius, ir verta tai pasakyti tiesiai. Užšifruoti paketai atvyksta, išvyniojami pačiame podo tinklo namespace'e, o tada turi išeiti kitu sąsaja. Linux atsisako šio antro žingsnio, nebent persiuntimas įjungtas tame pačiame namespace'e.
Ką klientas gali pasiekti, o ko ne
Atsakantis adresas priklauso tunelio galiniam taškui, o VPN procesas jį valdo vietiškai, todėl persiuntimas visiškai nedalyvauja. Visa kita, įskaitant kitą podą, paslaugos VIP ar internetą, reikalauja, kad branduolys perkeltų paketą iš tun0 į eth0. Kai tas perkėlimas atmetamas, simptomas yra vienoda tyla, o ne atmetimas, nes niekas negeneruoja ICMP klaidos atgal tuneliu. Gaunate skirtuosius laikus, o ne nepasiekiamumo pranešimus, ir tai yra užuomina, kad niekas apskritai nemaršrutizuoja.
Dvi minutės klasifikavimo susiaurina sluoksnį. Jei DNS vardai nepavyksta, o neapdoroti pingai į paslaugos IP pavyksta, problema yra DNS vamzdynuose, o ne persiuntime. Jei kiekviena paskirties vieta už peer adreso baigiasi laiku, įskaitant pliką IP, pradėkite nuo namespace'o.
Perskaitykite nustatymą namespace'o viduje
Kiekvienas podas gauna savo tinklo namespace'ą, o net.ipv4.ip_forward yra sysctl kiekvienam namespace'ui. Jo keitimas mazge nieko nepasako apie konteinerį, ir tai patikimas būdas praleisti popietę netinkamoje mašinoje.
kubectl exec -it deploy/openvpn -- sysctl net.ipv4.ip_forward
# net.ipv4.ip_forward = 0
Nulis patvirtina diagnozę. Reikšmė taip pat nepaveldima iš mazgo vykdymo konfigūracijos: ji prasideda nuo atvaizdo numatytosios vertės kiekvieną kartą kuriant konteinerį. Todėl rankiniu būdu su kubectl exec ... sysctl -w pritaikyta pataisa išnyksta kitą kartą perkraunant ir grįžta kaip gedimas, kuris atrodo protarpinis.
Įjungti taip, kad manifestas ją išlaikytų
Patvarus variantas yra init konteineris, kuris veikia tame pačiame pod sandbox'e ir įrašo reikšmę prieš startuojant VPN konteineriui. Konteineriai pode dalijasi tinklo namespace'u, todėl nustatymas pereina į pagrindinį konteinerį.
initContainers:
- name: enable-forwarding
image: busybox:1.36
command: ["sysctl", "-w", "net.ipv4.ip_forward=1"]
securityContext:
privileged: true
Būtent privileged: true yra eilutė, dėl kurios recenzentai prieštarauja, ir jie teisūs. Rašyti sysctl reikia arba privilegijos, arba siaurai apibrėžto gebėjimo, o klasteris su ribotu Pod Security Standard gali tiesiog atsisakyti privilegijuoto init konteinerio. Jei admission atmeta podą, apie tai sužinote kūrimo metu, o tai bent jau sąžininga ir lengva skaityti.
Švaresnė alternatyva yra podo lygio securityContext.sysctls sąrašas, leidžiantis kubelet'ui taikyti namespace'inius sysctl ne suteikiant privilegijų nė vienam konteineriui. Jis apima tik klasterio leidžiamų sąrašo vardus. Ar net.ipv4.ip_forward yra tame sąraše, priklauso nuo to, kaip buvo sukonfigūruotas kubelet, o podas, prašantis sysctl už jo ribų, atmetamas admission metu arba įstringa CreateContainerConfigError, kol sandbox'as bandomas iš naujo. Patikrinkite leidžiamų sąrašą prieš manydami, kad laukas sugedęs.
Prieš kurdami rankiniu būdu bet kurį iš dviejų metodų, pažiūrėkite, ar chart jau atskleidžia jungiklį, dažnai kaip kažką panašaus į ipForwardInitContainer: true. Chart vertės naudojimas palieka jūsų override failą mažą ir išgyvena kitą atnaujinimą, ko rankiniu būdu pataisyti Deployment pakeitimai nepadaro.
Antroji pusė: grįžimo kelias ir politika
Įjungtas persiuntimas yra būtinas, bet nepakankamas. Jei klientai naudoja privatų baseiną, kuriam klasterio tinklas neturi maršruto, atsakymai neranda kelio atgal į tunelį, ir podas turi maskuoti tą srautą savo paskirties link.
Politika yra ant viršaus. NetworkPolicy objektai ir debesijos užkardos taisyklės vertinami pagal šaltinio adresą, kurį paketas neša po vertimo, todėl klientų baseinui parašyta taisyklė gali tyliai nustoti atitikti, kai įjungiamas maskavimas.
Kai klientams reikia pasiekti tik paslaugas klasterio viduje, VPN užbaigimas paslaugos VIP yra mažesnis dizainas nei maršrutizavimas į podų tinklą. Jis taip pat visiškai laiko klientų baseiną už CNI maršrutų lentelės.
Atskirti nepavykusį šuolį nuo kliento
Dirbkite į išorę ir sustokite ties pirmuoju tyliu žingsniu. Pradėkite nuo VPN peer, tada pabandykite kokio nors podo adresą, tada paslaugos VIP, ir tik po to viešą paskirties vietą. Kiekviena sėkmė perkelia ribą vienu šuoliu, o kiekviena nesėkmė įvardija sluoksnį, kurį verta apžiūrėti. Po bet kurio diegimo įeikite su exec ir dar kartą perskaitykite sysctl, nes pakeistas podas pradeda nuo atvaizdo numatytosios vertės, o pataisa, kurios niekada nebuvo manifeste, jau dingusi.
Kubernetes dokumentacija apie sysctl naudojimą klasteryje išvardija, kuriuos vardus galima nustatyti per podo saugos kontekstą, ir tai yra pirmoji vieta, kur reikia žiūrėti, kai admission atmeta pakeitimą.