Block outgoing connections to private IPs from Docker containers
Asked Answered
R

2

13

Some of the services that we run on our servers with Docker, try to connect to private IP addresses (10.0.0.0/8, 192.0.0.0/16, 172.16.0.0/12, 100.64.0.0/10).

This behavior is normal but our server provider detects this traffic and sends us alerts.

We would like to stop only the outgoing traffic, not the incoming with iptables.

This is our current setup:

-A OUTPUT -d 192.168.0.0/16 -m owner --uid-owner `id -u dockeruser` -j REJECT --reject-with icmp-port-unreachable
-A OUTPUT -d 100.64.0.0/10 -m owner --uid-owner `id -u dockeruser` -j REJECT --reject-with icmp-port-unreachable
-A OUTPUT -d 172.16.0.0/12 -m owner --uid-owner `id -u dockeruser` -j REJECT --reject-with icmp-port-unreachable
-A OUTPUT -d 10.0.0.0/8 -m owner --uid-owner `id -u dockeruser` -j REJECT --reject-with icmp-port-unreachable

However this doesn't seem to work because Docker creates the following rules:

Chain FORWARD (policy ACCEPT)
target     prot opt source               destination
DOCKER-ISOLATION  all  --  anywhere             anywhere
DOCKER     all  --  anywhere             anywhere

For the services:

Chain DOCKER (1 references)
target     prot opt source               destination
ACCEPT     tcp  --  anywhere             172.17.0.2           tcp dpt:1234
ACCEPT     tcp  --  anywhere             172.17.0.4           tcp dpt:1234

Finally:

Chain DOCKER-ISOLATION (1 references)
target     prot opt source               destination
RETURN     all  --  anywhere             anywhere

Any feedback is appreciated.

Ridgeling answered 12/12, 2016 at 18:16 Comment(3)
I'm not an iptables expert, but you can stop Docker modifying your iptables by passing --iptables=false as a flag to the daemon when starting it.Lyons
Thanks for the advice, but we want Docker to add it's own firewall rulesRidgeling
All or nothing atm afaik.Lyons
A
11

You are adding the rules in the wrong chain. The traffic that is originated from a docker container passes through the FORWARD chain of the filter table, not the OUTPUT chain. This is because from the host computer's perspective, the traffic is incoming from the docker0 interface, and the host computer is merely acting as a forwarder.

In order to differentiate between inbound and outbound traffic, use the -i and -o options to specify interface. Also you can't use uid to determine whether the traffic is coming from a docker container (since the data is not locally originated). Checking incoming interface is enough for that.

So, add the following rules to the DOCKER-ISOLATION chain (which is being called from the FORWARD chain):

-A DOCKER-ISOLATION -d 192.168.0.0/16 -i docker0 ! -o docker0 -j REJECT --reject-with icmp-port-unreachable
-A DOCKER-ISOLATION -d 100.64.0.0/10 -i docker0 ! -o docker0 -j REJECT --reject-with icmp-port-unreachable
-A DOCKER-ISOLATION -d 172.16.0.0/12 -i docker0 ! -o docker0 -j REJECT --reject-with icmp-port-unreachable
-A DOCKER-ISOLATION -d 10.0.0.0/8 -i docker0 ! -o docker0 -j REJECT --reject-with icmp-port-unreachable

Replace docker0 by name of the virtual interface created by docker.

(Note: If the chain DOCKER-ISOLATION doesn't exist, append directly to FORWARD chain).

Also look at the output of iptables -vL and iptables -t nat -vL to better understand how addresses are being translated.

Alodee answered 14/12, 2016 at 7:40 Comment(3)
The original answer didn't work until we insert the rules to the FORWARD chain in the first positions with -I FORWARD 1. I have edited your answer but if it against the rules, please update it yourself so other people can benefit.Ridgeling
Inserting these rules in beginning of FORWARD chain is not a good idea, since it would prevent incoming traffic from these IP ranges (which you want to allow). Either append at the end of FORWARD chain, or if you have a chain named DOCKER-ISOLATION, append to it.Alodee
Original answer didn't work because DOCKER chain is only used for outgoing traffic (docker0 to physical interface). I've edited the answer.Alodee
E
1

Can't comment under the accepted answer, so here's my solution:

Docker provides it's own special DOCKER-USER chain that is designed to be used before any other chain:

Chain FORWARD (policy DROP 0 packets, 0 bytes)
pkts bytes target                   prot opt in      out       source     destination
0    0     DOCKER-USER              all  --  any     any       anywhere   anywhere
0    0     DOCKER-ISOLATION-STAGE-1 all  --  any     any       anywhere   anywhere            
0    0     ACCEPT                   all  --  any     docker0   anywhere   anywhere    ctstate RELATED,ESTABLISHED
0    0     DOCKER                   all  --  any     docker0   anywhere   anywhere            
0    0     ACCEPT                   all  --  docker0 !docker0  anywhere   anywhere            
0    0     ACCEPT                   all  --  docker0 docker0   anywhere   anywhere

So now you can just add add a new deny rules like this:

-I DOCKER-USER -p tcp -d 10.0.0.0/8 --dport 443 -j DROP
Ecto answered 2/11, 2021 at 12:42 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.