Docker-Portveröffentlichung versus VPN: Wohin die Antwort geht
Ein veröffentlichter Container antwortet von seiner eigenen Adresse, bevor das Reverse-NAT greift. Zwei Entwürfe können diese Antwort auf dem öffentlichen Pfad halten, mit unterschiedlichen Kosten.
Der Host antwortet weiterhin auf SSH, nachdem ein Full-Tunnel-VPN hochgefahren ist, während ein über Docker veröffentlichter Dienst auf derselben Maschine verstummt. Am Listener ist nichts falsch: Der Container läuft, die Portzuordnung existiert, und das Paket kommt an. Der Container ist gesund, und die Anfrage erreicht ihn tatsächlich. Der Unterschied liegt darin, wo die Antwort beginnt, wenn Linux seine Route wählt, und dieser Unterschied entscheidet, welchen der beiden folgenden Entwürfe Sie brauchen.
Verfolgen Sie das Tupel durch das Ziel-NAT
Nehmen Sie einen Host unter 192.0.2.10, der TCP 2222 auf einen Container unter 172.30.240.5:22 veröffentlicht. Eine Anfrage von 198.51.100.25 wird übersetzt, bevor sie den Container erreicht, und der Container antwortet als er selbst.
WAN request: 198.51.100.25 -> 192.0.2.10:2222
after DNAT: 198.51.100.25 -> 172.30.240.5:22
container reply: 172.30.240.5:22 -> 198.51.100.25
Bei der Routenentscheidung des Hosts trägt die Antwort noch die Quelladresse des Containers. Die Rückübersetzung stellt das veröffentlichte Tupel erst später wieder her, und deshalb sieht das Paket genau in dem Moment falsch aus, in dem die Route gewählt wird.
Warum eine reine Host-Regel das verfehlt
Eine Regel, die die WAN-Tabelle nur für Pakete von 192.0.2.10 auswählt, deckt die eigenen Daemons des Hosts ab und verfehlt diese weitergeleitete Antwort vollständig. Die Quelladresse der Antwort ist 172.30.240.5, nicht der Host.
Die Überkorrektur besteht darin, alles vom Container über das WAN zu routen, was auch die unabhängigen ausgehenden Verbindungen des Containers vom VPN ausnimmt. Das ist eine andere Richtlinie als die angeforderte, und es überrascht später meist jemanden.
Post-DNAT-Matching ist ein anderer Hook
Die Docker-Dokumentation zu Firewalls merkt an, dass gewöhnliche Benutzerfilterung das Ziel nach dem DNAT sieht, daher ist das Abgleichen des veröffentlichten Ports 2222 in einer normalen Regel nicht dasselbe wie das Abgleichen des Containerports 22. Wenn das ursprüngliche Tupel zählt, nutzen Sie den unterstützten Mechanismus für das ursprüngliche Ziel, statt zu raten, welcher Port sichtbar ist.
Diese Hook-Verwechslung erzeugt Regeln, die korrekt aussehen und nie greifen. Prüfen Sie die Zähler an der Regel selbst, bevor Sie die Richtlinie umschreiben. Eine Regel ohne Treffer sagt Ihnen, dass sie an einer Stelle ausgewertet wird, die das Paket nie erreicht.
Entwurf A: die Entscheidung als Verbindungszustand tragen
Eine Verbindungsmarkierung kann die Eingangsentscheidung durch die Übersetzung tragen, muss aber vor dem entscheidenden Routen-Lookup wieder am Paket stehen. Die Schritte sind:
- Reservieren Sie ein Markierungsfeld und eine Regelpriorität, die weder mit Docker noch mit dem VPN oder einem anderen Richtlinieninhaber kollidieren.
- Identifizieren Sie nur die beabsichtigte neue WAN-Verbindung an einem Pre-DNAT-Punkt, an dem die Verbindungsverfolgung verfügbar ist.
- Tragen Sie die Entscheidung in der Verbindungsmarkierung ein, ohne die ursprüngliche Anfrage selbst in die WAN-Tabelle zu zwingen.
- Stellen Sie in der Antwortrichtung nur Ihre eigenen Markierungsbits vor dem Routing am Paket wieder her.
- Wählen Sie eine vollständige WAN-Tabelle früh genug, damit keine VPN-Regel zuerst gewinnen kann.
Diese Tabelle braucht die echten verbundenen Routen und das Gateway. Sie braucht außerdem ein definiertes Verhalten, wenn die Route fehlt. Stilles Durchfallen in den Tunnel ist das schlechteste Ergebnis, weil die Konfiguration weiterhin zu funktionieren scheint. Scheitern Sie stattdessen geschlossen und protokollieren Sie es.
Entwurf B: auf dem Host terminieren
Ein bewusst konfiguriertes Frontend auf der Hostseite, etwa ein TCP-Proxy oder ein Reverse-Proxy vor dem Container, hält die Antwort von der Host-Adresse ausgehend. Regeln, die für den Host geschrieben wurden, verhalten sich dann wie erwartet, und der Container bleibt in seinem privaten Netz.
Der Preis ist ein weiteres bewegliches Teil mit eigener Konfiguration, Quelladressbehandlung und Zugriffskontrollen. Es ist meist die einfachere unterstützte Grenze und oft die richtige Antwort, wenn die Routing-Richtlinie von einer Person gepflegt würde, die gehen könnte.
Prüfen Sie die Änderung, nicht die Absicht
Öffnen Sie eine neue autorisierte Verbindung von der öffentlichen Seite und bestätigen Sie, dass die Antwort über die beabsichtigte Schnittstelle abgeht. Prüfen Sie dann, ob eine unabhängige, vom Container gestartete Anfrage weiterhin dem VPN folgt.
Leeren Sie nicht die Verbindungstabelle der Maschine, um eine Regel zu testen: bestehende Einträge behalten ihre frühere Zuordnung, und das Leeren bricht alles andere auf dem Host. Einen Port zu veröffentlichen definiert Erreichbarkeit. Es definiert nicht den Antwortpfad. Schreiben Sie den gewählten Entwurf mit seinen Tabellennamen auf, damit die nächste Person ihn nicht während eines Vorfalls neu entdecken muss.