Warum ein macvlan-Container einem VPN-Client nicht antworten kann
Ein macvlan-Container kann nicht mit seinem eigenen Host sprechen, und seine Antworten können über das falsche Gateway hinausgehen. Fügen Sie eine Shim-Route auf der Hostseite hinzu und wählen Sie dann ein Quellmodell.
Stellen Sie sich einen Linux-Host vor, der ein VPN terminiert und zugleich einen Container in einem macvlan-Netzwerk betreibt. Das LAN ist 192.168.60.0/24, der Container hält 192.168.60.210, und VPN-Clients kommen aus 10.95.0.0/24. Der Client erreicht den Dienst, die Antwort kommt nie zurück, und jede Firewall-Regel auf dem Host sieht korrekt aus. Zwei getrennte Einschränkungen erzeugen dieses Symptom, und wer die eine behebt, lässt die andere bestehen.
Zwei Einschränkungen, ein Symptom
Die erste Einschränkung ist die Isolation: Der macvlan-Treiber von Docker erlaubt einem Container nicht, über die Eltern-Schnittstelle mit seinem eigenen Host zu sprechen. Der Verkehr zwischen dem Host-Stack und dem Container hat keinen Weg, egal wie die Routen auf dem Host geschrieben sind.
Die zweite Einschränkung ist der Rückweg. Das Standard-Gateway des Containers ist meist der LAN-Router, sodass eine Antwort an einen VPN-Client über diesen Router hinausgeht. Hat der Router keine Route zurück in den VPN-Pool, wird die Antwort irgendwo dazwischen verworfen.
Beide Fehler sehen aus Sicht des Clients gleich aus: eine Anfrage kommt an, eine Antwort kommt nie. Sie brauchen unterschiedliche Reparaturen, und eine breite Masquerade-Regel kann verbergen, welche von beiden noch defekt ist. Deshalb ist der erste Test ein Mitschnitt auf der Containerseite und keine weitere Firewall-Änderung. Erscheint die Anfrage dort nie, ist die Isolations-Einschränkung im Spiel.
Den Shim auf der Hostseite eng bauen
Eine zweite macvlan-Schnittstelle auf dem Host, im Bridge-Modus an dieselbe Eltern-Schnittstelle gehängt, gibt dem Host-Stack eine eigene Identität in diesem LAN-Segment. Reservieren Sie ihr eine Adresse außerhalb des DHCP-Pools und außerhalb des Container-Bereichs, und leiten Sie nur den Container darüber.
ip link add macvlan-vpn link eth0 type macvlan mode bridge ip address add 192.168.60.250/32 dev macvlan-vpn ip link set macvlan-vpn up ip route add 192.168.60.210/32 dev macvlan-vpn src 192.168.60.250
Der erste Befehl legt die Schnittstelle im Bridge-Modus an, dem dokumentierten Standard dieses Treibers und dem Modus, den Sie für Verkehr zwischen Host und Container wollen. Der zweite vergibt ein /32, damit die Adresse nicht mit dem LAN-Präfix kollidiert, und der vierte schickt nur die Adresse des Containers über den Shim.
Leiten Sie nicht das ganze LAN über die neue Schnittstelle um. Die gewöhnliche verbundene Route bleibt, wie sie ist, und die Host-Route ist bewusst eng, damit ein Container einen Weg bekommt, ohne dass der Rest des Segments sein Verhalten ändert. Eine Standardroute auf den Shim wäre ein anderes Design mit anderen Folgen. Halten Sie sie spezifisch, dann bleibt der Wirkungsradius klein.
Diese Befehle ändern die Netzwerkkonfiguration auf einem laufenden Host. Auf einer Appliance oder einer verwalteten Plattform nutzen Sie den unterstützten Konfigurationsmechanismus dieser Plattform, denn eine interaktive Änderung über eine Root-Shell überlebt ein Upgrade möglicherweise nicht.
Entscheiden, wie die Quelle erhalten bleibt
Mit dem Shim an Ort und Stelle erreicht der Container den Host, und die Frage wird, welche Quelladresse die Antwort trägt. Die ursprüngliche VPN-Quelle zu erhalten ist das sauberere Modell: Der Container sieht die echte Client-Adresse, und Protokolle und Zugriffsregeln des Dienstes können sie nutzen.
Damit das funktioniert, muss die Netzwerkkonfiguration des Containers für diesen Pfad Verkehr für 10.95.0.0/24 an 192.168.60.250 als Gateway senden. Das ist eine unterstützte Routen- oder Gateway-Einstellung innerhalb der Container-Konfiguration, kein Trick auf der Hostseite. Bestätigen Sie sie von innen im Container, statt anzunehmen, die Einstellung sei wirksam geworden. Ein Standard-Gateway, das weiter auf den LAN-Router zeigt, schickt Antworten weiterhin in dasselbe Loch.
Wenn das freigegebene Design stattdessen die VPN-Quellen verbirgt, fassen Sie die Übersetzung eng: der echte VPN-Pool, der Shim als ausgehende Schnittstelle und der konkrete Container und Dienst.
iptables -t nat -A POSTROUTING -s 10.95.0.0/24 -o macvlan-vpn -j SNAT --to-source 192.168.60.250
Gleichen Sie den Shim als Egress-Schnittstelle ab, nicht den Tunnel. Eine Regel, die den Tunnel als ausgehende Schnittstelle nennt, passt nicht auf ein Paket Richtung Container, und genau dieser Fehler steckt meist in einer solchen Einrichtung. Halten Sie die Regel so eng wie den Satz oben und prüfen Sie sie, wenn sich der Pool ändert.
Vom Client prüfen, nicht vom Host
Eine Anfrage vom Host selbst, gebunden an die Shim-Adresse, beweist, dass der Shim den Container erreicht. Sie beweist nicht, dass der Container Verkehr an eine erhaltene Quelle 10.95.0.x zurückschicken kann, denn die Quelladresse ist in diesem Test die des Shims.
curl -sS --interface 192.168.60.250 -o /dev/null -w '%{http_code}\n' http://192.168.60.210:8080/health
sudo tcpdump -ni macvlan-vpn host 192.168.60.210Der erste Befehl prüft die Strecke vom Host zum Container, und der zweite zeigt, was tatsächlich über den Shim läuft, während ein echter VPN-Client die Anfrage stellt. Achten Sie auf die Quelladresse auf dem Hinweg und darauf, ob eine Antwort mit demselben Flow erscheint.
Auf dem Host muss die Weiterleitung aktiviert sein, und der Weiterleitungspfad braucht eine Freigabe für den VPN-Pool zum Shim auf dem Dienst-Port plus etablierte Antworten. Eine INPUT-Regel auf dem Host genehmigt weitergeleiteten Verkehr nicht, was ein häufiger Grund ist, warum das Paket verworfen wird, nachdem die Routen korrekt aussehen.
Starten Sie die echte Anwendung mit echten Zugangsdaten und prüfen Sie dann, ob ein zweiter, unabhängiger Dienst auf demselben Container Ihnen weiterhin den Zugriff verweigert. Wenn der einzige Weg zum Funktionieren darin bestand, jede Weiterleitungsregel zu öffnen, ist das Design nicht fertig. Notieren Sie außerdem, welche Quelladresse der Dienst aufgezeichnet hat, denn genau die werden seine eigenen Zugriffsregeln künftig verwenden.