Zašto Docker kontejner ne može doći do hostova iza VPN-a
Bridge kontejneri imaju vlastiti namespace, pa im je hostov tunel nevidljiv. Usporedite host networking, tun uređaj i macvlan prije nego što mijenjate DNS.
Kontejner koji ne može doći ni do čega iza korporativnog VPN-a obično živi u drugom mrežnom namespaceu od tunela. Rute, DNS serveri i firewall oznake hostovog klijenta pripadaju hostovom stacku; bridge kontejner ima svoj. Ta jedna činjenica objašnjava većinu prijava koje stižu do platformskog tima, a i razlog je zašto «VPN je pokvaren» i «Docker zaobilazi VPN» mogu istovremeno biti netočni. Dvije vrlo različite postavke kriju se iza jednog simptoma, zato utvrdite koju imate prije nego što promijenite postavku.
Utvrdite čiji namespace posjeduje tunel
Na Docker Desktopu za macOS ili Windows kontejneri rade unutar Linux virtualnog stroja. VPN klijent instaliran na radnoj površini stvara tunel u operativnom sustavu radne površine, a virtualni stroj ga nikada ne vidi. Nijedna konfiguracija kontejnera to ne popravlja, jer sučelje koje bi kontejner trebao uopće ne postoji u njegovom mrežnom namespaceu.
Na Linux hostu tunel živi u hostovom namespaceu, a bridge kontejneri do njega obično dolaze kroz hostovu tablicu usmjeravanja sa source NAT-om primijenjenim na izlazu. Kada taj put zakaže, uzrok je obično politika prosljeđivanja, filtriranje obrnutog puta ili preklapajuća podmreža, a ne ruta koja nedostaje. Potvrdite u kojem se od dva svijeta nalazite prije nego što čitate dalje:
docker info --format '{{.OperatingSystem}}'
docker run --rm --net=host alpine ip route | head -5
docker run --rm alpine ip route | head -5
Razlika između tih dviju tablica usmjeravanja cijeli je problem na jednom ekranu. Ako hostov prikaz sadrži tunelsko sučelje, a bridge prikaz ne, gledate izolaciju namespacea i sve ostalo je izbor kako je prijeći.
Host networking je test, a ne dizajn
Pokretanje kontejnera s host networkingom, što Docker dokumentira kao dijeljenje hostovog mrežnog namespacea, čini da izravno naslijedi tunelsko sučelje i njegove rute. Ako isti zahtjev zatim uspije, teorija ruta je potvrđena, a kvar je izolacija namespacea, a ne vjerodajnice, DNS ili pravilo pristupa.
docker run --rm --net=host curl -sS -o /dev/null -w '%{http_code}\n' https://api.internal/health
Zadržite to kao dijagnostiku. Host networking odriče se objavljivanja portova i većine izolacije koju ste htjeli od kontejnera, a na Docker Desktopu «host» znači virtualni stroj, ne radnu površinu, pa vas uspjeh ili neuspjeh tamo može zavesti ako zaboravite kojem hostu ste se obraćali.
tun uređaj i privilegije koje dolaze s njim
VPN klijent unutar kontejnera treba tunelski uređaj i dopuštenje da ga konfigurira. Uobičajeni prečac je --privileged, koji daje svaki uređaj i ublažava sigurnosnu politiku kroz cijeli kontejner. To je daleko više nego što ovaj posao traži i teško je opravdati na pregledu.
sudo modprobe tun
docker run --rm -it --device /dev/net/tun --cap-add NET_ADMIN myvpn-client
Uža forma mapira jedan čvor uređaja i dodaje samo mogućnost mrežne administracije. Najprije učitajte modul na hostu kako bi čvor postojao. Ako kontejner krene, a klijent javi da ne može otvoriti tunelski uređaj, provjerite mapiranje prije nego posumnjate u profil, jer je ta pogreška obično doslovna.
Ovaj dizajn također znači da klijent radi za svaki kontejner. To je točan odgovor kada svaki radni teret treba vlastiti tunel, a pogrešan kada ste samo htjeli da hostov tunel bude vidljiv, što je platformski tim vjerojatno pretpostavljao da radite.
Bridge NAT mijenja izvor koji VPN vidi
S zadanim bridgeom izlazni promet kontejnera prevodi se na hostovu adresu. Iza VPN-a korporativna strana zato vidi hostovu tunelsku adresu, a ne kontejnerovu, pravila pristupa po izvoru ponašaju se kao da je zahtjev poslao host, i dva kontejnera postaju nerazlučiva VPN serveru.
macvlan ili ipvlan umjesto toga daje kontejneru LAN adresu, što pomaže otkrivanju u LAN-u i čini da kontejner izgleda kao ravnopravan na segmentu. Također u potpunosti zaobilazi hostov tunel, pa takav kontejner neće doći do prefiksa samo za VPN, osim ako je VPN dostupan i iz tog LAN-a.
Oba oblika su legitimna; odgovaraju na različite zahtjeve. Ako je zahtjev «ovaj kontejner mora doći do usluge samo za VPN», birate između usmjeravanja kroz host i završavanja tunela unutar kontejnera. Zapišite taj izbor prije postavljanja, ne nakon prvog neuspjelog zahtjeva. Što god odabrali, zabilježite izvornu adresu koju će udaljena strana vidjeti, jer upravo to pokazuju njezina pravila pristupa i njezini zapisi. Dizajn koji ne može navesti tu adresu nije dovršen.
DNS slijedi daemon, a ne tunel
Kontejner dobiva konfiguraciju resolvera pri pokretanju, kopiranu iz daemona ili iz slike. Adrese koje VPN pošalje nakon spajanja stižu prekasno za tu kopiju i šalju se hostovom resolveru, a ne u kontejner.
Postavite resolver izričito za uslugu ili ga usmjerite na interni resolver dostupan kroz tunel. Kontejner koji privatno ime razrješava na javnu adresu obično koristi javni resolver, a ne pati od pokvarene rute, i popravak pripada u compose datoteku ili konfiguraciju daemona.
Isto razmišljanje vrijedi za pitanje izlazne adrese. Ako se svaki kontejner mora pojavljivati s različite VPN adrese, jedan hostov tunel to ne može isporučiti jer ih NAT sažima u jedan izvor. Izvedivi oblici su klijent u namespaceu svakog kontejnera ili sidecar koji posjeduje tunel i dijeli svoj stack, i oba mijenjaju način adresiranja aplikacije.
Kontrolni popis prije zatvaranja tiketa: utvrdite namespace koji posjeduje tunel, dokažite put s host networkingom, mapirajte samo potreban tun uređaj, zapamtite izvornu adresu nakon NAT-a, postavite resolver izričito i tretirajte izlazne adrese po kontejneru kao arhitektonsku odluku, a ne zastavicu.