Docker-containerverkeer omzeilt de VPN van de host: zo controleert u het
Een host-VPN dekt alleen de netwerknaamruimte van de host. Met deze controles ziet u of verkeer van containers op een bridge de tunnel in gaat of er direct uit gaat.
Uw browser op de host toont het VPN-uitgangsadres, de container meldt uw thuisverbinding en iemand noemt dat een lek. Er is niets gelekt. Een host-tunnel is een bundel interfaces, routes en regels die bij de netwerknaamruimte van de host horen, en een container op een bridge is een andere naamruimte met zijn eigen standaardroute. Ik heb op een Compose-stack gezeten waar de VPN-client wekenlang verbonden was en er nooit één containerpakket in was gekomen.
Controleer de naamruimte vóór het systeemvakpictogram
Naamruimten zijn het hele argument. Wanneer Docker een container op een bridgenetwerk start, maakt het een netwerknaamruimte, hangt het ene uiteinde van een veth-paar erin en geeft die naamruimte een adres en een standaardroute. De tunnelinterface, hoe die ook heet, leeft in de naamruimte van de host. Verkeer in de container kan hem niet zien, en geen enkele clientinstelling verandert dat van buitenaf.
Twee ondersteunde stappen halen u uit de isolatie. --network host plaatst de container in de naamruimte van de host, zodat hij de routes van de host en daarmee de tunnel erft. --network container:vpn deelt de naamruimte van een andere container, en zo sturen de meeste sidecar-ontwerpen een werklast door een VPN-container. Beide zijn expliciete keuzes; meestal is maar één ervan wat de persoon die uitrolt bedoelde.
Hostmodus is geen gratis upgrade. De container heeft geen eigen adres meer, poortpublicatie geldt niet meer, en een proces met NET_ADMIN kan daar de routing van de host herschrijven. Dat accepteren kan de juiste beslissing zijn. Aannemen dat het al aan staat, is hoe mensen een avond besteden aan het debuggen van een tunnel die nooit in het pad lag.
Volg het pakket de bridge af
Een bridgecontainer stuurt zijn pakket naar zijn standaardgateway, dat is de bridge-interface op de host. De host stuurt het pakket vervolgens door en vertaalt in de standaardconfiguratie het bronadres naar het zijne voordat het pakket naar buiten gaat. Juist die vertaalslag ondergraaft het beleid geruisloos.
Tegen de tijd dat het pakket het tunneleindpunt bereikt, draagt het het adres van de host. Elke regel, policyroute of beslissing over een gesplitste tunnel die op het oorspronkelijke adres van de container is gebaseerd, komt niet meer overeen, en twee containers die via verschillende uitgangen naar buiten moeten, zijn niet alleen aan de bron te onderscheiden. Als u routing per container nodig hebt, moet de beslissing vóór de vertaling vallen of in een naamruimte die u beheert.
Docker onderhoudt deze regels zelf, via welke firewallbackend de daemon ook is geconfigureerd. Handgeschreven regels buiten de ondersteunde hook voor doorgestuurd verkeer, DOCKER-USER, kunnen worden herordend of verwijderd wanneer de daemon herstart of de host wordt geüpgraded. De Docker-documentatie over pakketfiltering toont de volgorde van de chains; het praktische punt is dat elke regel een eigenaar nodig heeft en een herlaadpad dat u echt hebt getest.
Test de twee systemen apart
Bewijs uit de ene naamruimte zegt niets over de andere. Een verzoek dat in de VPN-container draait, bewijst dat de tunnel voor die container werkt. Het is geen bewijs over de host, en hetzelfde commando uit een --network host-container is geen bewijs over de 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'
Herhaal de test dan in de echte applicatiecontainer in plaats van een vergelijkbare image. De app kan een extra route, een proxy-omgevingsvariabele of een andere resolver hebben, en elk daarvan verandert het antwoord. Controleer elke keer naamresolutie en de tweede adresfamilie: containers op door de gebruiker gedefinieerde bridges lossen op via de ingebouwde resolver van Docker op 127.0.0.11, en een IPv6-standaardroute op de bridge kan verkeer naar buiten brengen terwijl u bezig bent een tunnel te testen die alleen IPv4 is.
Lees het patroon voordat u inloggegevens aanraakt
Als de host werkt en de container niet, is de oorzaak bijna altijd structureel, en sleutels roteren of de client opnieuw installeren kost een middag. Sorteer eerst het symptoom en de oplossing noemt zich meestal zelf.
| 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 |
De overlapregel verdient een eigen zin. Een VPN-profiel dat een route pusht voor 172.17.0.0/16, of voor een 10.0.0.0/8 die toevallig uw bridge-prefix bevat, zorgt dat de tunnel het containersubnet opeist, en antwoorden naar vertaalde adressen gaan de verkeerde kant op of verdwijnen. Het Docker-netwerk opnieuw nummeren is meestal schoner dan uitzonderingen opstapelen.
Maak de dekking expliciet en breek hem dan expres
Twee ontwerpen doorstaan een review. Deel de naamruimte van de VPN-container en elke gedekte werklast gebruikt één tunnel met één herstartgrens, wat eenvoudig is tot één dienst een andere uitgang of zijn eigen DNS-pad nodig heeft. Of routeer het containernetwerk naar een VPN-gateway op de host: doorsturen aan, de bridge-prefix op de tunnel gericht, retourverkeer expliciet afgehandeld. Dat koopt controle per netwerk en kost u een regelset die u moet onderhouden bij daemon- en clientupgrades.
Hoe dan ook, de test die telt is het faalgeval. Stop de tunnel terwijl een containerverzoek onderweg is en kijk waar het pakket heen gaat. Als het terugvalt op het directe pad, is de dekking nooit afgedwongen, want een kill switch van een client regelt het eigen verkeer van de client en niet doorgestuurde pakketten vanaf een bridge. Herstart daarna de daemon en de host en bevestig het resultaat een tweede keer; dat is het moment waarop handgeschreven regels verdwijnen.
Voordat u het af noemt, bevestigt u vier dingen: de tunnelinterface zit in dezelfde naamruimte als het verkeer, de containertest liep in de echte container, naamresolutie en beide adresfamilies zijn gecontroleerd, en de tunnelfaaltest faalt nog steeds gesloten. Schrijf daarna de firewallbackend, de clientversie en de eigenaar van elke regel op. Die vastlegging is wat voorkomt dat de volgende upgrade een ongedocumenteerde mix van oude aannames achterlaat.