Docker Networking Nightmare and UFW can't help you ;-;
Guys, Docker just fuck me up real hard ;-;
Realizing that my docker-based application has been open-naked to the public for months is fucked up dude.
Here is the breakdown of what happen and why and how to fix this.
7 Jul, I was casually browsing on shodan.io and tried one of my server IP addresses and it turned out that I have port 4040 opened. I even set my UFW rule to deny all that’s not whitelisted.
So, I reviewed all my docker-based service, and it turned out that all my docker services are reachable by the internet UNRESTRICTED
What Wrong?
we’re talking about Docker Compose here’s what docker-compose.yml usually looks like:
services:
app:
image: xxx
ports:
- "4040:4040"
volumes:
- .:/app
this configuration will expose ports to the internet through 0.0.0.0:4040
and nothing like UFW can prevent it from exposing to the internet.
because Docker is directly making changes on the Iptables level.
This is pretty serious in that it might unintentionally expose sensitive services that should not be exposed to the internet, exposed to the internet. without restriction.
Why?
referring to Docker Docs, traffic from/to containers is routed before INPUT/OUTPUT rules apply. This bypass all rules "effectively ignoring your firewall configuration."
How to fix
There are multiple ways to prevent Docker from exposing ports to the internet.
1. The most recommended way (by most tech websites) is to disable iptables for docker entirely
by editing /etc/docker/daemon.json
to disable it by:
{
"iptables" : false
}
I’ve tried this method and sadly doesn’t work. also, Docker Docs Recommend against this method quote "It is likely to break container networking for the Docker Engine"
2. Next up, “User-defined networks”.
You just need to create a network driver and use this network driver to communicate with another Docker Container.
Tho, this is recommended if you are just going to use your docker container internally or between docker containers.
Excerpt from Archivebox Docker-compose.yml here’s what User-defined networks looks like:
# using network driver name "dns" and set dns address to "172.20.0.53" for the "main" the container
services:
archivebox:
image: archivebox/archivebox:latest
ports:
- 8000:8000
networks:
- dns
dns:
- 172.20.0.53
# Setup IPv4 address for pi-hole container
pihole:
image: pihole/pihole:latest
networks:
dns:
ipv4_address: 172.20.0.53
# Network driver setup
networks:
# network just used for pihole container to offer :53 dns resolving on fixed ip for archivebox container
# Learn more : https://docs.docker.com/compose/networking/
dns:
ipam:
driver: default
config:
- subnet: 172.20.0.0/24 # Here is subnet for internal Docker Network ip address
3. Publish port cautiously on specified network Interfaces
This method is the easiest way, you just have to specify your network interfaces when config your docker-compose.yml
for example, you need to forward port 4040
of your host to 8080
on the docker host:
ports:
- "127.0.0.1:4040:8080"
This will exposing your docker container on port 8080
to 127.0.0.1:4000
on your local network, NOT THE INTERNET!
What I Learned from the incident
First, internet scanners like shodan/censys are very useful for detecting an accidental expose.
Second, Never trust certain software too much! this is really important in this case i trusted UFW’s ability to block traffic so much that I didn’t even ever check for port leaks. So, this simple issue remain under radar for years!
Aside from that don’t forget to check your docker-compose.yml
file when hosting new software for potential port leaks, because most docker-focused projects would always(if not mostly) expose their service to the internet via something like 4040:4040
in their default docker-compose.yml
file.
And now your service should be safe from an unwanted attention!
References:
-
https://stackoverflow.com/questions/30383845/what-is-the-best-practice-of-docker-ufw-under-ubuntu
-
https://stackoverflow.com/questions/73916855/ufw-seems-not-to-block-all-ports-ubuntu-with-docker
-
https://forums.docker.com/t/running-multiple-docker-containers-with-ufw-and-iptables-false/8953
Note: this is the longest article I have written in years, if anyone has a comment please leave one! via My E-Mail or GitHub issue!