Dlaczego kontener Dockera nie dociera do hostów za VPN
Kontenery w sieci mostkowej mają własną przestrzeń nazw, więc tunel hosta jest dla nich niewidoczny. Porównaj sieć hosta, urządzenie tun i macvlan, zanim zmienisz DNS.
Kontener, który nie dociera do niczego za firmowym VPN, zwykle żyje w innej przestrzeni nazw sieci niż tunel. Trasy, serwery DNS i znaczniki zapory klienta hosta należą do stosu hosta; kontener w sieci mostkowej ma własny. Ten jeden fakt wyjaśnia większość zgłoszeń, które trafiają do zespołu platformy, i jest też powodem, dla którego „VPN jest zepsuty” i „Docker omija VPN” mogą być jednocześnie nieprawdziwe. Za jednym objawem kryją się dwie bardzo różne konfiguracje, więc ustal, którą masz, zanim zmienisz jakiekolwiek ustawienie.
Ustal, do kogo należy przestrzeń nazw tunelu
W Docker Desktop dla macOS lub Windows kontenery działają wewnątrz maszyny wirtualnej Linux. Klient VPN zainstalowany na pulpicie tworzy tunel w systemie operacyjnym pulpitu, a maszyna wirtualna nigdy go nie widzi. Żadna konfiguracja kontenera tego nie naprawi, ponieważ interfejs, którego kontener potrzebowałby, w ogóle nie istnieje w jego przestrzeni nazw sieci.
Na hoście Linux tunel żyje w przestrzeni nazw hosta, a kontenery mostkowe zwykle docierają do niego przez tablicę routingu hosta z NAT-em źródłowym stosowanym na wyjściu. Gdy ta ścieżka zawodzi, przyczyną jest zwykle polityka przekazywania, filtrowanie odwrotnej ścieżki lub nakładająca się podsieć, a nie brakująca trasa. Potwierdź, w którym z dwóch światów jesteś, zanim przeczytasz dalej:
docker info --format '{{.OperatingSystem}}'
docker run --rm --net=host alpine ip route | head -5
docker run --rm alpine ip route | head -5
Różnica między tymi dwiema tablicami routingu to cały problem na jednym ekranie. Jeśli widok hosta zawiera interfejs tunelu, a widok mostu nie, patrzysz na izolację przestrzeni nazw, a wszystko inne jest wyborem, jak ją przekroczyć.
Sieć hosta to test, nie projekt
Uruchomienie kontenera z siecią hosta, którą Docker dokumentuje jako współdzielenie przestrzeni nazw sieci hosta, powoduje, że dziedziczy on bezpośrednio interfejs tunelu i jego trasy. Jeśli to samo żądanie wtedy się powiedzie, teoria tras jest potwierdzona, a awarią jest izolacja przestrzeni nazw, nie poświadczenia, DNS ani reguła dostępu.
docker run --rm --net=host curl -sS -o /dev/null -w '%{http_code}\n' https://api.internal/health
Zachowaj to jako diagnostykę. Sieć hosta rezygnuje z publikowania portów i większości izolacji, której chciałeś od kontenera, a w Docker Desktop „host” oznacza maszynę wirtualną, nie pulpit, więc sukces lub porażka tam może cię zmylić, jeśli zapomnisz, do którego hosta się zwracałeś.
Urządzenie tun i towarzyszące mu uprawnienia
Klient VPN wewnątrz kontenera potrzebuje urządzenia tunelowego i pozwolenia na jego konfigurację. Typowym skrótem jest --privileged, który przyznaje każde urządzenie i łagodzi politykę bezpieczeństwa w całym kontenerze. To znacznie więcej, niż wymaga to zadanie, i trudno to uzasadnić w przeglądzie.
sudo modprobe tun
docker run --rm -it --device /dev/net/tun --cap-add NET_ADMIN myvpn-client
Węższa forma mapuje pojedynczy węzeł urządzenia i dodaje tylko możliwość administracji siecią. Najpierw wczytaj moduł na hoście, aby węzeł istniał. Jeśli kontener się uruchomi, a klient zgłosi, że nie może otworzyć urządzenia tunelowego, sprawdź mapowanie, zanim podejrzysz profil, ponieważ ten błąd jest zwykle dosłowny.
Ten projekt oznacza też, że klient działa dla każdego kontenera. To właściwa odpowiedź, gdy każde obciążenie potrzebuje własnego tunelu, i niewłaściwa, gdy chciałeś tylko, aby tunel hosta był widoczny, co zespół platformy prawdopodobnie zakładał, że robisz.
NAT mostu zmienia źródło, które widzi VPN
Przy domyślnym moście ruch wychodzący kontenera jest tłumaczony na adres hosta. Dlatego za VPN strona firmowa widzi adres tunelu hosta, a nie kontenera, reguły dostępu według źródła zachowują się tak, jakby żądanie wysłał host, a dwa kontenery stają się nierozróżnialne dla serwera VPN.
macvlan lub ipvlan zamiast tego daje kontenerowi adres LAN, co pomaga w wykrywaniu w sieci LAN i sprawia, że kontener wygląda jak równorzędny w segmencie. Omija też całkowicie tunel hosta, więc taki kontener nie dotrze do prefiksów tylko-VPN, chyba że VPN jest osiągalny również z tej sieci LAN.
Obie formy są uzasadnione; odpowiadają na różne wymagania. Jeśli wymaganiem jest „ten kontener musi docierać do usługi tylko-VPN”, wybierasz między routingiem przez hosta a zakończeniem tunelu wewnątrz kontenera. Zapisz ten wybór przed wdrożeniem, nie po pierwszym nieudanym żądaniu. Cokolwiek wybierzesz, zanotuj adres źródłowy, który zobaczy drugi koniec, bo właśnie to pokażą jego reguły dostępu i jego logi. Projekt, który nie potrafi podać tego adresu, nie jest gotowy.
DNS podąża za demonem, nie za tunelem
Kontener otrzymuje konfigurację resolvera przy starcie, skopiowaną z demona lub z obrazu. Adresy, które VPN wypycha po połączeniu, przychodzą zbyt późno dla tej kopii i są wypychane do resolvera hosta, a nie do kontenera.
Ustaw resolver jawnie dla usługi albo wskaż go na wewnętrzny resolver osiągalny przez tunel. Kontener, który rozwiązuje prywatną nazwę na publiczny adres, zwykle używa publicznego resolvera, a nie cierpi z powodu zepsutej trasy, i poprawka należy do pliku compose lub konfiguracji demona.
To samo rozumowanie dotyczy kwestii adresu wyjściowego. Jeśli każdy kontener musi pojawiać się z innego adresu VPN, jeden tunel hosta nie może tego zapewnić, ponieważ NAT sprowadza je do jednego źródła. Działające formy to klient w przestrzeni nazw każdego kontenera lub sidecar, który posiada tunel i dzieli swój stos, i oba zmieniają sposób adresowania aplikacji.
Lista kontrolna przed zamknięciem zgłoszenia: ustal przestrzeń nazw, która posiada tunel, udowodnij ścieżkę siecią hosta, zamapuj tylko potrzebne urządzenie tun, zapamiętaj adres źródłowy po NAT, ustaw resolver jawnie i traktuj adresy wyjściowe dla kontenera jako decyzję architektoniczną, a nie flagę.