Schritte zum Begrenzen der externen Verbindungen zum Docker-Container mit iptables?

19

Mein Ziel ist es, den Zugriff auf Docker-Container auf einige wenige öffentliche IP-Adressen zu beschränken. Gibt es einen einfachen, wiederholbaren Prozess, um mein Ziel zu erreichen? Wenn ich nur die Grundlagen von iptables verstehe, während ich die Standardoptionen von Docker verwende, finde ich es sehr schwierig.

Ich möchte einen Container ausführen, ihn für das öffentliche Internet sichtbar machen, aber nur Verbindungen von ausgewählten Hosts zulassen. Ich würde erwarten, eine Standard-INPUT-Richtlinie von REJECT festzulegen und dann nur Verbindungen von meinen Hosts zuzulassen. Aber Dockers NAT-Regeln und -Ketten stören und meine INPUT-Regeln werden ignoriert.

Kann jemand ein Beispiel dafür liefern, wie ich mein Ziel erreichen kann, wenn ich die folgenden Annahmen mache?

  • Host öffentliche IP 80.80.80.80 auf eth0
  • Host private IP 192.168.1.10 auf eth1
  • docker run -d -p 3306:3306 mysql
  • Alle Verbindungen zu Host / Container 3306 mit Ausnahme der Hosts 4.4.4.4 und 8.8.8.8 blockieren

Ich bin froh, den Container nur an die lokale IP-Adresse zu binden, benötige aber Anweisungen zum Einrichten der iptables-Weiterleitungsregeln, die den Docker-Prozess und den Neustart des Hosts überstehen.

Vielen Dank!

GGGforce
quelle

Antworten:

15

Zwei Dinge, die bei der Arbeit mit den Firewall-Regeln von Docker zu beachten sind:

  1. Verwenden Sie die DOCKER-USERKette , um zu vermeiden, dass Ihre Regeln vom Hafenarbeiter überladen werden
  2. Docker nimmt das Port-Mapping in der PREROUTINGKette der natTabelle vor. Dies geschieht also vor den filterRegeln --destund --dportzeigt die interne IP und den Port des Containers an. Um auf das ursprüngliche Ziel zuzugreifen, können Sie verwenden -m conntrack --ctorigdstport.

Beispielsweise:

iptables -A DOCKER-USER -i eth0 -s 8.8.8.8 -p tcp -m conntrack --ctorigdstport 3306 --ctdir ORIGINAL -j ACCEPT
iptables -A DOCKER-USER -i eth0 -s 4.4.4.4 -p tcp -m conntrack --ctorigdstport 3306 --ctdir ORIGINAL -j ACCEPT
iptables -A DOCKER-USER -i eth0 -p tcp -m conntrack --ctorigdstport 3306 --ctdir ORIGINAL -j DROP

HINWEIS: Ohne --ctdir ORIGINALwürde dies auch den Antwortpaketen entsprechen, die für eine Verbindung vom Container zu Port 3306 auf einem anderen Server zurückkommen, was mit ziemlicher Sicherheit nicht das ist, was Sie wollen! Sie brauchen dies nicht unbedingt, wenn wie ich Ihre erste Regel lautet -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT, da dies für alle Antwortpakete gilt, aber es wäre sicherer, sie trotzdem zu verwenden --ctdir ORIGINAL.

SystemParadox
quelle
Sollte dies bearbeitet werden , um die --ctdir ? Ich benutze-m conntrack --ctstate NEW --ctorigdstport 3306 --ctdir ORIGINAL
Lonix
@Ionix, ja sollte es, obwohl ich gerade erst herausgefunden habe, warum es mich verwirrt hat. Ich habe ein bisschen Erklärung hinzugefügt.
SystemParadox
1
Beachten Sie, dass die Standardtabelle DOCKER-USERden folgenden Eintrag enthält: Dieser -A DOCKER-USER -j RETURNwird vor dem oben genannten ausgeführt, wenn Sie ihn verwenden -A. Eine Lösung besteht darin, Regeln in umgekehrter Reihenfolge am Kopf einzufügen -I.
BMitch
@BMitch Oder noch besser , fügen Sie alle Regeln in eine neue FILTERSKette ein und -Ifügen Sie neue Regeln ein (wie Sie gesagt haben), um -I INPUT -j FILTERS-I DOCKER-USER -i eth0 -j FILTERS
dorthin
@BMitch Allerdings habe ich gerade meinen Server überprüft und die Rückgaberegel ist nicht da, vielleicht fügt die neueste Docker-Version sie nicht mehr ein? Es ist jedoch eine gute Idee, sie zu verwenden -I, um auf Nummer sicher zu gehen.
Lonix
8

Mit Docker v.17.06 gibt es eine neue iptables-Kette namens DOCKER-USER. Dieser ist für Ihre benutzerdefinierten Regeln bestimmt: https://docs.docker.com/network/iptables/

Anders als die Kette DOCKER wird sie beim Bauen / Starten von Containern nicht zurückgesetzt. Sie können diese Zeilen also zu Ihrer iptables-Konfiguration / Ihrem iptables-Skript hinzufügen, um den Server bereitzustellen, noch bevor Sie docker installieren und die Container starten:

-N DOCKER
-N DOCKER-ISOLATION
-N DOCKER-USER
-A DOCKER-ISOLATION -j RETURN
-A DOCKER-USER -i eth0 -p tcp -m tcp --dport 3306 -j DROP
-A DOCKER-USER -j RETURN

Jetzt ist der Port für MySQL für den externen Zugriff gesperrt (eth0), obwohl Docker den Port für die Welt öffnet. (Diese Regeln setzen voraus, dass Ihre externe Schnittstelle eth0 ist.)

