Iptables – Steps for limiting outside connections to docker container with iptables

dockeriptables

My goal is to limit access to docker containers to just a few public IP addresses. Is there a simple, repeatable process to accomplish my goal? Understanding only the basics of iptables while using Docker's default options, I'm finding it very difficult.

I'd like to run a container, make it visible to the public Internet, but only allow connections from select hosts. I would expect to set a default INPUT policy of REJECT and then only allow connections from my hosts. But Docker's NAT rules and chains get in the way and my INPUT rules are ignored.

Can somebody provide an example of how to accomplish my goal given the following assumptions?

  • Host public IP 80.80.80.80 on eth0
  • Host private IP 192.168.1.10 on eth1
  • docker run -d -p 3306:3306 mysql
  • Block all connection to host/container 3306 except from hosts 4.4.4.4 and 8.8.8.8

I'm happy to bind the container to only the local ip address but would need instructions on how to set up the iptables forwarding rules properly which survive docker process and host restarts.

Thanks!

Best Answer

Two things to bear in mind when working with docker's firewall rules:

  1. To avoid your rules being clobbered by docker, use the DOCKER-USER chain
  2. Docker does the port-mapping in the PREROUTING chain of the nat table. This happens before the filter rules, so --dest and --dport will see the internal IP and port of the container. To access the original destination, you can use -m conntrack --ctorigdstport.

For example:

iptables -A DOCKER-USER -i eth0 -s 8.8.8.8 -p tcp -m conntrack --ctorigdstport 3306 --ctdir ORIGINAL -j ACCEPT
iptables -A DOCKER-USER -i eth0 -s 4.4.4.4 -p tcp -m conntrack --ctorigdstport 3306 --ctdir ORIGINAL -j ACCEPT
iptables -A DOCKER-USER -i eth0 -p tcp -m conntrack --ctorigdstport 3306 --ctdir ORIGINAL -j DROP

NOTE: Without --ctdir ORIGINAL, this would also match the reply packets coming back for a connection from the container to port 3306 on some other server, which is almost certainly not what you want! You don't strictly need this if like me your first rule is -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT, as that will deal with all the reply packets, but it would be safer to still use --ctdir ORIGINAL anyway.