Docker-Container-Traffic umgeht das VPN des Hosts: So prüfen Sie es
Ein Host-VPN deckt nur den Netzwerk-Namespace des Hosts ab. Mit diesen Prüfungen finden Sie heraus, ob Container-Traffic über eine Bridge in den Tunnel gelangt oder direkt hinausgeht.
Ihr Browser auf dem Host zeigt die VPN-Austrittsadresse, der Container meldet Ihre Heimverbindung, und jemand nennt das ein Leck. Nichts ist entwichen. Ein Host-Tunnel ist ein Bündel aus Schnittstellen, Routen und Regeln, die zum Netzwerk-Namespace des Hosts gehören, und ein Container auf einer Bridge ist ein anderer Namespace mit seiner eigenen Standardroute. Ich habe auf einem Compose-Stack gesessen, bei dem der VPN-Client wochenlang verbunden war und nicht ein einziges Container-Paket je hineingelangt ist.
Prüfen Sie den Namespace vor dem Tray-Symbol
Namespaces sind das ganze Argument. Wenn Docker einen Container in einem Bridge-Netzwerk startet, legt es einen Netzwerk-Namespace an, hängt ein Ende eines veth-Paars hinein und gibt diesem Namespace eine Adresse und eine Standardroute. Die Tunnelschnittstelle, wie auch immer sie heißt, lebt im Namespace des Hosts. Traffic im Container kann sie nicht sehen, und keine Client-Einstellung ändert das von außen.
Zwei unterstützte Wege holen Sie aus der Isolation. --network host legt den Container in den Namespace des Hosts, sodass er die Routen des Hosts und damit den Tunnel erbt. --network container:vpn teilt den Namespace eines anderen Containers, und so schicken die meisten Sidecar-Designs eine Workload durch einen VPN-Container. Beides sind ausdrückliche Entscheidungen; meist ist nur eine davon das, was die Person beim Deployment gemeint hat.
Der Host-Modus ist kein kostenloses Upgrade. Der Container hat keine eigene Adresse mehr, Port-Veröffentlichung greift nicht mehr, und ein Prozess mit NET_ADMIN kann dort das Routing des Hosts umschreiben. Das zu akzeptieren kann die richtige Entscheidung sein. Anzunehmen, es sei bereits an, ist der Grund, warum Leute einen Abend damit verbringen, einen Tunnel zu debuggen, der nie im Pfad lag.
Folgen Sie dem Paket von der Bridge weg
Ein Bridge-Container schickt sein Paket an sein Standard-Gateway, also die Bridge-Schnittstelle auf dem Host. Der Host leitet das Paket dann weiter und übersetzt in der Standardkonfiguration die Quelladresse in seine eigene, bevor das Paket hinausgeht. Genau dieser Übersetzungsschritt hebelt Richtlinien still aus.
Wenn das Paket den Tunnel-Endpunkt erreicht, trägt es die Adresse des Hosts. Jede Regel, Policy-Route oder Split-Tunnel-Entscheidung, die an der ursprünglichen Adresse des Containers ansetzt, greift nicht mehr, und zwei Container, die über verschiedene Ausgänge hinausgehen sollen, lassen sich allein anhand der Quelle nicht unterscheiden. Wenn Sie Routing pro Container brauchen, muss die Entscheidung vor der Übersetzung oder in einem Namespace fallen, den Sie kontrollieren.
Docker pflegt diese Regeln selbst, über welches Firewall-Backend der Daemon auch immer konfiguriert wurde. Von Hand geschriebene Regeln außerhalb des unterstützten Hooks für weitergeleiteten Traffic, DOCKER-USER, können umsortiert oder verworfen werden, wenn der Daemon neu startet oder der Host aktualisiert wird. Die Docker-Dokumentation zur Paketfilterung zeigt die Reihenfolge der Chains; der praktische Punkt ist, dass jede Regel einen Eigentümer und einen Reload-Pfad braucht, den Sie tatsächlich getestet haben.
Testen Sie die beiden Systeme getrennt
Beweise aus einem Namespace sagen nichts über den anderen. Eine Anfrage im VPN-Container beweist, dass der Tunnel für diesen Container funktioniert. Das ist kein Beweis über den Host, und derselbe Befehl aus einem --network host-Container ist kein Beweis über die Bridge.
# host namespace
ip route get 1.1.1.1
ip -brief addr show
# a fresh container on the same bridge network
docker run --rm --network appnet alpine sh -c 'ip route; cat /etc/resolv.conf; ip -6 route'
Wiederholen Sie den Test dann im echten Anwendungscontainer statt in einem ähnlichen Image. Die App kann eine zusätzliche Route, eine Proxy-Umgebungsvariable oder einen anderen Resolver mitbringen, und jedes davon ändert die Antwort. Prüfen Sie jedes Mal Namensauflösung und die zweite Adressfamilie: Container auf benutzerdefinierten Bridges lösen über Dockers eingebauten Resolver unter 127.0.0.11 auf, und eine IPv6-Standardroute auf der Bridge kann Traffic hinausbefördern, während Sie mit dem Testen eines reinen IPv4-Tunnels beschäftigt sind.
Lesen Sie das Muster, bevor Sie Anmeldedaten anfassen
Wenn der Host funktioniert und der Container nicht, ist die Ursache fast immer strukturell, und Schlüssel zu rotieren oder den Client neu zu installieren kostet einen Nachmittag. Sortieren Sie zuerst das Symptom, und die Lösung benennt sich meist selbst.
| What you see | Usual cause | First check |
|---|---|---|
| Host exits through the VPN, container shows the ISP address | The container never entered the tunnel | Default route inside the container |
| Container works until the daemon restarts, then stops | Rules outside the supported hook, or a changed backend | Daemon's reported firewall backend and DOCKER-USER |
| Container loses internal hosts after the tunnel comes up | VPN prefix overlaps the Docker bridge subnet | ip route on the host, then docker network inspect |
| Small replies arrive, large ones hang | Tunnel MTU or missing MSS clamping | Link MTU on both ends of the tunnel |
| Container falls back to the ISP address when the tunnel drops | Nothing enforces the kill switch for forwarded traffic | Stop the tunnel with a request in flight |
Die Überlappungszeile verdient einen eigenen Satz. Ein VPN-Profil, das eine Route für 172.17.0.0/16 schiebt, oder für ein 10.0.0.0/8, das zufällig Ihr Bridge-Präfix enthält, bringt den Tunnel dazu, das Container-Subnetz zu beanspruchen, und Antworten an übersetzte Adressen laufen in die falsche Richtung oder verschwinden. Das Docker-Netz neu zu nummerieren ist meist sauberer, als Ausnahmen anzuhäufen.
Machen Sie die Abdeckung explizit und brechen Sie sie dann absichtlich
Zwei Entwürfe halten einer Prüfung stand. Teilen Sie den Namespace des VPN-Containers, und jede abgedeckte Workload nutzt einen Tunnel mit einer Neustartgrenze, was einfach ist, bis ein Dienst einen anderen Ausgang oder seinen eigenen DNS-Pfad braucht. Oder leiten Sie das Containernetz zu einem VPN-Gateway auf dem Host: Weiterleitung aktiviert, das Bridge-Präfix auf den Tunnel gerichtet, Rückverkehr ausdrücklich behandelt. Das erkauft Kontrolle pro Netz und kostet Sie ein Regelwerk, das Sie über Daemon- und Client-Upgrades hinweg pflegen müssen.
Wie auch immer, der entscheidende Test ist der Fehlerfall. Stoppen Sie den Tunnel, während eine Container-Anfrage unterwegs ist, und beobachten Sie, wohin das Paket geht. Fällt es auf den direkten Pfad zurück, wurde die Abdeckung nie erzwungen, denn ein Kill-Switch des Clients regelt den eigenen Traffic des Clients und nicht weitergeleitete Pakete von einer Bridge. Starten Sie danach den Daemon und den Host neu und bestätigen Sie das Ergebnis ein zweites Mal; das ist der Moment, in dem von Hand geschriebene Regeln verschwinden.
Bevor Sie es als erledigt bezeichnen, bestätigen Sie vier Dinge: Die Tunnelschnittstelle liegt im selben Namespace wie der Traffic, der Containertest lief im echten Container, Namensauflösung und beide Adressfamilien wurden geprüft, und der Tunnel-Fehlerfall schlägt weiterhin geschlossen fehl. Schreiben Sie dann das Firewall-Backend, die Client-Version und den Eigentümer jeder Regel auf. Dieser Eintrag ist es, der verhindert, dass das nächste Upgrade eine undokumentierte Mischung alter Annahmen hinterlässt.