6

I have a problem where ports exposed to applications running on our system in docker containers remain open to the world despite the iptables configuration designed to restrict access.

It seems to me that the problem may be related to the docker daemon adding rules to iptables on startup. I'm also aware of the flags --icc=true|false, --ip-forward=true|false and --iptables=true|false but I'm not sure which combination of these flags I should be applying. I have tried --icc=false and --ip-forward=false but neither have had the desired effect. I'm loathe to use --iptables=false because the docker daemon is clearly adding in a number of rules, which I'd have to configure manually if they are still needed.

This is the state of the rules before that docker daemon starts:

Chain INPUT (policy DROP 0 packets, 0 bytes)
 pkts bytes target     prot opt in     out     source               destination         
    0     0 ACCEPT     all  --  lo     any     anywhere             anywhere            
    0     0 REJECT     all  --  !lo    any     anywhere             loopback/8           reject-with icmp-port-unreachable
    0     0 DROP       tcp  --  any    any     anywhere             anywhere             tcpflags:! FIN,SYN,RST,ACK/SYN state NEW
    0     0 DROP       all  -f  any    any     anywhere             anywhere            
    0     0 DROP       tcp  --  any    any     anywhere             anywhere             tcpflags: FIN,SYN,RST,PSH,ACK,URG/FIN,SYN,RST,PSH,ACK,URG
    0     0 DROP       tcp  --  any    any     anywhere             anywhere             tcpflags: FIN,SYN,RST,PSH,ACK,URG/NONE
   82  8831 ACCEPT     all  --  any    any     anywhere             anywhere             state RELATED,ESTABLISHED
    0     0 ACCEPT     icmp --  any    any     anywhere             anywhere             icmp echo-request
    0     0 ACCEPT     tcp  --  any    any     anywhere             anywhere             multiport dports ssh
    0     0 ACCEPT     tcp  --  any    any     <IP ADDRESS RANGE 1>  anywhere             multiport dports ssh,http,https,7990,7999,tproxy,8090,8095,18080
    0     0 ACCEPT     tcp  --  any    any     <IP ADDRESS RANGE 2>  anywhere             multiport dports ssh,http,https,7990,7999,tproxy,8090,8095,18080
    0     0 LOG        all  --  any    any     anywhere             anywhere             limit: avg 5/min burst 5 LOG level debug prefix "iptables denied: "
    0     0 REJECT     all  --  any    any     anywhere             anywhere             reject-with icmp-port-unreachable

Chain FORWARD (policy DROP 0 packets, 0 bytes)
 pkts bytes target     prot opt in     out     source               destination         
   24  2489 REJECT     all  --  any    any     anywhere             anywhere             reject-with icmp-port-unreachable

Chain OUTPUT (policy DROP 0 packets, 0 bytes)
 pkts bytes target     prot opt in     out     source               destination         
   77 10080 ACCEPT     all  --  any    any     anywhere             anywhere  

And this is what it's like with the docker daemon running:

