OpenVPN në Docker: kontrata e ekzekutimit që i nevojitet një klienti minimal
Një imazh i shqyrtuar, një profil i mbrojtur, akses TUN dhe NET_ADMIN. Çfarë merr kontejneri, çfarë nuk duhet të marrë dhe si të provohet se tuneli funksionon.
Vendosni një klient VPN në një kontejner dhe merrni një hapësirë emrash me një tunel brenda saj, jo një host që drejton të gjithë trafikun e tij përmes një VPN. Këto janë projekte të veçanta, dhe trajtimi i tyre si një i vetëm është pikërisht mënyra se si kontejnerët përfundojnë të privilegjuar aksidentalisht. Ky udhëzues mbulon vetëm të parin: një imazh i shqyrtuar, një profil i mbrojtur dhe një proces klienti i kufizuar në hapësirën e vet të emrave të rrjetit.
Filloni nga një artefakt që dikush e ka miratuar më parë. Hapat më poshtë supozojnë një imazh që përmban ekzekutuesin openvpn dhe një profil të plotë klienti me certifikatën dhe materialin e çelësit të zgjidhur tashmë brenda montimit. Ata nuk ndërtojnë softuer, nuk lëshojnë kredenciale dhe nuk mbulojnë mjedise pa root as kontejnerë Windows nativë, secili prej të cilëve ndryshon përgjigjen.
Çfarë merr kontejneri dhe çfarë nuk merr
Mbani profilin dhe gjithçka që ai referon në një drejtori lokale me leje të kufizuara, të montuar vetëm për lexim. Rrugët relative brenda profilit duhet të zgjidhen brenda atij montimi; ky është një detaj që njerëzit e humbin kur një certifikatë qëndron një drejtori mbi profilin dhe kontejneri nuk e sheh kurrë.
services:
vpn:
image: ${VPN_CLIENT_IMAGE:?set the reviewed image reference}
cap_add:
- NET_ADMIN
devices:
- /dev/net/tun:/dev/net/tun
volumes:
- ./vpn:/vpn:ro
working_dir: /vpn
entrypoint: ["openvpn"]
command: ["--config", "/vpn/client.ovpn"]
Ai skedar jep tre gjëra dhe nuk kërkon asgjë tjetër. Referenca e imazhit duhet të fiksohet me digest nëse politika e vendosjes suaj thotë kështu, dhe profili duhet të jetë ai i shqyrtuari, jo një kopje që dikush e redaktoi në vend në host.
Vetëm për lexim këtu do të thotë që kontejneri nuk mund të ndryshojë skedarët tuaj në host; nuk do të thotë që kontejneri nuk mund të lexojë çelësin privat që keni montuar. Ky është i gjithë qëllimi i montimit, dhe për këtë arsye lejet e skedarëve, pronësia dhe mënyra se si sekreti mbërriti në host ende kanë rëndësi. Asnjëherë mos kaloni një fjalëkalim në rreshtin e komandës dhe mos e pjekni në një shtresë imazhi, sepse të dyja mbijetojnë në vende që nuk mund t'i pastroni më vonë.
Aftësitë, entrypoint dhe kurthi mes tyre
Nevojiten dy cilësime dhe ato bëjnë punë të palidhura. NET_ADMIN lejon manipulimin e ndërfaqeve dhe rrugëve brenda hapësirës së emrave të kontejnerit. Hyrja e pajisjes /dev/net/tun lejon procesin të hapë fare pajisjen e tunelit. Dhënia e njërës pa tjetrën prodhon një dështim të qartë, gjë që është e përshtatshme: pajisja TUN që mungon dështon gjatë hapjes, ndërsa aftësia që mungon dështon kur klienti përpiqet të konfigurojë ndërfaqen.
Asnjëra prej tyre nuk justifikon privileged: true. Një kontejner i privilegjuar merr të gjitha aftësitë plus akses pajisjesh, dhe kjo është një dhënie shumë më e madhe sesa i nevojitet këtij ngarkese pune. referenca për privilegjet dhe aftësitë e mjedisit të ekzekutimit shpjegon deri ku arrin ajo dhënie. Nëse një chart ose një postim blogu e kërkon, së pari kontrolloni nëse kërkesa ishte në të vërtetë një rrugë pajisjeje që mungon ose një aftësi që mungon.
Anashkalimi i entrypoint është pjesa që kafshon. Thirrja e drejtpërdrejtë e openvpn është e saktë për një imazh të zakonshëm dhe e gabuar për çdo imazh produkti, skripti i nisjes së të cilit përgatit rregulla të murit të zjarrit, skedarë resolver ose kredenciale përpara se të ekzekutojë daemonin. Anashkalimi i atij skripti kalon përgatitjen dhe ju lë të korrigjoni një tunel që u ngrit në një hapësirë emrash gjysmë të konfiguruar.
Ekzekutoni klientin në plan të parë dhe lëreni të jetë procesi kryesor i kontejnerit. Një proces që daemonizohet del menjëherë, kontejneri rinis në cikël, dhe regjistrat që ju nevojiten janë të shpërndarë mes rinisjeve që duken të gjitha njësoj.
Verifikoni nga brenda hapësirës së emrave, jo nga hosti
Ngrini stack-un, konfirmoni në regjistër që klienti arriti një gjendje të lidhur, më pas inspektoni hapësirën e emrave që mban në të vërtetë tunelin.
docker compose up -d
docker compose logs --tail 40 vpn
docker compose exec vpn ip -br addr
docker compose exec vpn ip route
Lista e adresave duhet të tregojë një ndërfaqe tuneli me një adresë nga pishina, dhe tabela e rrugëve duhet të tregojë destinacionet e shtyra që tregojnë drejt saj. Nëse ndërfaqja mungon, klienti nuk arriti kurrë në pikën e krijimit të saj. Nëse ekziston por asnjë rrugë nuk e përdor, vendi për të kërkuar janë push ose opsionet e rrugës.
Më pas provoni destinacionin që ju intereson, nga hapësira e emrave që supozohet të përdorë tunelin, me aplikacionin dhe jo vetëm me ping. Zgjidhja e emrave është një dështim më vete që meriton provë të qartë: një adresë DNS e shtyrë nuk e përditëson vetë resolverin e një kontejneri, dhe një klient autonom që e injoron push-in do t'i zgjidhë emrat përmes asaj që ka konfiguruar imazhi.
Gjendja e shkëputur është pjesë e kontratës
Sjellja e rilidhjes kërkon kontrollin e vet, sepse një politikë rinisjeje provon që procesi riniset dhe nuk thotë asgjë për atë që bën trafiku në mes. Ndaloni tunelin, provoni destinacionin e synuar dhe vëzhgoni nëse lidhja refuzohet, varet ose ka sukses në heshtje përmes rrugës së zakonshme të kontejnerit. Rezultati i fundit është ai që ka rëndësi, dhe është i padukshëm në një regjistër të shëndetshëm.
Nëse ngarkesa e punës nuk duhet të përdorë kurrë rrugën e zakonshme, projektojeni atë në mënyrë eksplicite me rregulla të murit të zjarrit dhe një sinjal gatishmërie brenda hapësirës së emrave. Kill switch është një politikë që ju shkruani dhe provoni, jo një veti që trashëgohet duke ekzekutuar një klient në një kontejner.
Së fundi, mbani mend kufirin: këto rrugë jetojnë në hapësirën e emrave të kontejnerit dhe nuk zëvendësojnë tabelën e rrugëzimit të hostit. Rregullat e përcjelljes, përkthimit dhe murit të zjarrit të Docker mbeten pjesë e rrugës së jashtme, dhe një port i publikuar nuk është ndërfaqe VPN.