Using iptables rules aren't working with Docker container

For everyone looking for solution to this problem, the answer is this:

*filter
:INPUT ACCEPT [0:0]
:FORWARD DROP [0:0]
:OUTPUT ACCEPT [0:0]
:FILTERS - [0:0]
:DOCKER-USER - [0:0]

-F INPUT
-F DOCKER-USER
-F FILTERS

-A INPUT -i lo -j ACCEPT
-A INPUT -p icmp --icmp-type any -j ACCEPT
-A INPUT -j FILTERS

-A DOCKER-USER -i ens33 -j FILTERS

-A FILTERS -m state --state ESTABLISHED,RELATED -j ACCEPT
-A FILTERS -m state --state NEW -m tcp -p tcp --dport 22 -j ACCEPT
-A FILTERS -m state --state NEW -m tcp -p tcp --dport 80 -j ACCEPT
-A FILTERS -m state --state NEW -m tcp -p tcp --dport 443 -j ACCEPT
-A FILTERS -j REJECT --reject-with icmp-host-prohibited

COMMIT

Found it here: https://unrouted.io/2017/08/15/docker-firewall/

Works perfectly.


I'll explain my scenario where I've tested what you want to achieve.

I've launched a docker container where port 9010 is forwarded to port 8080:

docker run -p 9010:8080 swaggerapi/swagger-editor

Docker creates a DNAT rule for the PREROUTING chain that forwards traffic from port 9010 to port 8080:

DNAT       tcp  --  !docker0 *       0.0.0.0/0            0.0.0.0/0            tcp dpt:9010 to:172.17.0.5:8080

Docker also creates a rule in the DOCKER chain allowing all traffic sent to the container's IP address and port 8080.

ACCEPT     tcp  --  !docker0 docker0  0.0.0.0/0            172.17.0.5           tcp dpt:8080

The DOCKER chain is used in the FORWARD chain, where all traffic sent to the docker0 bridge is processed by rules in the DOCKER chain.

DOCKER     all  --  *      docker0  0.0.0.0/0            0.0.0.0/0

Now I want to filter traffic sent to port 8080 (traffic to port 9010 has been processed by the PREROUTING and now it's traffic sent to port 8080) blocking all IP addresses while allowing traffic from IP 192.168.1.142. The IP address of the container could be added to those rules for increased granularity of course.

I add the following rules at the beginning of the FORWARD chain. Alternatively you could replace FORWARD with DOCKER.

iptables -I FORWARD -p tcp --dport 8080 -j DROP
iptables -I FORWARD -p tcp -s 192.168.1.142 --dport 8080 -j ACCEPT

Thanks to those rules only IP 192.168.1.142 can reach the 8080 port used by the container.

For those visiting this answer if you only want to allow one specific IP address to access the containers use the iptables command suggested in the Docker docs.