Un pod d'OpenVPN a Kubernetes no reenvia res? Comprova ip_forward
Els clients fan ping al pod de la VPN i res més enllà no respon. El namespace té el reenviament desactivat, i la solució ha de sobreviure a l'admission, als reinicis i al camí de tornada.
El teu portàtil mostra un túnel verd, el registre del client diu que s'han empès rutes, i l'única adreça que respon és la IP del túnel del propi servidor VPN. Els pings més enllà moren tant se val a què apuntis, sigui un ClusterIP, l'adreça d'un altre pod o un nom d'amfitrió públic. Aquesta combinació és diagnòstica, no vaga: la desencapsulació funciona, i el segon salt no.
Ho vaig trobar en un node Debian amb una imatge d'OpenVPN instal·lada per chart, i el túnel era la part fàcil. El client va rebre una concessió 10.8.0.x, 10.8.0.1 va respondre, i 10.96.0.10, el servei DNS del clúster, va caducar. Res del registre del servidor no semblava malaltís, i és exactament per això que la gent comença a reescriure regles d'iptables que mai no necessitava tocar.
Un pod de VPN és un encaminador, i val la pena dir-ho clarament. Els paquets xifrats arriben, es desembolcallen al namespace de xarxa propi del pod, i després han de sortir per una interfície diferent. Linux rebutja aquest segon pas tret que el reenviament estigui habilitat dins d'aquell mateix namespace.
Què pot i què no pot assolir el client
L'adreça que respon pertany al punt final del túnel, i el procés de la VPN la posseeix localment, així que no hi intervé cap reenviament. Tota la resta, incloent-hi un altre pod, un VIP de servei o Internet, necessita que el nucli mogui un paquet de tun0 a eth0. Quan aquest moviment es rebutja, el símptoma és un silenci uniforme i no un rebuig, perquè res no genera un error ICMP cap avall pel túnel. Obteniu temps d'espera, no missatges d'inabastable, i aquesta és la pista que ningú no encamina de cap manera.
Dos minuts de classificació estrenyen la capa. Si els noms DNS fallen mentre els pings crus a una IP de servei funcionen, el problema és la fontaneria DNS, no el reenviament. Si tota destinació més enllà de l'adreça del peer caduca, inclosa una IP nua, comenceu pel namespace.
Llegeix el paràmetre dins del namespace
Cada pod rep el seu propi namespace de xarxa, i net.ipv4.ip_forward és un sysctl per namespace. Canviar-lo al node no et diu res del contenidor, i és una manera fiable de passar una tarda a la màquina equivocada.
kubectl exec -it deploy/openvpn -- sysctl net.ipv4.ip_forward
# net.ipv4.ip_forward = 0
Un zero confirma el diagnòstic. El valor tampoc no s'hereta de la configuració d'execució del node: comença pel valor per defecte de la imatge cada vegada que es crea un contenidor. Per tant, una correcció aplicada a mà amb kubectl exec ... sysctl -w desapareix al següent reinici i torna com una fallada que sembla intermitent.
Habilitar-ho perquè el manifest ho conservi
L'opció duradora és un contenidor init que s'executa al mateix pod sandbox i escriu el valor abans que arrenqui el contenidor de la VPN. Els contenidors d'un pod comparteixen un namespace de xarxa, així que el paràmetre passa al contenidor principal.
initContainers:
- name: enable-forwarding
image: busybox:1.36
command: ["sysctl", "-w", "net.ipv4.ip_forward=1"]
securityContext:
privileged: true
Aquest privileged: true és la línia que els revisors qüestionen, i tenen raó. Escriure un sysctl necessita o bé privilegi o bé una capacitat d'abast estret, i un clúster que aplica el Pod Security Standard restringit pot rebutjar de ple un contenidor init privilegiat. Si l'admission rebutja el pod, ho saps en el moment de crear-lo, cosa que almenys és honesta i fàcil de llegir.
L'alternativa més neta és la llista securityContext.sysctls a nivell de pod, que permet al kubelet aplicar sysctls amb namespace sense concedir privilegis a cap contenidor. Només cobreix noms de la llista permesa del clúster. Si net.ipv4.ip_forward hi és depèn de com s'ha configurat el kubelet, i un pod que demana un sysctl fora de la llista és rebutjat a l'admission o es queda atrapat a CreateContainerConfigError mentre es reintenta el sandbox. Comprova la llista permesa abans d'assumir que el camp està trencat.
Abans de construir a mà qualsevol dels dos enfocaments, mira si el chart ja exposa l'interruptor, sovint com una cosa com ipForwardInitContainer: true. Fer servir el valor del chart manté petit el teu fitxer d'override i sobreviu a la propera actualització, cosa que les edicions de Deployment pedaçades a mà no fan.
La segona meitat: camí de tornada i política
El reenviament activat és necessari, no suficient. Si els clients fan servir un pool privat pel qual la xarxa del clúster no té ruta, les respostes no troben el camí de tornada al túnel, i el pod ha d'emmascarar aquest trànsit cap a la seva destinació.
La política se superposa. Els objectes NetworkPolicy i les regles de tallafoc del núvol s'avaluen contra l'adreça d'origen que porta el paquet després de la traducció, així que una regla escrita per al pool de clients pot deixar de coincidir en silenci un cop l'emmascarament està habilitat.
Quan els clients només han d'assolir serveis dins del clúster, fer que la VPN acabi al VIP del servei és un disseny més petit que encaminar cap a la xarxa de pods. També manté el pool de clients completament fora de la taula d'encaminament de la CNI.
Aïllar el salt que falla respecte del client
Treballa cap a fora i atura't al primer pas silenciós. Comença pel peer de la VPN, després prova l'adreça d'algun pod, després un VIP de servei, i només després una destinació pública. Cada èxit mou la frontera un salt, i cada fallada anomena la capa que val la pena inspeccionar. Després de qualsevol desplegament, entra i llegeix el sysctl de nou, perquè un pod substituït comença pel valor per defecte de la imatge i una correcció que mai no era al manifest ja ha desaparegut.
La documentació de Kubernetes sobre l'ús de sysctls en un clúster llista quins noms es poden definir mitjançant el context de seguretat del pod, i és el primer lloc on mirar quan l'admission rebutja el canvi.