Schritte zum Einschränken von externen Verbindungen zum Docker-Container mit iptables?

Mein Ziel ist es, den Zugriff auf Docker-Container auf nur 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, fällt es mir sehr schwer.

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 Standardeingaberichtlinie von ABLEHNEN festzulegen und dann nur Verbindungen von meinen Hosts zuzulassen. Aber die NAT-Regeln und -Ketten von Docker stören und meine Eingabevorschriften werden ignoriert.

Kann jemand ein Beispiel dafür geben, wie ich mein Ziel unter den folgenden Annahmen erreichen kann?

  • Öffentliche Host-IP 80.80.80.80 auf eth0
  • Private Host-IP 192.168.1.10 auf eth1
  • docker run -d -p 3306:3306 mysql
  • Blockieren Sie alle Verbindungen zu Host / Container 3306 mit Ausnahme der Hosts 4.4.4.4 und 8.8.8.8

Ich bin gerne bereit, den Container nur an die lokale IP-Adresse zu binden, benötige jedoch Anweisungen zum ordnungsgemäßen Einrichten der iptables-Weiterleitungsregeln, die den Docker-Prozess und Host-Neustarts überstehen.

Danke!

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

  1. Um zu vermeiden, dass Ihre Regeln von Docker überlastet werden, verwenden Sie die DOCKER-USER Kette
  2. Docker macht das Port-Mapping in der PREROUTING kette der nat Tabelle. Dies geschieht vor dem filter regeln, also --dest und --dport sehen Sie die interne IP und den Port des Containers. Um auf das ursprüngliche Ziel zuzugreifen, können Sie Folgendes 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 ACCEPTiptables -A DOCKER-USER -i eth0 -s 4.4.4.4 -p tcp -m conntrack --ctorigdstport 3306 --ctdir ORIGINAL -j ACCEPTiptables -A DOCKER-USER -i eth0 -p tcp -m conntrack --ctorigdstport 3306 --ctdir ORIGINAL -j DROP

HINWEIS: Ohne --ctdir ORIGINAL, dies würde auch mit den Antwortpaketen übereinstimmen, die für eine Verbindung vom Container zum Port 3306 auf einem anderen Server zurückkommen, was mit ziemlicher Sicherheit nicht das ist, was Sie wollen! Sie brauchen das nicht unbedingt, wenn Ihre erste Regel wie ich lautet -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT, da das mit allen Antwortpaketen umgehen wird, aber es wäre sicherer, immer noch zu verwenden --ctdir ORIGINAL Wie dem auch sei.

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

Im Gegensatz zum Ketten-DOCKER wird es beim Erstellen / 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.)

Schließlich müssen Sie iptables bereinigen und zuerst den Docker-Dienst neu starten, wenn Sie es zu sehr durcheinander gebracht haben, den Port wie ich zu sperren.

UPDATE: Während diese Antwort noch gültig ist, ist die Antwort von @SystemParadox mit DOCKER-USER in Kombination mit --ctorigdstport ist besser.

Hier ist eine Lösung, die zwischen Neustarts gut anhält und es Ihnen ermöglicht, die zu beeinflussen ausgesetzt hafen statt der intern Port.

iptables -t mangle -N DOCKER-mysqliptables -t mangle -A DOCKER-mysql -s 22.33.44.144/32 -j RETURNiptables -t mangle -A DOCKER-mysql -s 22.33.44.233/32 -j RETURNiptables -t mangle -A DOCKER-mysql -j DROPiptables -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 beidem):

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

UPDATE: Obwohl diese Lösung 2015 gültig war, ist sie nicht mehr der richtige Weg.

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

Die Vorwärtsregeln von Docker erlauben standardmäßig alle externen Quell-IPs. Um nur einer bestimmten IP oder einem bestimmten Netzwerk den Zugriff auf die Container zu gestatten, fügen Sie oben in der DOCKER-Filterkette eine negierte Regel ein. Um beispielsweise den externen Zugriff so einzuschränken, dass nur die 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

Was ich am Ende getan habe, war:

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

Ich habe die nicht berührt --iptables oder --icc Option.