Kuidas suunata ainult Dockeri konteinerite liiklust läbi OpenVPN-i
Jätke host oma tavalisse ühendusse ja pange üks konteineri alamsuhtlus tunnelisse: NAT-i järjekord, allikareeglid, OpenVPN iroute ja MSS-kontrollid.
Konteineri pakett ei jõua kunagi tun0-ni ja konteineri lisavõimed ei muuda seda. Külalise ja tunneli vahel on kaks marsruudiotsingut: üks külalise võrgu nimeruumi sees, teine hostis pärast seda, kui kaader sillale maandub, ja teine küsib teist tabelit teistsuguste vastendusreeglitega. Minu võrdluspaigutus on Linuxi host, kus töötab OpenVPN klient, mis hoiab 10.8.0.10 aadressil tun0, Dockeri sild aadressil 172.18.0.0/16, ja privaatne aadress, kuhu pääseb ainult tunneli pool. Eesmärk jääb kitsaks: see külalise alamsuhtlus väljub tunneli kaudu, samal ajal kui host hoiab oma tavalist ühendust.
VPN-kliendi käivitamine konteineri sees on teine lahendus, mitte otsetee. Siis kuulub tunnel ja volitused konteinerile ning töö liigub Dockerfile'i, selle asemel et jääda iptablesi.
Edasisaatmine valib marsruudi sihtkoha järgi, seejärel kirjutab NAT allika ümber
Kui on seatud net.ipv4.ip_forward=1, suunatakse edasisaadetud pakett ainult sihtkoha järgi, põhitabelis. Allikas ei mängi selles otsuses rolli. Alles pärast marsruudi valimist käivitab tuum POSTROUTING ja just seal asub Dockeri enda reegel: -s 172.18.0.0/16 ! -o br-appnet -j MASQUERADE. Kõik, mis lahkub sillalt teise liidese suunas, tõlgitakse, ja aadress, milleks see saab, sõltub liidesest, kuhu marsruut selle saatis.
See reegel selgitab enamikku sümptomitest, mille kohta mult küsitakse. Kui põhitabelis pole privaatse sihtkoha jaoks marsruuti, väljub pakett ühenduse kaudu hosti füüsilise aadressiga. Teie teenusepakkuja viskab sihtkoha ära või kaugsaait viskab ära RFC 1918 allika, mida ta ei oodanud, ja konteiner jookseb ajast üle, samal ajal kui tunnel püsib üleval ja terve. Püüdmine tun0 peal ei näita midagi ja see ongi vihje. Kui marsruut siiski osutab tun0 peale, kirjutab MASQUERADE allika ümber 10.8.0.10 peale ja sama konteiner töötab, ilma et te midagi puutuksite.
Küsige otsingut, mis nimetab külalise allikat. Ilma from ja iif vastab host omaenda sokli eest ja teatab tee, mida edasisaadetud pakett kunagi ei võta:
ip route get 192.168.11.222 from 172.18.0.5 iif br-appnetKui see vastus nimetab ühendust, pole tunnel pildil ja ükski tunneli poolne seade ei aita.
Viige külaline tunneli enda aadressile
Väikseim toimiv muudatus on selgesõnaline allika ümberkirjutus väljumisel. Sisestage see, mitte ärge lisage lõppu: Docker istub juba POSTROUTING eesotsas, seega -A ga lisatud reegel hinnatakse Dockeri oma järel ja ei rakendu kunagi.
iptables -t nat -I POSTROUTING 1 -s 172.18.0.0/16 -o tun0 -j SNAT --to-source 10.8.0.10Kaks tingimust otsustavad, kas see püsib. Aadress peab olema selline, mida klient tõesti hoiab, seega kinnitage see iga kliendi kirjega, mis sisaldab ifconfig-push 10.8.0.10 255.255.255.0; reegel, mis nimetab aadressi, mida kunagi ei määratud, tekitab vaikseid kõrvaldamisi, mitte viga. Ja kaugpool peab selle allika vastu võtma ning vastused tagasi suunama, seepärast nimetab sealne lubatud nimekiri tunneli aadressi, mitte külalise alamsuhtlust. Kui kliendi aadress on dünaamiline, -j MASQUERADE koos -o tun0 järgib seda, mida liides hoiab, kuid see maksab kaugpoliitika arvelt, mille vastu te fikseeritud väärtust kirjutada ei saa.
Filtreerimine on teine pool. Docker seab FORWARD poliitika drop peale ja tühjendab igal deemonitaaskäivitusel ketid, mida ta omab, seega pange kohalik poliitika DOCKER-USER sisse, mis jääb püsima:
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 ACCEPTTagasireegel on oluline: tun0 peale saabuvat vastust ei võeta silla avatud ühenduse jaoks vastu ainult seetõttu, et väljuv suund oli.
Hoidke host otse allikareegliga
Kui kogu sild peaks tunnelit kasutama, aga miski muu hostis mitte, jätke NAT vahele ja andke sellele allikale oma tabel. Külalise aadressid jäävad siis otsast otsani nähtavaks.
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 vpnboxReegleid vaadatakse enne põhitabelit ja from vastab allikale. Tunneli enda välised paketid kannavad hosti füüsilist allikat, seega ei vasta need kunagi from 172.18.0.0/16 le ja tunnel ei saa end tagasi iseendasse suunata. Just see eneseväljajätmine teeb paigutuse stabiilseks.
Vastusetee vajab nüüd abi. Kaugpool näeb tõlkimata 172.18.0.x ega tea, kus see asub. Serveris on iga kliendi failil vaja iroute 172.18.0.0 255.255.0.0, et serveri sisemine tabel annaks selle prefiksi sellele kliendile, ja lükatud route 172.18.0.0 255.255.0.0, et teised kliendid teaksid, et see on olemas.
Kaks kontrolli enne usaldamist. Käivitage ip route show default: koos redirect-gateway def1 hoiab tabel 0.0.0.0/1 ja 128.0.0.0/1 kaudu tun0, ja host pole üldse otsene, sest need poolvaikimisi marsruudid võidavad ilma default asendamata. Reeglid, mis on lisatud ip rule add ga, kaovad samuti taaskäivitusel, seega kandke neid up-skriptis.
Paketi suurus on teine tõrge, millega kokku puutute
1500-baidine sillaliides annab tunnelile rohkem, kui see kanda jaksab, kui välised UDP- ja IP-päised lisanduvad. Väikesed vahetused lähevad läbi, seega DNS laheneb ja TLS-i kätlus lõpeb, seejärel jääb suurem üleslaadimine kinni ilma ühegi veata. Saatja kordab ikka sama segmendi suurust, sest ICMP teade fragmenteerimise vajadusest, mis ütleks tal vähendada, ei jõua kunagi kohale.
Parandage see liidesel, MSS-i juures või mõlemas. Klammerdamine ei vaja külalise kaasabi:
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-pmtuKlammerdamine kirjutab ümber ainult TCP. UDP, sealhulgas QUIC, vajab selle asemel madalamat külalise liidest, kasutades --opt com.docker.network.driver.mtu=1400 võrgu loomisel või vastavat compose-võtit.
DNS ja kontrollid, mida tasub korrata
Nimede lahendamine järgib sama teed. Dockeri sisseehitatud resolver 127.0.0.11 juures edastab hosti seadistatud serveritele, seega konteiner pärib selle, mida host kasutab. Kui privaatsele tsoonile vastab ainult tunnelist kättesaadav resolver, suunake külaline sellele aadressile ja katsetage getent hosts abil konteineri sees, mitte hostis.
- Käivitage ebaõnnestuv päring külalise sees; hostipoolne katse kasutab teist allikaaadressi ja peidab probleemi.
- Lugege lisatud NAT- ja filtriteeglite loendureid. Null vastetega reegel on marsruutimise viga, mitte poliitika viga.
- Kinnitage, et teie SNAT-reegli tunneli aadress on see, mida klient tõesti hoiab.
- Langetage külalise MTU-d või klammerdage MSS, enne kui süüdistate serverit tõrkes.
Minge nimekirja mööda ja peatuge esimese tõrke juures. Just see kiht tuleb parandada; kõik, mis lisatakse veel allpool, peidab ainult piiri, mis murdub.