Das ist eigentlich eine sehr gute Frage, und ich bin überrascht, dass noch niemand sie gestellt hat. Die Antwort ist kompliziert, aber bisher waren die Antworten zu diesem Thema leider abweisend und beantworteten die Frage nicht.
Es ist nicht so, dass Discourse ufw umgeht, sondern docker umgeht ufw, indem es Regeln hinzufügt, die dazu führen, dass alle exponierten Ports von Docker-Containern trotz der Anwesenheit von ufw funktionieren.
Was passiert?
Eingehende Pakete, die für einen Container bestimmt sind, treffen auf die FORWARD-Tabelle und nicht auf die INPUT-Tabelle, wie man vielleicht erwarten würde.
Vor der Docker-Installation
Chain FORWARD (policy DROP 0 packets, 0 bytes)
pkts bytes target prot opt in out source destination
0 0 ufw-before-logging-forward all -- any any anywhere anywhere
0 0 ufw-before-forward all -- any any anywhere anywhere
0 0 ufw-after-forward all -- any any anywhere anywhere
0 0 ufw-after-logging-forward all -- any any anywhere anywhere
0 0 ufw-reject-forward all -- any any anywhere anywhere
0 0 ufw-track-forward all -- any any anywhere anywhere
Nach der Docker-Installation
Chain FORWARD (policy DROP 0 packets, 0 bytes)
pkts bytes target prot opt in out source destination
8 416 DOCKER-USER all -- any any anywhere anywhere
8 416 DOCKER-ISOLATION-STAGE-1 all -- any any anywhere anywhere
0 0 ACCEPT all -- any docker0 anywhere anywhere ctstate RELATED,ESTABLISHED
4 256 DOCKER all -- any docker0 anywhere anywhere
4 160 ACCEPT all -- docker0 !docker0 anywhere anywhere
0 0 ACCEPT all -- docker0 docker0 anywhere anywhere
0 0 ufw-before-logging-forward all -- any any anywhere anywhere
0 0 ufw-before-forward all -- any any anywhere anywhere
0 0 ufw-after-forward all -- any any anywhere anywhere
0 0 ufw-after-logging-forward all -- any any anywhere anywhere
0 0 ufw-reject-forward all -- any any anywhere anywhere
0 0 ufw-track-forward all -- any any anywhere anywhere
Der Grund, warum die Pakete die Forward-Tabelle treffen, liegt an Regeln, die Docker zur nat-Tabelle hinzufügt:
Chain PREROUTING (policy ACCEPT 0 packets, 0 bytes)
pkts bytes target prot opt in out source destination
210 12734 DOCKER all -- any any anywhere anywhere ADDRTYPE match dst-type LOCAL
Chain DOCKER (2 references)
pkts bytes target prot opt in out source destination
0 0 RETURN all -- docker0 any anywhere anywhere
0 0 DNAT tcp -- !docker0 any anywhere anywhere tcp dpt:https to:172.17.0.2:443
107 6848 DNAT tcp -- !docker0 any anywhere anywhere tcp dpt:http to:172.17.0.2:80
nat/PREROUTING wird vor der Entscheidung, ob Pakete über INPUT oder FORWARD gesendet werden sollen, verarbeitet.
Letztendlich liegt das Problem darin, dass zwei Dienste auf dem System die Firewall-Regeln ändern. ufw weiß nichts davon, daher kann es nur berichten, was es konfiguriert hat.
Eine Lösung
Dafür ist die Neukonfiguration der Firewall, um auch für Docker bestimmte Daten über die ufw-Chains weiterzuleiten:
Ich verwende die folgende leichte Anpassung ihrer Arbeit, die vor der Aktivierung von ufw eingerichtet wird:
# gestohlen von https://github.com/chaifeng/ufw-docker - sieht vernünftig aus
# das Hinzufügen der Weiterleitung zu ufw-user-input ermöglicht Verbindungen zu
# weitergeleiteten Ports, die wir explizit geöffnet haben
cat <<EOUFW >> /etc/ufw/after.rules
# BEGIN UFW AND DOCKER
*filter
:ufw-user-forward - [0:0]
:ufw-user-input - [0:0]
:DOCKER-USER - [0:0]
-A DOCKER-USER -j RETURN -s 10.0.0.0/8
-A DOCKER-USER -j RETURN -s 172.16.0.0/12
-A DOCKER-USER -j RETURN -s 192.168.0.0/16
-A DOCKER-USER -p udp -m udp --sport 53 --dport 1024:65535 -j RETURN
-A DOCKER-USER -j ufw-user-forward
-A DOCKER-USER -j ufw-user-input
-A DOCKER-USER -j DROP -p tcp -m tcp --tcp-flags FIN,SYN,RST,ACK SYN -d 10.0.0.0/8
-A DOCKER-USER -j DROP -p tcp -m tcp --tcp-flags FIN,SYN,RST,ACK SYN -d 172.16.0.0/12
-A DOCKER-USER -j DROP -p tcp -m tcp --tcp-flags FIN,SYN,RST,ACK SYN -d 192.168.0.0/16
-A DOCKER-USER -j DROP -p udp -m udp --dport 0:32767 -d 10.0.0.0/8
-A DOCKER-USER -j DROP -p udp -m udp --dport 0:32767 -d 172.16.0.0/12
-A DOCKER-USER -j DROP -p udp -m udp --dport 0:32767 -d 192.168.0.0/16
-A DOCKER-USER -j RETURN
COMMIT
# END UFW AND DOCKER
EOUFW