Ang container na hindi umabot sa anuman sa likod ng corporate VPN ay karaniwang nakatira sa ibang network namespace kaysa sa tunnel. Ang mga ruta, DNS server at firewall mark ng host client ay kabilang sa stack ng host; ang bridge-network container ay may sarili. Ang nag-iisang katotohanang ito ang nagpapaliwanag sa karamihan ng ulat na dumarating sa isang platform team, at ito rin ang dahilan kung bakit «sira ang VPN» at «nilalampasan ng Docker ang VPN» ay maaaring parehong mali nang sabay. Dalawang magkaibang setup ang nagtatago sa likod ng isang sintomas, kaya tukuyin kung alin ang mayroon ka bago magbago ng anumang setting.

Alamin kung kaninong namespace ang tunnel

Sa Docker Desktop para sa macOS o Windows, tumatakbo ang mga container sa loob ng isang Linux virtual machine. Ang VPN client na naka-install sa desktop ay gumagawa ng tunnel sa operating system ng desktop, at hindi ito nakikita ng virtual machine. Walang container configuration ang makakapag-ayos nito, dahil ang interface na kakailanganin ng container ay wala talaga sa network namespace nito.

Sa isang Linux host, ang tunnel ay nakatira sa namespace ng host, at ang mga bridge container ay karaniwang umaabot dito sa pamamagitan ng routing table ng host na may source NAT na inilalapat sa paglabas. Kapag nabigo ang rutang iyon, ang dahilan ay karaniwang forwarding policy, reverse-path filtering o isang magkapatong na subnet kaysa sa nawawalang ruta. Kumpirmahin kung alin sa dalawang mundo ka naroroon bago magbasa pa:

docker info --format '{{.OperatingSystem}}'
docker run --rm --net=host alpine ip route | head -5
docker run --rm alpine ip route | head -5

Ang pagkakaiba ng dalawang routing table na iyon ang buong problema sa isang screen. Kung ang view ng host ay naglalaman ng tunnel interface at ang view ng bridge ay wala, tinitingnan mo ang namespace isolation, at ang lahat ng iba ay pagpili kung paano ito tatawirin.

Ang host networking ay isang pagsubok, hindi isang disenyo

Ang pagpapatakbo ng container na may host networking, na idinodokumento ng Docker bilang pagbabahagi ng network namespace ng host, ay nagpapamanhid dito nang direkta ng tunnel interface at mga ruta nito. Kung ang parehong kahilingan ay magtagumpay pagkatapos, kumpirmado ang teorya ng ruta at ang pagkabigo ay namespace isolation, hindi mga kredensyal, DNS o isang access rule.

docker run --rm --net=host curl -sS -o /dev/null -w '%{http_code}\n' https://api.internal/health

Panatilihin itong diagnostic. Ang host networking ay tumatanggap sa port publishing at sa karamihan ng isolation na gusto mo mula sa isang container, at sa Docker Desktop ang «host» ay nangangahulugang ang virtual machine, hindi ang desktop, kaya ang tagumpay o pagkabigo doon ay maaaring magligaw sa iyo kung nakalimutan mo kung aling host ang iyong tinutugunan.

Isang tun device at ang mga pribilehiyong kasama nito

Ang VPN client sa loob ng container ay nangangailangan ng tunnel device at pahintulot na i-configure ito. Ang karaniwang shortcut ay --privileged, na nagbibigay ng bawat device at nagpapaluwag sa security policy sa buong container. Iyon ay higit pa sa kailangan ng gawaing ito, at mahirap bigyang-katwiran sa isang review.

sudo modprobe tun
docker run --rm -it --device /dev/net/tun --cap-add NET_ADMIN myvpn-client

Ang mas makitid na anyo ay nagmamapa ng nag-iisang device node at nagdadagdag lamang ng kakayahan sa network administration. I-load muna ang module sa host para umiral ang node. Kung magsimula ang container at iulat ng client na hindi nito mabuksan ang tunnel device, suriin ang mapping bago maghinala sa profile, dahil ang error na iyon ay karaniwang literal.

Ang disenyong ito ay nangangahulugan ding tumatakbo ang client bawat container. Iyon ang tamang sagot kapag ang bawat workload ay nangangailangan ng sariling tunnel, at ang maling sagot kapag gusto mo lamang na makita ang tunnel ng host, na malamang ipinagpalagay ng platform team na ginagawa mo.

Binabago ng bridge NAT ang source na nakikita ng VPN

Sa default na bridge, ang outbound traffic ng container ay isinasalin sa address ng host. Kaya sa likod ng VPN, nakikita ng corporate side ang tunnel address ng host at hindi ang sa container, ang mga access rule per source ay kumikilos na parang ang host ang nagpadala ng kahilingan, at ang dalawang container ay nagiging hindi mapag-iba ng VPN server.

Ang macvlan o ipvlan ay nagbibigay sa container ng LAN address sa halip, na tumutulong sa LAN discovery at ginagawang parang kapantay sa segment ang container. Nilalampasan din nito nang lubusan ang tunnel ng host, kaya ang naturang container ay hindi makakaabot sa VPN-only prefixes maliban kung ang VPN ay maabot din mula sa LAN na iyon.

Parehong lehitimo ang dalawang anyo; sumasagot sila sa magkaibang pangangailangan. Kung ang pangangailangan ay «dapat maabot ng container na ito ang isang VPN-only service», pumipili ka sa pagitan ng pag-route sa host at pagtatapos ng tunnel sa loob ng container. Isulat ang pagpiling iyon bago ang deployment, hindi pagkatapos ng unang nabigong kahilingan. Anuman ang piliin mo, itala ang source address na makikita ng malayong dulo, dahil iyon ang ipapakita ng mga access rule at log nito. Ang disenyong hindi masabi ang address na iyon ay hindi pa tapos.

Sinusundan ng DNS ang daemon, hindi ang tunnel

Ang container ay nakakakuha ng resolver configuration nito sa pagsisimula, kinopya mula sa daemon o mula sa image. Ang mga address na itinutulak ng VPN pagkatapos kumonekta ay dumarating nang huli para sa kopyang iyon, at itinutulak sila sa resolver ng host at hindi sa loob ng container.

Itakda ang resolver nang tahasan para sa serbisyo, o ituro ito sa isang internal resolver na maabot sa pamamagitan ng tunnel. Ang container na niresolba ang isang pribadong pangalan sa isang pampublikong address ay karaniwang gumagamit ng pampublikong resolver, hindi nagdurusa sa sirang ruta, at ang pagwawasto ay nabibilang sa compose file o configuration ng daemon.

Ang parehong pangangatwiran ay nalalapat sa tanong ng exit address. Kung ang bawat container ay dapat lumitaw mula sa ibang VPN address, hindi ito maibibigay ng isang tunnel ng host dahil pinagsasama-sama sila ng NAT sa isang source. Ang mga magagawang anyo ay isang client sa namespace ng bawat container o isang sidecar na nagmamay-ari ng tunnel at nagbabahagi ng stack nito, at binabago ng dalawa kung paano indirihian ang application.

Checklist bago isara ang ticket: tukuyin ang namespace na nagmamay-ari ng tunnel, patunayan ang ruta gamit ang host networking, i-map lamang ang kinakailangang tun device, tandaan ang source address pagkatapos ng NAT, itakda ang resolver nang tahasan at ituring ang exit address per container bilang desisyon sa arkitektura at hindi bandila.

Kaugnay na mga artikulo