Docker on Debian / Ubuntu not respecting ufw firewall settings exposing ports

9 December 2019 by Peter
In Docker

Docker bypasses ufw firewall settings and exposes ports to the outside world, a very serious security leak.

post main image
https://unsplash.com/@andrewtneel

Again another unexpected Docker issue. In a previous post I described why and how you must force Docker to use a subnet, to prevent sudden unexpected changes in the network with consequences like mail no longer working.

This post is about Docker not respecting firewall settings, at least when running Debian / Ubuntu and ufw (Uncomplicated Firewall). Docker does not tell you this, and exposes ports, so this behavior is totally unexpected.

My ISPConfig server is running Debian Stretch. I use ufw as a firewall, below are the main settings.

ufw status verbose
Status: active
Logging: on (low)
Default: deny (incoming), allow (outgoing), deny (routed)
New profiles: skip

To                         Action      From
--                         ------      ----
22/tcp                     ALLOW IN    Anywhere                  
80/tcp                     ALLOW IN    Anywhere                  
443/tcp                    ALLOW IN    Anywhere                  
8080/tcp                   ALLOW IN    Anywhere                  
25                         ALLOW IN    Anywhere       

As you can see, all incoming connections are blocked except a few allowed.

My Docker Python web applications use the Gunicorn WSGI HTTP server to serve the Python Flask app. Nginx is running on the host and is configured as a reverse proxy for these applications. Works like a charm. In the docker-compose.yml file the ports are loaded from the .env file:

services:
  web:
    ...
    env_file:
      - ./.env

    ports:
      - "${SERVER_PORT_HOST}:${SERVER_PORT_CONTAINER}"

For one application .env file contains these lines:

SERVER_PORT_HOST=8001
SERVER_PORT_CONTAINER=8001

So in effect the docker-compose line that is used is:

    ports:
      - "8001:8001"

The problem: Docker port 8001 is exposed to the outside network even if ufw is configured to block incoming connections.

This means that the Docker application/service also is visible at <SERVER-IP>:8001. This not only is very bad, it is also totally unexpected as ufw was configured to block all incoming connections.

Solutions

There are several solutions to this, here I choose to bind the port to the host machine. The docker-compose.yml lines then become:

    ports:
      - "127.0.0.1:8001:8001"

This works for me.

Other ways to solve this are to prevent Docker messing with the firewall, add rules to the ufw file /etc/ufw/after.rules, etc. See links below.

Summary

Some people consider this Docker behavior as a bug, and I can only agree to this. Ufw is a firewall, a very important program to control security. Ufw is very widely used and if another program bypasses its behavior the user must be informed. Until this is fixed, at minimum Docker should issue a big warning message when starting an application.

Links / credits

Be careful with Docker ports!
https://dev.to/kovah/be-careful-with-docker-ports-3pih

Docker service exposed publicly though made to expose ports to localhost only
https://stackoverflow.com/questions/50621936/docker-service-exposed-publicly-though-made-to-expose-ports-to-localhost-only

Docker services only available to the local host
https://stackoverflow.com/questions/54261105/docker-services-only-available-to-the-local-host

How to fix the Docker and UFW security flaw
https://www.techrepublic.com/article/how-to-fix-the-docker-and-ufw-security-flaw/

The dangers of UFW + Docker
https://blog.viktorpetersson.com/2014/11/03/the-dangers-of-ufw-docker.html

What is the best practice of docker + ufw under Ubuntu
https://stackoverflow.com/questions/30383845/what-is-the-best-practice-of-docker-ufw-under-ubuntu