Ako smerovať cez OpenVPN len prevádzku kontajnerov Docker
Nechajte host na jeho obvyklom uplinku a vložte do tunela jednu podsieť kontajnerov: poradie NAT, pravidlá zdroja, iroute v OpenVPN a kontroly MSS.
Paket kontajnera sa nikdy nedostane do tun0 , a ďalšie oprávnenia na kontajneri to nezmenia. Medzi hosťom a tunelom stoja dve hľadania trasy: jedno v sieťovom mennom priestore hosťa, jedno na hostiteľovi po tom, čo rámec pristane na moste, a druhé sa pýta inej tabuľky s inými pravidlami zhody. Moje referenčné usporiadanie je Linuxový hostiteľ s OpenVPN klientom, ktorý drží 10.8.0.10 na tun0 , mostom Docker na 172.18.0.0/16 , a privátnou adresou, ku ktorej sa dostane len strana tunela. Cieľ zostáva úzky: tá podsieť hosťa odchádza tunelom, zatiaľ čo hostiteľ si drží obvyklý uplink.
Prevádzkovať VPN klienta vnútri kontajnera je iný návrh , nie skratka. Kontajner potom vlastní svoj tunel aj prihlasovacie údaje a práca sa presúva do Dockerfile namiesto toho, aby zostala v iptables.
Preposielanie vyberá trasu podľa cieľa, potom NAT prepíše zdroj
Keď je nastavené net.ipv4.ip_forward=1 , preposielaný paket sa smeruje len podľa cieľa, v hlavnej tabuľke. Zdroj v tom rozhodnutí nehrá žiadnu úlohu. Až po výbere trasy jadro spustí POSTROUTING , a práve tam sedí vlastné pravidlo Dockeru: -s 172.18.0.0/16 ! -o br-appnet -j MASQUERADE . Všetko, čo opustí most na iné rozhranie, sa preloží, a adresa, ktorou sa stane, závisí od rozhrania, kam ho trasa poslala.
Toto pravidlo vysvetľuje väčšinu príznakov, na ktoré sa ma pýtajú. Ak hlavná tabuľka nemá trasu k privátnemu cieľu, paket opustí uplink s fyzickou adresou hostiteľa. Váš poskytovateľ cieľ zahodí, alebo vzdialená lokalita zahodí zdroj RFC 1918, ktorý nečakala, a kontajneru vyprší čas, kým tunel zostáva hore a zdravý. Zachytenie na tun0 nič neukáže, a to je stopa. Ak trasa skutočne smeruje na tun0 , MASQUERADE prepíše zdroj na 10.8.0.10 , a ten istý kontajner funguje bez toho, aby ste sa čohokoľvek dotkli.
Pýtajte sa na hľadanie, ktoré pomenuje zdroj hosťa. Bez from a iif hostiteľ odpovedá za svoj vlastný socket a hlási cestu, ktorou preposielaný paket nikdy nepôjde:
ip route get 192.168.11.222 from 172.18.0.5 iif br-appnetAk tá odpoveď pomenuje uplink, tunel nie je v hre a žiadne nastavenie na strane tunela nepomôže.
Preveďte hosťa na vlastnú adresu tunela
Najmenšia fungujúca zmena je výslovné prepísanie zdroja na ceste von. Vložte ho, namiesto toho aby ste ho pridávali: Docker už sedí na čele POSTROUTING , takže pravidlo pridané pomocou -A sa vyhodnocuje za tým Dockerovým a nikdy sa nespustí.
iptables -t nat -I POSTROUTING 1 -s 172.18.0.0/16 -o tun0 -j SNAT --to-source 10.8.0.10Dve podmienky rozhodujú, či to vydrží. Adresa musí byť tá, ktorú klient skutočne drží, takže ju pripnite záznamom pre každého klienta obsahujúcim ifconfig-push 10.8.0.10 255.255.255.0 ; pravidlo, ktoré pomenuje adresu, ktorá nikdy nebola pridelená, spôsobí tiché zahadzovanie, nie chybu. A vzdialená strana musí tento zdroj prijať a smerovať odpovede späť, preto zoznam povolených tam pomenúva adresu tunela, nie podsieť hosťa. Keď je adresa klienta dynamická, -j MASQUERADE s -o tun0 nasleduje to, čo má rozhranie, za cenu vzdialenej politiky, proti ktorej nemôžete písať pevnú hodnotu.
Filtrovanie je druhá polovica. Docker nastaví politiku FORWARD na drop a pri každom reštarte démona vyčistí reťazce, ktoré vlastní, preto dajte lokálnu politiku do DOCKER-USER , ktorá prežíva:
iptables -I DOCKER-USER -i br-appnet -o tun0 -j ACCEPT
iptables -I DOCKER-USER -i tun0 -o br-appnet -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPTPravidlo návratu je dôležité: odpoveď prichádzajúca na tun0 pre spojenie otvorené mostom sa neprijme len preto, že smer von bol.
Držte hostiteľa priamo pomocou pravidla zdroja
Keď má celý most používať tunel, ale nič iné na hostiteľovi nie, preskočte NAT a dajte tomu zdroju vlastnú tabuľku. Adresy hosťa potom zostávajú viditeľné od začiatku do konca.
echo "200 vpnbox" >> /etc/iproute2/rt_tables
ip rule add from 172.18.0.0/16 lookup vpnbox pref 1000
ip route add default dev tun0 table vpnboxPravidlá sa konzultujú pred hlavnou tabuľkou a from zodpovedá zdroju. Vlastné vonkajšie pakety tunela nesú fyzickú adresu hostiteľa, takže nikdy nezodpovedajú from 172.18.0.0/16 , a tunel nemôže smerovať sám seba späť do seba. Práve toto sebavylúčenie robí usporiadanie stabilným.
Cesta späť teraz potrebuje pomoc. Vzdialená strana vidí nepreloženú 172.18.0.x a nemá dôvod vedieť, kde býva. Na serveri potrebuje súbor pre každého klienta iroute 172.18.0.0 255.255.0.0 , aby vnútorná tabuľka servera odovzdala tento prefix tomuto klientovi, a pushnutú route 172.18.0.0 255.255.0.0 , aby ostatní klienti vedeli, že existuje.
Dve kontroly, kým tomu uveríte. Spustite ip route show default : s redirect-gateway def1 tabuľka drží 0.0.0.0/1 a 128.0.0.0/1 cez tun0 , a hostiteľ rozhodne nie je priamo, pretože tie polovice predvoleného vyhrávajú bez nahradenia default . Pravidlá pridané pomocou ip rule add tiež miznú pri reštarte, preto ich noste v up skripte.
Veľkosť paketu je druhá porucha, na ktorú narazíte
Most s 1500 bajtmi dá tunelu viac, než unesie, keď sa pridajú vonkajšie hlavičky UDP a IP. Malé výmeny prejdú, takže DNS sa vyrieši a TLS handshake sa dokončí, potom sa väčší upload zasekne bez akejkoľvek chyby. Odosielateľ stále opakuje rovnakú veľkosť segmentu, pretože ICMP správa o potrebe fragmentácie, ktorá by mu povedala zmenšiť, nikdy nepríde.
Opravte to na rozhraní, na MSS alebo oboch. Zovretie nepotrebuje spoluprácu hosťa:
ip link set dev tun0 mtu 1400
iptables -t mangle -A FORWARD -o tun0 -p tcp --tcp-flags SYN,RST SYN -j TCPMSS --clamp-mss-to-pmtuZovretie prepisuje len TCP. UDP, vrátane QUIC, potrebuje namiesto toho znížené rozhranie hosťa, s --opt com.docker.network.driver.mtu=1400 pri vytváraní siete alebo zodpovedajúcim kľúčom compose.
DNS a kontroly, ktoré sa oplatí opakovať
Preklad mien ide tou istou cestou. Vstavaný resolver Dockeru na 127.0.0.11 preposiela na nakonfigurované servery hostiteľa, takže kontajner dedí to, čo hostiteľ používa. Keď privátnu zónu odpovedá len resolver dostupný cez tunel, nasmerujte hosťa na tú adresu, a testujte pomocou getent hosts vnútri kontajnera, nie na hostiteľovi.
- Spustite zlyhávajúcu požiadavku vnútri hosťa; test na strane hostiteľa používa inú zdrojovú adresu a problém skrýva.
- Čítajte počítadlá na NAT a filtračných pravidlách, ktoré ste pridali. Pravidlo s nulovou zhodou je chyba smerovania, nie politiky.
- Potvrďte, že adresa tunela v pravidle SNAT je tá, ktorú klient skutočne drží.
- Znížte MTU hosťa alebo zovrite MSS, skôr než obviníte server zo zaseknutia.
Prejdite zoznam a zastavte sa pri prvej poruche. Práve tá vrstva sa má opraviť; čokoľvek pridané nižšie len skrýva hranicu, ktorá sa láme.