I use nftables to set my firewall rules. I typically manually configure the rules myself. Recently, I just happened to dump the ruleset, and, much to my surprise, my config was gone, and it was replaced with an enourmous amount of extremely cryptic firewall rules. After a quick examination of the rules, I found that it was Docker that had modified them. And after some brief research, I found a number of open issues, just like this one, of people complaining about this behaviour. I think it’s an enourmous security risk to have Docker silently do this by default.
I have heard that Podman doesn’t suffer from this issue, as it is daemonless. If that is true, I will certainly be switching from Docker to Podman.
This is standard, but often unwanted, behavior of docker.
Docker creates a bunch of chain rules, but IIRC, doesn’t modify actual incoming rules (at least it doesn’t for me) it just will make a chain rule for every internal docker network item to make sure all of the services can contact each other.
Yes it is a security risk, but if you don’t have all ports forwarded, someone would still have to breach your internal network IIRC, so you would have many many more problems than docker.
I think from the dev’s point of view (not that it is right or wrong), this is intended behavior simply because if docker didn’t do this, they would get 1,000 issues opened per day of people saying containers don’t work when they forgot to add a firewall rules for a new container.
Option to disable this behavior would be 100x better then current, but what do I know lol
My problem with this, is that when running a public facing server, this ends up with people exposing containers that really, really shouldn’t be exposed.
Excerpt from another comment of mine:
It’s only docker where you have to deal with something like this:
--- services: webtop: image: lscr.io/linuxserver/webtop:latest container_name: webtop security_opt: - seccomp:unconfined #optional environment: - PUID=1000 - PGID=1000 - TZ=Etc/UTC - SUBFOLDER=/ #optional - TITLE=Webtop #optional volumes: - /path/to/data:/config - /var/run/docker.sock:/var/run/docker.sock #optional ports: - 3000:3000 - 3001:3001 restart: unless-stopped
Originally from here, edited for brevity.
Resulting in exposed services. Feel free to look at shodan or zoomeye, internet connected search engines, for exposed versions of this service. This service is highly dangerous to expose, as it gives people an in to your system via the docker socket.
But… You literally have ports rules in there. Rules that expose ports.
You don’t get to grumble that docker is doing something when you’re telling it to do it
Dockers manipulation of nftables is pretty well defined in their documentation. If you dig deep everything is tagged and natted through to the docker internal networks.
As to the usage of the docker socket that is widely advised against unless you really know what you’re doing.
Documentation people don’t read. People expect, that, like most other services, docker binds to ports/addresses behind the firewall. Literally no other container runtime/engine does this, including, notably, podman.
Too bad people don’t read that advice. They just deploy the webtop docker compose, without understanding what any of it is. I like (hate?) linuxserver’s webtop, because it’s an example of the two of the worst footguns in docker in one
To include the rest of my comment that I linked to:
You originally stated:
And I’m trying to say that even if that was true, it would still be better than a footgun where people expose stuff that’s not supposed to be exposed.
But that isn’t the case for podman. A quick look through the github issues for podman, and I don’t see it inundated with newbies asking “how to expose services?” because they assume the firewall port needs to be opened, probably. Instead, there are bug reports in the opposite direction, like this one, where services are being exposed despite the firewall being up.
(I don’t have anything against you, I just really hate the way docker does things.)
Sure, I get it, this stuff should be accessible for all. Easy to use with sane defaults and all that. But at the end of the day anyone wanting to using this stuff is exposing potential/actual vulnerabilites to the internet (via the OS, the software stack, the configuration, … ad nauseum), and the management and ultimate responsibility for that falls on their shoulders.
If they’re not doing the absolute minimum of R’ingTFM for something as complex as Docker then what else has been missed?
Unless you tell it otherwise that’s exactly what it does. If you don’t bind ports good luck accessing your NAT’d 172.17.0.x:3001 service from the internet. Podman has the exact same functionality.
So uh, I just spun up a vps a couple days ago, few docker containers, usual security best practices… I used ufw to block all and open only ssh and a couple others, as that’s what I’ve been told that I need to do. Should I be panicking about my containers fucking with the firewall?
Docker will have only exposed container ports if you told it to.
If you used
-p 8080:80
(cli) or- 8080:80
(docker-compose) then docker will have dutifully NAT’d those ports through your firewall. You can either not do either of those if it’s a port you don’t want exposed or as @[email protected] says below you can ensure it’s only mapped to localhost (or an otherwise non-public) IP.Thanks - more detailed reply below :)
Actually, ufw has its own separate issue you may need to deal with. (Or bind ports to localhost/127.0.0.1 as others have stated.)
Prevent docker from manipulating iptables
Don’t know what it’s actually doing, I’m just learning how to work with nftables, but I saved that link in case oneday I want to manage the iptables rules myself :)
Good luck. Your going to have to change the rules whenever the up address of the container changes.
If you are talking about the IP address then just add a static address, no? I do it anyway in my docker compose:
... networks: traefik.net: ipv4_address: 10.10.10.99 networks: traefik.net: name: traefik-net external: true
I’m not an expert so maybe I’m wrong, if so do not hesitate to correct me !
EDIT: If the IP address doesn’t change, you do not need to change to routing and iptables/nftables rules. ??
How come I don’t see my previous rules when I dump the ruleset, then? I have my rules written in
/etc/nftables.conf
, and they were previously applied by running# nft -f /etc/nftables.conf
. Now, when I dump the current ruleset with# nft list ruleset
, those previous rules aren’t there — all I see are Docker’s rules.That assumes you’re on some VPS with a hardware firewall in front.
Often enough you’re on a dedicated server that’s directly exposed to the internet, with those iptables rules being the only thing standing between your services and the internet.
What difference does it make if you open the ports yourself for the services you expose, or Docker does it for you? That’s all that Docker is meant to do, act as convenience so you don’t have to add/remove rules as the containers go up/down, or remember Docker interfaces.
If by any chance you are making services listen on 0.0.0.0 and covering them up with a firewall that’s very bad practice.
There’s no alternative for 0.0.0.0 and a firewall if you’re e.g. using kubernetes.
I’m fairly sure you can find an alternative to whatever problem you’re having.
You need to be able to have multiple nodes in one LAN access ports on each others’ containers without exposing those to the world and without using additional firewalls in front of the nodes.
That’s why kubernetes ended up removing docker support and instead recommends podman or using containerd natively.