Ein Container, der nichts hinter dem Firmen-VPN erreicht, lebt normalerweise in einem anderen Netzwerk-Namespace als der Tunnel. Routen, DNS-Server und Firewall-Markierungen des Host-Clients gehören zum Stack des Hosts; ein Bridge-Container hat seinen eigenen. Diese eine Tatsache erklärt die meisten Meldungen, die ein Plattformteam erreichen, und sie ist auch der Grund, warum „das VPN ist kaputt“ und „Docker umgeht das VPN“ gleichzeitig falsch sein können. Hinter einem Symptom verbergen sich zwei sehr verschiedene Aufbauten, also stellen Sie fest, welchen Sie haben, bevor Sie eine Einstellung ändern.

Finden Sie heraus, wem der Namespace des Tunnels gehört

Unter Docker Desktop für macOS oder Windows laufen Container in einer virtuellen Linux-Maschine. Ein auf dem Desktop installierter VPN-Client erstellt einen Tunnel im Desktop-Betriebssystem, und die virtuelle Maschine sieht ihn nie. Keine Container-Konfiguration behebt das, weil die Schnittstelle, die der Container bräuchte, in seinem Netzwerk-Namespace überhaupt nicht existiert.

Auf einem Linux-Host lebt der Tunnel im Namespace des Hosts, und Bridge-Container erreichen ihn normalerweise über die Routing-Tabelle des Hosts, wobei beim Verlassen Quell-NAT angewendet wird. Wenn dieser Pfad scheitert, ist die Ursache meist Weiterleitungsrichtlinie, Reverse-Path-Filterung oder ein überlappendes Subnetz statt einer fehlenden Route. Bestätigen Sie, in welcher der beiden Welten Sie sich befinden, bevor Sie weiterlesen:

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

Der Unterschied zwischen diesen beiden Routing-Tabellen ist das ganze Problem auf einem Bildschirm. Enthält die Host-Ansicht die Tunnelschnittstelle und die Bridge-Ansicht nicht, sehen Sie Namespace-Isolation, und alles Weitere ist eine Entscheidung darüber, wie man sie überquert.

Host-Netzwerk ist ein Test, kein Entwurf

Einen Container mit Host-Netzwerk zu starten, was Docker als Teilen des Host-Netzwerk-Namespace dokumentiert, lässt ihn die Tunnelschnittstelle und ihre Routen direkt erben. Gelingt dieselbe Anfrage danach, ist die Routentheorie bestätigt, und der Fehler ist Namespace-Isolation statt Anmeldedaten, DNS oder einer Zugriffsregel.

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

Behalten Sie es als Diagnose. Host-Netzwerk gibt die Portveröffentlichung und den größten Teil der Isolation auf, die Sie von einem Container wollten, und unter Docker Desktop bedeutet „host“ die virtuelle Maschine, nicht den Desktop, sodass ein Erfolg oder Misserfolg dort täuschen kann, wenn Sie vergessen, welchen Host Sie ansprachen.

Ein tun-Gerät und die Privilegien, die damit einhergehen

Ein VPN-Client im Container braucht ein Tunnelgerät und die Berechtigung, es zu konfigurieren. Die übliche Abkürzung ist --privileged, das jedes Gerät gewährt und die Sicherheitsrichtlinie im gesamten Container lockert. Das ist weit mehr, als diese Aufgabe verlangt, und in einer Prüfung schwer zu rechtfertigen.

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

Die engere Form bildet den einzelnen Geräteknoten ab und fügt nur die Netzwerkverwaltungsfähigkeit hinzu. Laden Sie das Modul zuerst auf dem Host, damit der Knoten existiert. Wenn der Container startet und der Client meldet, dass er das Tunnelgerät nicht öffnen kann, prüfen Sie die Zuordnung, bevor Sie das Profil verdächtigen, denn dieser Fehler ist meist wörtlich gemeint.

Dieses Design bedeutet auch, dass der Client pro Container läuft. Das ist die richtige Antwort, wenn jede Arbeitslast ihren eigenen Tunnel braucht, und die falsche, wenn Sie nur den Tunnel des Hosts sichtbar haben wollten, was das Plattformteam vermutlich annahm.

Bridge-NAT ändert die Quelle, die das VPN sieht

Mit der Standard-Bridge wird ausgehender Container-Verkehr auf die Host-Adresse übersetzt. Hinter einem VPN sieht die Firmenseite daher die Tunneladresse des Hosts statt der des Containers, Zugriffsregeln pro Quelle verhalten sich, als hätte der Host die Anfrage gestellt, und zwei Container werden für den VPN-Server ununterscheidbar.

macvlan oder ipvlan gibt dem Container stattdessen eine LAN-Adresse, was die LAN-Erkennung unterstützt und den Container wie einen Peer im Segment aussehen lässt. Es umgeht auch den Host-Tunnel vollständig, sodass ein solcher Container Präfixe nur für VPN nicht erreicht, es sei denn, das VPN ist auch aus diesem LAN erreichbar.

Beide Formen sind legitim; sie beantworten unterschiedliche Anforderungen. Lautet die Anforderung „dieser Container muss einen Nur-VPN-Dienst erreichen“, wählen Sie zwischen Routing über den Host und Beenden des Tunnels im Container. Schreiben Sie diese Wahl vor dem Deployment auf, nicht nach der ersten fehlgeschlagenen Anfrage. Was auch immer Sie wählen, notieren Sie die Quelladresse, die die Gegenseite sehen wird, denn genau die zeigen ihre Zugriffsregeln und ihre Protokolle. Ein Design, das diese Adresse nicht nennen kann, ist nicht fertig.

DNS folgt dem Daemon, nicht dem Tunnel

Ein Container erhält seine Resolver-Konfiguration beim Start, kopiert vom Daemon oder vom Image. Adressen, die das VPN nach dem Verbindungsaufbau pusht, kommen für diese Kopie zu spät, und sie werden an den Resolver des Hosts gepusht statt in den Container.

Setzen Sie den Resolver für den Dienst explizit, oder zeigen Sie ihn auf einen internen Resolver, der über den Tunnel erreichbar ist. Ein Container, der einen privaten Namen auf eine öffentliche Adresse auflöst, nutzt meist einen öffentlichen Resolver und leidet nicht unter einer kaputten Route, und die Korrektur gehört in die Compose-Datei oder die Daemon-Konfiguration.

Dieselbe Überlegung gilt für die Frage der Ausgangsadresse. Muss jeder Container von einer anderen VPN-Adresse erscheinen, kann ein Host-Tunnel das nicht liefern, weil NAT sie zu einer Quelle zusammenfasst. Die gangbaren Formen sind ein Client im Namespace jedes Containers oder ein Sidecar, der den Tunnel besitzt und seinen Stack teilt, und beide ändern, wie die Anwendung adressiert wird.

Checkliste vor dem Schließen des Tickets: den Namespace identifizieren, dem der Tunnel gehört, den Pfad mit Host-Netzwerk beweisen, nur das benötigte tun-Gerät zuordnen, die Quelladresse nach NAT merken, den Resolver explizit setzen und Ausgangsadressen pro Container als Architekturentscheidung statt als Flag behandeln.

Ähnliche Artikel