실제로 이것은 매우 좋은 질문이며, 아직 아무도 묻지 않았다는 점이 놀랍습니다. 답변은 복잡하지만, 지금까지 이 주제에 대한 반응들은 불행히도 질문을 제대로 답변하지 않고 무시하는 어조였습니다.
Discourse가 ufw를 우회한다는 것이 본질적인 문제는 아닙니다. *docker*가 ufw를 우회하는 것입니다. Docker는 컨테이너의 노출된 포트가 ufw가 존재하더라도 작동하도록 하는 규칙을 추가하여 ufw를 우회합니다.
무슨 일이 일어나고 있는가?
컨테이너로 향하는 수신 패킷은 예상과 달리 INPUT 테이블이 아닌 FORWARD 테이블에 도달합니다.
Docker 설치 전
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
Docker 설치 후
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
패킷이 포워딩 테이블에 도달하는 이유는 Docker가 nat 테이블에 추가하는 규칙 때문입니다:
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은 패킷을 INPUT 또는 FORWARD로 보낼지 결정되기 이전에 처리됩니다.
결국 문제는 시스템에서 방화벽 규칙을 수정하는 서비스가 두 개 있다는 것입니다. ufw는 이 사실에 대해 알지 못하므로, 자신이 구성한 것만 보고할 수 있을 뿐입니다.
해결책
Docker로 향하는 트래픽이 ufw 체인을 통해서도 통과하도록 방화벽을 재구성하는 것입니다:
저는 그들의 작업을 약간 수정하여 ufw를 활성화하기 전에 아래 내용을 적용합니다:
# stolen from https://github.com/chaifeng/ufw-docker - looks sensible
# adding the forward to ufw-user-input allows connections to
# forwarded ports that we explicitly opened
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