Chain INPUT (policy DROP 0 packets, 0 bytes)
 pkts bytes target     prot opt in     out     source               destination         
    0     0 ACCEPT     all  --  lo     any     anywhere             anywhere            
    0     0 REJECT     all  --  !lo    any     anywhere             loopback/8           reject-with icmp-port-unreachable
    0     0 DROP       tcp  --  any    any     anywhere             anywhere             tcpflags:! FIN,SYN,RST,ACK/SYN state NEW
    0     0 DROP       all  -f  any    any     anywhere             anywhere            
    0     0 DROP       tcp  --  any    any     anywhere             anywhere             tcpflags: FIN,SYN,RST,PSH,ACK,URG/FIN,SYN,RST,PSH,ACK,URG
    0     0 DROP       tcp  --  any    any     anywhere             anywhere             tcpflags: FIN,SYN,RST,PSH,ACK,URG/NONE
 1335  230K ACCEPT     all  --  any    any     anywhere             anywhere             state RELATED,ESTABLISHED
    1    32 ACCEPT     icmp --  any    any     anywhere             anywhere             icmp echo-request
    7   380 ACCEPT     tcp  --  any    any     anywhere             anywhere             multiport dports ssh
    0     0 ACCEPT     tcp  --  any    any     <IP ADDRESS RANGE 1>  anywhere             multiport dports ssh,http,https,7990,7999,tproxy,8090,8095,18080
    0     0 ACCEPT     tcp  --  any    any     <IP ADDRESS RANGE 2>  anywhere             multiport dports ssh,http,https,7990,7999,tproxy,8090,8095,18080
   35  2016 LOG        all  --  any    any     anywhere             anywhere             limit: avg 5/min burst 5 LOG level debug prefix "iptables denied: "
   62  3672 REJECT     all  --  any    any     anywhere             anywhere             reject-with icmp-port-unreachable

Chain FORWARD (policy DROP 0 packets, 0 bytes)
 pkts bytes target     prot opt in     out     source               destination         
54492   21M DOCKER     all  --  any    docker0  anywhere             anywhere            
51882   20M ACCEPT     all  --  any    docker0  anywhere             anywhere             ctstate RELATED,ESTABLISHED
58371 9122K ACCEPT     all  --  docker0 !docker0  anywhere             anywhere            
    0     0 DROP       all  --  docker0 docker0  anywhere             anywhere            
 1186  121K REJECT     all  --  any    any     anywhere             anywhere             reject-with icmp-port-unreachable

Chain OUTPUT (policy DROP 0 packets, 0 bytes)
 pkts bytes target     prot opt in     out     source               destination         
 2090  263K ACCEPT     all  --  any    any     anywhere             anywhere            

Chain DOCKER (1 references)
 pkts bytes target     prot opt in     out     source               destination         
   86  7048 ACCEPT     tcp  --  !docker0 docker0  anywhere             172.17.0.2           tcp dpt:7990
 1639  395K ACCEPT     tcp  --  !docker0 docker0  anywhere             172.17.0.2           tcp dpt:7999
  791  151K ACCEPT     tcp  --  !docker0 docker0  anywhere             172.17.0.3           tcp dpt:http-alt
   20  1898 ACCEPT     tcp  --  !docker0 docker0  anywhere             172.17.0.4           tcp dpt:8090
   49  4561 ACCEPT     tcp  --  !docker0 docker0  anywhere             172.17.0.5           tcp dpt:18080
   25  3642 ACCEPT     tcp  --  !docker0 docker0  anywhere             172.17.0.6           tcp dpt:8095

There are also a number of POSTROUTING & MASQUERADE rules, which don't display with iptables -L, only when you use iptables-save. I'm not sure of the significance of these either.

I suspect that the DOCKER target rule in the FORWARD chain is the source of the problem but I cannot see how to solve this problem because it seems to be inserted by the docker daemon at the start of the chain.

So, can anyone advise me as to what I need to do to make sure that the ports 7990, 8090 etc. are not exposed to the world when running docker?

Thanks

Richard

Richard Corfield
  • 3,529
  • 1
  • 14
  • 11

2 Answers2

6

The DOCKER chain is a custom chain defined at the FORWARD chain. When a packet hits any interface and is bound to the docker0 bridge interface, it is sent to the custom DOCKER chain.

pkts bytes target     prot opt in     out     source               destination         
54492   21M DOCKER     all  --  any    docker0  anywhere             anywhere            

Now the DOCKER chain will take all incoming packets, except ones coming from docker0, and send them to a container IP (172.x.x.x) and port, in this case say 7990.

pkts bytes target     prot opt in     out     source               destination         
   86  7048 ACCEPT     tcp  --  !docker0 docker0  anywhere             172.17.0.2           tcp dpt:7990

