0

I have a number of CentOS 7 VPS running Docker and are orchastrated by Cattle (Rancher).

These VPS should only be accessible from a couple of IP addresses on the internet and all other sources should be dropped/ignored. I have configured firewalld appropriately and the restriction is working for the standard system services, such as SSH, but when I deploy a container to them the exposed port is being allowed from anywhere.

It seems that Docker is mapping the host IP/port to the container IP/port (which is correct) but then this rule is being inserted into netfilter BEFORE my explicit source allow list...

Is there anyway to get around this? Any help would be much appreciated.

justacodemonkey
  • 153
  • 1
  • 7

2 Answers2

1

Yeah, you just have to make your blocking firewall entries evaluate before the entries added by docker.

In my environment, docker adds allow rules to a chain called DOCKER and deny rules to a chain called DOCKER-ISOLATION. These get evaluated at the beginning of the FORWARD chain. So if your env is like mine, just stick your own rules at the top of the FORWARD chain. This is in the 'filter' table. I recently confused myself with the 'filter' and 'nat' tables.

Hope that helps -Dylan

Dylan Martin
  • 548
  • 4
  • 14
  • This is exactly what I was thinking of doing, but I figured iptables chains were frowned upon in CentOS 7 land. I think this might be my only option unless there is some magic I haven't found in FirewallD... – justacodemonkey Apr 28 '17 at 20:13
  • Looks like we need this patch to go live to get a proper solution... https://github.com/docker/libnetwork/pull/1675 – justacodemonkey Apr 28 '17 at 22:46
0

I struggled with this one for a few hours, but here is a solution using iptables instead of firewalld.

The key is to get your blocks in before Docker. However Docker has a nasty habit of putting it's rules right to the top of the FORWARD chain on the filter table; on every service restart. So... I had to get creative and leverage the mangle table and the POSTROUTING chain, like so:

*mangle
:IS-ALLOWED -
-A IS-ALLOWED ! -o docker0 -j RETURN
-A IS-ALLOWED -o docker0 -s 1.1.1.1 -j RETURN
-A IS-ALLOWED -j DROP
-I POSTROUTING -j IS-ALLOWED
COMMIT

*filter
:INPUT ACCEPT [0:0]
:FORWARD ACCEPT [0:0]
:OUTPUT ACCEPT [0:0]
:IS-ALLOWED -
-A IS-ALLOWED -s 1.1.1.1 -j RETURN
-A IS-ALLOWED -i lo -j RETURN
-A IS-ALLOWED -j DROP
-A INPUT -m state --state RELATED,ESTABLISHED -j ACCEPT
-A INPUT -j IS-ALLOWED
-A INPUT -p icmp -j ACCEPT
-A INPUT -i lo -j ACCEPT
-A INPUT -p tcp -m state --state NEW -m tcp --dport 22 -j ACCEPT
-A INPUT -j REJECT --reject-with icmp-host-prohibited
-A FORWARD -j REJECT --reject-with icmp-host-prohibited
COMMIT

This restricts access to just 1.1.1.1 for the machine's services (SSH, ICMP etc) and the Docker forwarded services on the docker0 interface.

justacodemonkey
  • 153
  • 1
  • 7