Docker has placed its own forwarding in the iptables, so blocking INPUT and OUTPUT would not protect services expose via docker publish port. In addition, Docker moves its own rules at the top of yours in FORWARD https://github.com/moby/moby/issues/24848 https://docs.docker.com/engine/userguide/networking/#links https://serverfault.com/a/886257. To make it only accessible from a trust ip, here is the guide.
# Default rule that created by Docker
# iptables -I DOCKER-USER -j RETURN
# Drop only incoming, allowing outgoing connection for DNS, apt-get, pip
iptables -I DOCKER-USER -i eth0 -j DROP
# Return from where we jump if it is a connection we initial (otherwise apt wouldn't work inside docker)
iptables -I DOCKER-USER -m conntrack --ctstate RELATED,ESTABLISHED -j RETURN
# Return from where we jump if it is an IP we trust (replace XXX with an IP you trust)
iptables -I DOCKER-USER -s XXX.XXX.XXX.XXX/32 -i eth0 -j RETURN
# Logging for debug (see below)
# iptables -A DOCKER-USER -j LOG
The finish iptables rules (iptables -S
) would look like
=== The existing -P rules ===
-P INPUT ACCEPT
-P FORWARD DROP
-P OUTPUT ACCEPT
-N DOCKER
-N DOCKER-INGRESS
-N DOCKER-ISOLATION
-N DOCKER-USER
=== The new PRE_DOCKER chain you added ===
-N PRE_DOCKER
-A FORWARD -j PRE_DOCKER
=== The existing FORWARD rules created by docker ===
-A FORWARD -j DOCKER-USER
-A FORWARD -j DOCKER-INGRESS
-A FORWARD -j DOCKER-ISOLATION
-A FORWARD -o docker_gwbridge -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT
-A FORWARD -o docker_gwbridge -j DOCKER
-A FORWARD -i docker_gwbridge ! -o docker_gwbridge -j ACCEPT
-A FORWARD -o docker0 -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT
-A FORWARD -o docker0 -j DOCKER
-A FORWARD -i docker0 ! -o docker0 -j ACCEPT
-A FORWARD -i docker0 -o docker0 -j ACCEPT
-A FORWARD -i docker_gwbridge -o docker_gwbridge -j DROP
...
=== The new PRE_DOCKER rules you added ===
-A DOCKER-USER -j LOG
-A DOCKER-USER -s XXX.XXX.XXX.XXX/32 -i eth0 -j RETURN
-A DOCKER-USER -m conntrack --ctstate RELATED,ESTABLISHED -j RETURN
-A DOCKER-USER -i eth0 -j DROP
if -A PRE_DOCKER -j LOG
is there, you would find the log in /var/log/syslog
that explain the need of -i eth0
and -i docker0
Dec 7 16:14:23 ds06 kernel: [164304.277225] IN=eth0 OUT=docker0 MAC= SRC=A DST=B LEN=64 TOS=0x00 PREC=0x00 TTL=47 ID=34183 DF PROTO=TCP SPT=61065 DPT=7200 WINDOW=65535 RES=0x00 SYN URGP=0
Dec 7 16:14:23 ds06 kernel: [164304.277307] IN=docker0 OUT=eth0 PHYSIN=veth730785d MAC= SRC=B DST=A LEN=60 TOS=0x00 PREC=0x00 TTL=63 ID=0 DF PROTO=TCP SPT=7200 DPT=61065 WINDOW=28960 RES=0x00 ACK SYN URGP=0