If you were to post the output of iptables -t nat -L -n, you would see the DNAT rule which does the host to container port forwarding, say packets hitting the host interface on 49154 would be port forwarded to container IP 172.17.0.2 and port 7990.

DNAT       tcp  --  0.0.0.0/0            0.0.0.0/0            tcp dpt:49154 to:172.17.0.2:7990

You can block the packets from hitting the container by limiting the source IP of any 0.0.0.0 to allowing only the packets originating from your internal network, for instance. To allow connections to the container port of 7990 only from your internal network of say 192.168.1.0/24, you can run the following command -

/sbin/iptables -I FORWARD '!' -s 192.168.1.0/24 -d 172.17.0.2 -p tcp --dport 7990 -j DROP

This would prevent forwarding any packets to a container of the specified IP:Port, unless they are coming from the internal network. You can modify the source/destination IP and port depending on your setup.

Daniel t.
  • 9,061
  • 1
  • 32
  • 36
  • thanks for your answer. I looked into using the negation of source addresses (! -s ) but the problem I have is that I need to allow multiple source ranges. This is not allowed when using negation as I guess it doesn't make sense to define a rule which effectively says "block everything except this range AND block everything except this other range". So how can I use what you've suggested when I have to allow multiple source IP ranges? – Richard Corfield May 15 '15 at 08:42
  • Are you getting any errors when you specify multiple sources or range? You should be able to define multiple IPs or even a range, say '-s' with the IPs separated in commas, or with `--src-range`. Check this link http://serverfault.com/questions/6989/iptables-multiple-source-ips – Daniel t. May 15 '15 at 22:02
  • Unfortunately the IP ranges I need to allow are not contiguous. It doesn't seem possible to use `--src-range` with a comma-separated list; I receive the following error: `iptables-restore v1.4.14: iprange: Bad value for "--src-range" ...`. If I try to use '-s' I get this error: `iptables-restore v1.4.14: ! not allowed with multiple source or destination IP addresses`. Hmmm. – Richard Corfield May 15 '15 at 22:44
  • The default policy is ACCEPT for the forward chain - `Chain FORWARD (policy ACCEPT)`. You might try reversing this, by setting the default policy to DROP and setting allow rules under it explicitly. – Daniel t. May 15 '15 at 22:50
  • You can see from my iptables listings above that the default policy for the FORWARD chain is already DROP. And since the first rule sends all packets to the DOCKER chain it's ineffective anyway. – Richard Corfield May 19 '15 at 15:49
  • Sorry I didn't notice that. Still the DROP policy on the FORWARD chain won't work as the DOCKER custom chain accepts everything. You could probably mimic a similar setup for the DOCKER chain, by first changing the `source anywhere` to the ones you want to explicitly allow, you can list them one source per line and add a `REJECT ALL` rule at the bottom. – Daniel t. May 20 '15 at 21:14
0

So, this would be a comment, but no stree.. serverfault rep for it.

Have you tried the solution posted here: http://blog.viktorpetersson.com/post/101707677489/the-dangers-of-ufw-docker

of using this flag --iptables=false like such DOCKER_OPTS="--dns 8.8.8.8 --dns 8.8.4.4 --iptables=false"?

  • 1
    That's interesting. I did look into `iptables=false` originally but the problem is I need to allow *some* external access from *some* external IP ranges. Setting `iptables=false` implies I'd have to manually set up all the rules I need, including the NAT(?) which seems like it would still be a lot of trouble. – Richard Corfield Jun 02 '15 at 14:44
  • 1
    how about using this: https://github.com/gdm85/docker-fw ? – João Antunes Jun 02 '15 at 16:16
  • 1
    Thanks; I did look at docker-fw, but did not succeed in figuring out how to use it correctly. Now that I have worked around this problem by setting the firewall rules at the Google Project level instead of on the machine my motivation to investigate it further has dwindled ... – Richard Corfield Jun 02 '15 at 20:15