ubuntudockercontainersfirewalliptables

What is the best practice of docker + ufw under Ubuntu


I just tried out Docker. It is awesome but seems not work nicely with ufw. By default, docker will manipulate the iptables a little bit. The outcome is not a bug but not what I expected. For more details you can read The dangers of UFW + Docker

My goal is to set up a system like

    Host (running ufw) -> docker container 1 - nginx (as a reverse proxy)
                       -> docker container 2 - node web 1
                       -> docker container 3 - node web 2
                       -> .......

I want to manage the incoming traffic (e.g. restrict access) through ufw therefore I don't want docker to touch my iptables. Here is my test

Environment:

First Attempt

docker run --name ghost -v /home/xxxx/ghost_content:/var/lib/ghost -d ghost
docker run --name nginx -p 80:80 -v /home/xxxx/nginx_site_enable:/etc/nginx/conf.d:ro --link ghost:ghost -d nginx

No luck. The first command is fine but the second command will throw an error

Error response from daemon: Cannot start container

Second Attempt

Then I found this: unable to link containers with --iptables=false #12701

After running the following command, everything looks OK.

sudo iptables -N DOCKER

However, I noticed that I can not establish any outbound connections inside containers. For example:

xxxxg@ubuntu:~$ sudo docker exec -t -i nginx /bin/bash
root@b0d33f22d3f4:/# ping 74.125.21.147
PING 74.125.21.147 (74.125.21.147): 56 data bytes
^C--- 74.125.21.147 ping statistics ---
35 packets transmitted, 0 packets received, 100% packet loss
root@b0d33f22d3f4:/# 

If I remove --iptables=false from the Docker daemon, then the internet connection of containers will be back to normal but the ufw will not work 'properly' (well...by my definition).

So, what is the best practice of docker + ufw? Can anyone provide some help?


Solution

  • I've had such problem like months ago and lately decided to describe the issue along with the solution on my blog. Here's the shortcut.

    Using --iptables=false won't help you much with the case you described. It's simply not enough here. By default, none of your containers can do any outgoing connection.

    There's a small step you're omitting on your way to have containers behind UFW here. You can use --iptables=false or create /etc/docker/daemon.json file with content as follows

    {
      "iptables": false
    }
    

    the result will be the same, but the latter option requires you to restart whole docker service with service docker restart or even do a reboot if docker had a chance to add iptables rules before you disabled this function.

    When it's done, just do two more things:

    $ sed -i -e 's/DEFAULT_FORWARD_POLICY="DROP"/DEFAULT_FORWARD_POLICY="ACCEPT"/g' /etc/default/ufw
    $ ufw reload
    

    so you set up default forward policy in UFW for accept, and use:

    $ iptables -t nat -A POSTROUTING ! -o docker0 -s 172.17.0.0/16 -j MASQUERADE
    

    That way what you're achieving is disabling docker messy behavior in your iptables rules and at the same time docker is provided with necessary routing so containers will do outgoing connections just fine. UFW rules will be still restricted from this point on, though.

    Hope this resolves the issue for you and any that gets here in search of an answer.

    I described the problem and solution more comprehensively at https://www.mkubaczyk.com/2017/09/05/force-docker-not-bypass-ufw-rules-ubuntu-16-04/