Uncomplicated Firewall (UFW) is the default firewall configuration tool for Ubuntu. It’s easy to configure and easy to manage by an amateur like me. It’s disabled by default but you can enable UFW easily with the default set of rules like this:

sudo ufw enable

Now, in my setup I am running Ubuntu Server 16.04 as a virtual machine on my Macbook. In the server I have a Postgres container.

$ docker run --name test_postgres -e POSTGRES_PASSWORD=mysecretpassword -p 5432:5432 postgres 
$ docker ps -a | grep postgres
$ dd10fc032a12        postgres    "docker-entrypoint.s…"   28 seconds ago      Up 26 seconds                5432/tcp

The database can be accessible by other containers in the server but it should not be accessed by anyone outside of my virtual machine.

If you have paid attention to your networking lecture, the usual practice is to deny all incoming traffic and only allow some ports to be exposed to the outside world. In my case, I need SSH to be accessible outside of the host.

$ sudo ufw default deny incoming
Default incoming policy changed to 'deny'
$ sudo ufw allow ssh
Rule added
Rule added (v6)
$ sudo ufw reload
Firewall reloaded
$ sudo ufw status
Status: active

To                         Action      From
--                         ------      ----
22                         ALLOW       Anywhere
22 (v6)                    ALLOW       Anywhere (v6)

This should be sufficient to help us block anyone from accessing our container in the server… or not.

To test that no one outside of the virtual machine can connect to the Postgres server, I used pgAdmin4 on my Macbook and attempted to establish a connection to the container. And guess what? I was actually able to connect to the Postgres instance successfully!

This cannot be right as we have already block all incoming traffic except for SSH services. So what has gone wrong? Now, let’s check our iptables:

$ sudo iptables --list | grep postgresql
ACCEPT     tcp  --  anywhere             172.17.0.2           tcp dpt:postgresql

Hah, so it turns out that Docker has modified iptables directly to allow the container to bind to port 5432. To prevent Docker from modifying iptables, we will need to set iptables key to be false in /etc/docker/daemon.json.

I didn’t have that file in my folder so I went ahead to create the file.

$ sudo vim /etc/docker/daemon.json

Following the guide, I added the following content in the file:

{
    "iptables": false
}

Lastly, I restarted Docker.

sudo systemctl restart docker

Andddddddddddd it finally works!

The downside is that your docker can never be connected outside of your host machine by default. You can change the behaviour by adding appropriate rules via ufw or iptables.

References