Irgendwann müssen Sie iptables bereinigen und den Docker-Dienst zuerst neu starten, wenn Sie es zu sehr vermasselt haben und versucht haben, den Port wie ich zu sperren.

ck1
quelle
Ich vermisse, warum diese DOCKER-USER-Tabelle anders ist als jede andere vom Benutzer hinzugefügte Tabelle. Es wurde kein Filter vorab angewendet, sodass Sie die Schnittstellennamen immer noch selbst angeben müssen. Wenn Sie eine "MY-CHAIN" erstellen und in die FORWARD-Kette einfügen, hat dies das gleiche Ergebnis, nicht wahr?
ColinM
Ja, das macht einen Unterschied, da Docker die DOCKER-USER-Kette in die FORWARD-Kette einfügt: Aus -A FORWARD -j DOCKER-USER -A FORWARD -j DOCKER-ISOLATION diesem Grund werden die benutzerdefinierten Anweisungen vor der DOCKER-Kette ausgeführt.
ck1
Beachten Sie, dass bei Verwendung --dportinnerhalb von DOCKER-USER die interne IP- Adresse des Containerdienstes und nicht der exponierte Port übereinstimmen muss . Diese stimmen oft überein, aber nicht immer, und dies kann leicht zu Konflikten mit anderen Diensten führen. Daher behaupte ich immer noch, dass diese DOCKER-USER-Lösung nur halbherzig ist.
ColinM
4

UPDATE : Diese Lösung ist zwar gültig im Jahr 2015, aber nicht mehr der richtige Weg, dies zu tun.

Die Antwort scheint in der Dokumentation von Docker unter https://docs.docker.com/articles/networking/#the-world zu stehen

Die Weiterleitungsregeln von Docker lassen standardmäßig alle externen Quell-IPs zu. Fügen Sie oben in der DOCKER-Filterkette eine negierte Regel ein, damit nur eine bestimmte IP-Adresse oder ein bestimmtes Netzwerk auf die Container zugreifen kann. Um beispielsweise den externen Zugriff so einzuschränken, dass nur Quell-IP 8.8.8.8 auf die Container zugreifen kann, könnte die folgende Regel hinzugefügt werden:iptables -I DOCKER -i ext_if ! -s 8.8.8.8 -j DROP

Am Ende habe ich Folgendes getan:

iptables -I DOCKER -i eth0 -s 8.8.8.8 -p tcp --dport 3306 -j ACCEPT
iptables -I DOCKER -i eth0 -s 4.4.4.4 -p tcp --dport 3306 -j ACCEPT
iptables -I DOCKER 3 -i eth0 -p tcp --dport 3306 -j DROP

Ich habe die Optionen --iptablesoder nicht --iccangerührt.

GGGforce
quelle
1
In diesem Fall iptables -vnL DOCKERsind die Zielports alle Ports im Container. Wenn ich das richtig verstehe, bedeutet dies, dass die obigen Regeln nur den Port 3306innerhalb des Containers betreffen. Wenn Sie sich also in -p 12345:3306Ihrem Container befinden, ist Ihre Regel immer noch diejenige, die zum Sperren des Zugriffs erforderlich ist (dh --dport 12345nicht funktioniert). , weil die ACCEPT-Regeln der DOCKER-Kette Post-NAT sind.
Sunside
Richtig, die Regeln müssen sich auf die Häfen in den Containern beziehen.
GGGforce
1
Hum, das ist etwas hässlich, wenn Sie mehrere Container ausführen, die beispielsweise ein internes NGINX für Reverse-Proxying verwenden (z. B. Zabbix, einen benutzerdefinierten Load Balancer usw.), da Sie die IP-Adresse des Containers im Voraus kennen müssten. Ich bin immer noch auf der Suche nach einer Lösung für dieses Problem, das nicht erforderlich ist --iptables=false, da dies die schlechteste Wahl von allen zu sein scheint.
Sunside
Vielen Dank! Sie haben mein Problem nach vielen Stunden der Suche gelöst. Jetzt bin ich endlich in der Lage, MySQL nur an meine Heim-IP-Adresse zu schicken, ohne den weichen Unterbauch der ganzen Welt auszusetzen.
Matt Cavanagh
1
Die DOCKER-Kette darf nicht direkt vom Benutzer manipuliert werden! Verwenden Sie dazu die DOCKER-USER-Kette. Überprüfen Sie die akzeptierte Antwort.
Paul-Sebastian Manole
3

UPDATE: Während diese Antwort noch gültig ist, ist die Antwort von @SystemParadox DOCKER-USERin Kombination mit --ctorigdstportbesser.

Hier ist eine Lösung, die zwischen Neustarts gut erhalten bleibt und es Ihnen ermöglicht, den exponierten Port und nicht den internen Port zu beeinflussen.

iptables -t mangle -N DOCKER-mysql iptables -t mangle -A DOCKER-mysql -s 22.33.44.144/32 -j RETURN iptables -t mangle -A DOCKER-mysql -s 22.33.44.233/32 -j RETURN iptables -t mangle -A DOCKER-mysql -j DROP iptables -t mangle -A PREROUTING -i eth0 -p tcp -m tcp --dport 3306 -j DOCKER-mysql

Ich habe ein Docker-Image erstellt, das diese Methode verwendet, um die iptables automatisch für Sie zu verwalten, entweder mithilfe von Umgebungsvariablen oder dynamisch mit etcd (oder beiden):

https://hub.docker.com/r/colinmollenhour/confd-firewall/

ColinM
quelle