UFW Docker eperience

Disclamer: I am not a network expert. I am a full stack software engineer that has interests in infrastucture and networking. So i try to learn every day. If there is anything wrong or missundestood please contact me!

I installed ufw-docker on a system to test around with docker and ufw in my homelab. I wanted to learn how docker works with iptables and how i can block traffic to opended ports via docker. Core question was: how to only allow some users with a special ip to consume my service?

So i created an new virtual ubuntu machine and installed docker (compose) and ufw first.

I found a solution with ufw-docker that did not really worked out for me in the first place. So i tried to understand how it works / does not work for me.

Lab Setup - VM

The full installation guide to install the recent version of docker on a ubuntu maschine, follow the instructions on the docker site. Here in short:

# Add Docker's official GPG key:
sudo apt-get update
sudo apt-get install ca-certificates curl
sudo install -m 0755 -d /etc/apt/keyrings
sudo curl -fsSL https://download.docker.com/linux/ubuntu/gpg -o /etc/apt/keyrings/docker.asc
sudo chmod a+r /etc/apt/keyrings/docker.asc

# Add the repository to Apt sources:
echo \
  "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.asc] https://download.docker.com/linux/ubuntu \
  $(. /etc/os-release && echo "$VERSION_CODENAME") stable" | \
  sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
sudo apt-get update

# Install the latest version of docker and docker-compose
sudo apt-get install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin

Now install and activate ufw if not already happened. I used a virtual machine on my proxmox host to test this. So I had to allow SSH before activating the firewall.

sudo apt-get install ufw
sudo ufw allow 22/tcp
sudo systemctl restart ufw

Lab Setup - Docker Compose

After installing everything I created the test compose.yml that contains the setup for my tests. It's a very simple setup.

networks:
  ufw_test:
    driver: bridge
    driver_opts:
      com.docker.network.bridge.name: br-ufw-test
    ipam:
      config:
        - subnet: 192.168.33.0/24
          gateway: 192.168.33.1

services:
  webserver:
    container_name: webserver
    image: bitnami/nginx
    ports:
      - 8080:8080
    networks:
      ufw_test:
        ipv4_address: 192.168.33.2
  curl:
    container_name: curl
    image: curlimages/curl
    command:
      - sleep
      - infinity
    networks:
      ufw_test:
        ipv4_address: 192.168.33.3

The avoid random network creation with docker compose i defined my own network to have the full control. Spolier: this makes it easier when using ufw to allow specific requests through the network.

ufw_test the networks name and it is a bridge to our host network. As additionals driver option com.docker.network.bridge.name: br-ufw-test i defined to force use a static name for the network. In addition i defined the network configuration via ipam. After starting docker compose you can see the interface with ip a

$ ip a
...
59: br-ufw-test: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default
    link/ether 02:42:6a:90:42:8b brd ff:ff:ff:ff:ff:ff
    inet 192.168.33.1/24 brd 192.168.33.255 scope global br-ufw-test
       valid_lft forever preferred_lft forever
    inet6 fe80::42:6aff:fe90:428b/64 scope link
...

This compose file defines two containers:

This then is the network topology of my test lab:

The plugin you are using seems to generated a bad URL.This URL does not look like HUFFMAN data. See https://plantuml.com/text-encoding You may contact the PlantUML team at plantuml@gmail.comBut you should also probably contact the plugin authors you are currently using and send them this image For the record, here is your data: SoWkIImgAStDuKhEpot8pqlDAr58oyz7uYKb5d4vfEQb0000

Problem

I assumed i wanted to limit the access to the webserver container to

Simply disabling the container access with ufw does not end in the wanted result:

ufw deny 8080/tcp

The reason is that docker uses iptables to route traffic to the opened ports of a container. You can see this with the following command:

iptables -L ...

As you can see the forwording rule hits before the ufw rule so our deny rule becomes ignored.

ufw-docker

When searching i found ufw-docker which promises to add additional configuration to provide configuration to ufw rules. To install it you have to download the script and installed:

sudo wget -O /usr/local/bin/ufw-docker \
  https://github.com/chaifeng/ufw-docker/raw/master/ufw-docker
sudo chmod +x /usr/local/bin/ufw-docker

ufw-docker install

view details on page

This is the entry the script adds to the iptables config:

# BEGIN UFW AND DOCKER
*filter
:ufw-user-forward - [0:0]
:ufw-docker-logging-deny - [0:0]
:DOCKER-USER - [0:0]
-A DOCKER-USER -j ufw-user-forward

-A DOCKER-USER -j RETURN -s 10.0.0.0/8
-A DOCKER-USER -j RETURN -s 172.16.0.0/12
-A DOCKER-USER -j RETURN -s 192.168.0.0/16

-A DOCKER-USER -p udp -m udp --sport 53 --dport 1024:65535 -j RETURN

-A DOCKER-USER -j ufw-docker-logging-deny -p tcp -m tcp --tcp-flags FIN,SYN,RST,ACK SYN -d 192.168.0.0/16
-A DOCKER-USER -j ufw-docker-logging-deny -p tcp -m tcp --tcp-flags FIN,SYN,RST,ACK SYN -d 10.0.0.0/8
-A DOCKER-USER -j ufw-docker-logging-deny -p tcp -m tcp --tcp-flags FIN,SYN,RST,ACK SYN -d 172.16.0.0/12
-A DOCKER-USER -j ufw-docker-logging-deny -p udp -m udp --dport 0:32767 -d 192.168.0.0/16
-A DOCKER-USER -j ufw-docker-logging-deny -p udp -m udp --dport 0:32767 -d 10.0.0.0/8
-A DOCKER-USER -j ufw-docker-logging-deny -p udp -m udp --dport 0:32767 -d 172.16.0.0/12

-A DOCKER-USER -j RETURN

-A ufw-docker-logging-deny -m limit --limit 3/min --limit-burst 10 -j LOG --log-prefix "[UFW DOCKER BLOCK] "
-A ufw-docker-logging-deny -j DROP

COMMIT
# END UFW AND DOCKER

In my tests i reached the problem that i still can reach the port 192.168.33.2:8080.

HOW TO USE UFW_DOCKER

I thought i missconfigured something. So i digged deeper in the configuration of ufw-docker and found the following lines:

-A DOCKER-USER -j RETURN -s 10.0.0.0/8
-A DOCKER-USER -j RETURN -s 172.16.0.0/12
-A DOCKER-USER -j RETURN -s 192.168.0.0/16

The comment on the website was:

The following rules allow the private networks to be able to visit each other. Normally, private networks are more trusted than public networks.

This made me thinking. If i install a server in a network and use ufw, then it is not quite the case that i trust everyone. I do not know who is also part of the network so i want ufw to lock everything up. So i deleted that lines. With the wanted result, that i could not reach the webserver port when run the following curl command: ... But in addition i also wasn't able to curl it within the docker network. That was not what i wanted to accieve. ...

To allow traffic flow within the network i allowed routing on the named network

ufw route allow in on br-ufw-test out on br-ufw-test

allow routing inside the container network

$ ufw route allow in on br-ufw-test out on br-ufw-test

$ ufw route allow in on eth0 to 192.168.33.2 port 8080 proto tcp

Fazit: If someone else also got this problem, found a different easier solution or sees an error in my solution: let me know and /contact me.

Comments (0)

No comments yet. Be the first to comment!

Leave a Comment

Your email will not be published.
0 / 2000 characters

Your comment will be reviewed before appearing on the site.

← Back to all posts