Warum lässt Firewall öffentlichen Datenverkehr zu meinen nicht öffentlichen Ports zu, die an Docker-Container gebunden sind?

Warum lässt Firewall öffentlichen Datenverkehr zu meinen nicht öffentlichen Ports zu, die an Docker-Container gebunden sind?

Ich versuche, eine ziemlich einfache Firewall in Fedora zu implementieren, bei der das öffentliche Internet auf SSH, HTTP, HTTPS und Cockpit zugreifen kann, aber sonst auf nichts. In der Zwischenzeit führen die Server über Docker Microservices aus, die über die Ports 8000-8999 miteinander kommunizieren können.

netzwerkdiagramm

Ich habe dies auf einer Neuinstallation von Fedora Server mit den folgenden Befehlen eingerichtet:

firewall-cmd --zone=public --add-service=cockpit
firewall-cmd --zone=public --add-service=http
firewall-cmd --zone=public --add-service=https

firewall-cmd --zone=internal --add-source=192.168.1.65
firewall-cmd --zone=internal --add-source=192.168.1.66

firewall-cmd --zone=internal --add-port=8000-8999/tcp

firewall-cmd --runtime-to-permanent

Wenn ich meine Konfiguration mit überprüfe --list-all, sieht alles korrekt aus:

> firewall-cmd --list-all --zone=internal
internal (active)
  target: default
  icmp-block-inversion: no
  interfaces:
  sources: 192.168.1.65 192.168.1.66
  services: dhcpv6-client ssh
  ports: 8000-8999/tcp
  protocols:
  forward: no
  masquerade: no
  forward-ports:
  source-ports:
  icmp-blocks:
  rich rules:

> firewall-cmd --list-all --zone=public
public (active)
  target: default
  icmp-block-inversion: no
  interfaces: enp2s0
  sources:
  services: cockpit dhcpv6-client http https ssh
  ports:
  protocols:
  forward: no
  masquerade: no
  forward-ports:
  source-ports:
  icmp-blocks:
  rich rules:

Wenn ich dies jedoch teste, kann ich treffenhttp://192.168.1.65:8080. Ich kann es von einem Rechner im selben internen Netzwerk (192.168.128.128) aus aufrufen, ebenso wie eine öffentliche Anfrage von einem externen Rechner. Da keines von internalbeiden in aufgeführt war sources, nahm ich an, dass Firewalld die Anfragen nicht durchlassen würde.

Ich habe eine automatisch konfigurierte dockerZone mit der docker0Schnittstelle, aber wenn ich diese entferne, ändert das anscheinend nichts an meiner Fähigkeit, den internen Port zu erreichen.

Warum kann ich :8080 erfolgreich von Quellen anfordern, die nicht auf aufgeführt sind internal?

Antwort1

Nun, es stellt sich heraus, dass das Problem daher rührt, dass ich Docker für meine internen Ports verwende. Um den Prozess zu vereinfachen, Container mit der Welt und untereinander kommunizieren zu lassen, hat Docker beschlossen, einen Großteil der Kontrolle über Ihre Firewalls/Netzwerke zu übernehmen. Das bedeutet, dass, wenn Sienichtmöchten, dass Ihre Container öffentlich zugänglich sindUNDSie müssen den öffentlichen Zugriff über die Firewall auf demselben Computer wie Ihren Docker-Daemon steuern. Sie müssen Ihre Firewalls etwas anders konfigurieren.Docker verfügt über eine offizielle Dokumentation dazu, wie dies zu tun ist.Grundsätzlich stehen Ihnen folgende Möglichkeiten zur Verfügung:

  • Richten Sie eine separate Maschine nur für Ihre Firewall ein. Dies ist wahrscheinlich am einfachsten, da Docker und Ihre Firewall keine Ressourcen gemeinsam nutzen müssen.
  • Fügen Sie der Kette Ihre iptablesRegeln hinzu DOCKER-USER(das ist eher eine Antwort für iptablesBenutzer; ich bin nicht sicher, wie ich firewallddiesen Ansatz replizieren kann)
  • Deaktivieren Sie das Ganze durch entsprechende Einstellungen iptables=falsein Ihrer Docker-Dienstkonfiguration. (dieser Blog-Beitragdiskutiert diese Option)

ich auchhabe einen Beitrag gefundendas fand ich eine nette Variante der DOCKER-USERKettenoption. Im Grunde erstellt man mit eine iptables.confDatei, die man ohne Flush laden kann iptables-restore -n. Leider ist das keine iptablesLösung, sondern eine firewalldLösung.

Einer der schwierigen Aspekte bei der Diagnose dieses Problems bestand darin, dass ich ein Skript ausführte, um die Firewall meinen Wünschen entsprechend zu ändern. Dies funktionierte, bis ich den Computer neu startete oder den Docker-Daemon startete. Docker überschreibt die iptablesKonfiguration beim Start.

Antwort2

Ich konnte das Problem durch die Neuerstellung der DOCKER-USERKette beheben und möchte sie weitergeben, falls sie jemand anderes nützlich findet.

Dies basiert auf einer Lösung, die ich auf Github gefunden habe (https://github.com/firewalld/firewalld/issues/869) und auf dem Blog eines Genies (https://roosbertl.blogspot.com/2019/06/docker-ports-mit-firewalld-sichern.html), aber ich musste es ein wenig anpassen/verfeinern.

# 1. Stop Docker
systemctl stop docker.socket
systemctl stop docker.service

# 2. Recreate DOCKER-USER iptables chain with firewalld. Ignore warnings, do not ignore errors
firewall-cmd --permanent --direct --remove-chain ipv4 filter DOCKER-USER
firewall-cmd --permanent --direct --remove-rules ipv4 filter DOCKER-USER
firewall-cmd --permanent --direct --add-chain ipv4 filter DOCKER-USER

# 3. Add iptables rules to DOCKER-USER chain - unrestricted outbound, restricted inbound to private IPs
firewall-cmd --permanent --direct --add-rule ipv4 filter DOCKER-USER 1 -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT -m comment --comment 'Allow containers to connect to the outside world'
firewall-cmd --permanent --direct --add-rule ipv4 filter DOCKER-USER 1 -j RETURN -s 127.0.0.0/8 -m comment --comment 'allow internal docker communication, loopback addresses'
firewall-cmd --permanent --direct --add-rule ipv4 filter DOCKER-USER 1 -j RETURN -s 172.16.0.0/12 -m comment --comment 'allow internal docker communication, private range'

# 3.1 optional: for wider internal networks
firewall-cmd --permanent --direct --add-rule ipv4 filter DOCKER-USER 1 -j RETURN -s 10.0.0.0/8 -m comment --comment 'allow internal docker communication, private range'
firewall-cmd --permanent --direct --add-rule ipv4 filter DOCKER-USER 1 -j RETURN -s 192.168.0.0/16 -m comment --comment 'allow internal docker communication, private range'

# 4. Block all other IPs. This rule has lowest precedence, so you can add rules before this one later.
firewall-cmd --permanent --direct --add-rule ipv4 filter DOCKER-USER 10 -j REJECT -m comment --comment 'reject all other traffic to DOCKER-USER'

# 5. Activate rules
firewall-cmd --reload

# 6. Start Docker
systemctl start docker.socket
systemctl start docker.service

verwandte Informationen