I just learned: Docker edits firewall rules for you
geoff.tuxpup.com
geoff.tuxpup.com
K8s at least offers more fine-grained control over networking, between port range restrictions and having to enable a NodePort.
From https://zwischenzugs.com/2015/06/24/the-most-pointless-docke... anyone with Docker access gets root with that command.
TBH out of the box Kubernetes is as bad, or worse than docker, in that anyone with create pod permissions can get root on every worker node in the cluster (and the control plane nodes if it's unmanaged Kubernetes) https://raesene.github.io/blog/2019/04/01/The-most-pointless...
We evolved sysadmin oposing thumbs called virtual machines just to deal with our environment making it cheaper to emulate an entire other computer instead of dealing with having a user without write access, guaranteed, on the FS.
It would still catch people who bind to 0.0.0.0 and expect the traffic to be blocked by UFW, but that's a different issue. `iptables: false` is a very crude solution, they should offer something like `iptables: "manual"` where Docker only touches its own iptables chains and lets you wire them up to your own UFW/iptables chains in a sane way.
I can't think of another application on any of my systems that muck with firewall rules behind the scenes like this.
This is a case where a tool you trust (ufw) lies to you because Docker not only unexpectedly adds iptables rules for simple scenarios, but adds them at a higher priority than your firewall. Software doesn't normally modify your firewall when it binds to a port, and firewalls exist to restrict port exposure.
Docker adding iptables rules is understandable once you realize the full power of Docker networking, but I feel it's reasonable for people to not predict that behavior, given such power is beyond many people's use cases. (FWIW, rootless podman doesn't alter iptables, validating the proposition that using Docker in simple scenarios doesn't lend itself to a mental model that predicts iptables changes).
If Docker was a simple tool with brief docs, I could agree, but Docker's docs are so extensive that knowing everything it does isn't practical. One just has to hope they stumble into docs on footguns. It's hard for me to call this behavior "obvious" without basically invalidating footguns as an idea.
Adding to this. I really don't blame people (not even my past self) for:
* Expecting `-p 8001:8002` to behave the same way as the unprivileged `ssh -L 0.0.0.0:8001:${CONTAINER_IP_IN_ONE_DOCKER_SUBNET}:8002`.
* Expecting `ufw` to pickup changes in firewall rules.
* Trusting the offline `man 1 docker-run`.
Even knowing what I know now (I'm still pretty ignorant, but a little bit less than in the past), I still consider this a bad default from the Docker CLI.
Yes, `docker run` needs privileges for other stuff, but since the forwarding part can be done without punching a hole, I don't think it's unreasonable to expect it to be done that way.
Even just mentioning the word "iptables" in `docker-run(1)` would go a long way.
I think the firewall is my business, and nothing else should automatically open ports in it. Especially not docker.
https://github.com/moby/moby/issues/22054
It's completely asinine.
Very much a case of "make sure you use some sort of overarching firewall solution" wrapping your Docker hosts, otherwise you can be in for a world of hurt. :/
Their support for IPv6 used to be extremely shitty too, with the documented switch to enable it... not working at all. Heh. ;)
The IPv6 thing may or may not be better now, but I haven't tried Docker with IPv6 in years so no idea.
Docker doesn't expose anything to the public interface unless you specifically request that it does.
If you don't understand the implications of this, you should not be running servers.
It is absolute shite at doing IPv6, which is annoying.
Heh Heh Heh.
Having directly been involved in the clean up of it doing exactly that a few years ago, I'll just say that your confidence is dangerously misplaced. :(
What did you do, what did you get wrong, and why did it need "cleaned up"?
Should all programs running as root bypass a firewall explicitly configured by the user?
What is a published port? Again, look in the documentation, it's clearly states there [1].
You need to learn to read the documentation of potentially dangerous tools fully. If you don't, you're in for a world of hurt. The outside world is clearly just that.
[0]: https://docs.docker.com/compose/compose-file/compose-file-v3... [1]: https://docs.docker.com/config/containers/container-networki...
What you expect does not matter. What you're thinking of is exposing. It's even in the word "publish".
The documentation has two sections entirely devoted to the terms. It's in the section "container networking", which is marked as required reading by the docs.
It's not dockers fault that you're copy pasting configuration examples from medium blogs.
[0]: https://docs.docker.com/config/containers/container-networki...
> This creates a firewall rule in the container
We’re done here.
Many times you don't even want docker containers to go "to the network" directly and it shouldn't assume unsecure behaviour by default.
Moreover, CRITICALLY, you can't prevent Docker from doing that and you can ONLY secure the machine by adding another rule on top that supresses Dockers rule... and those dockers rule change over time making it easy for the blocking hack to stop working after an update and again make the machine unsecure.
But you've typed in a command that explicitly will alter the iptables rules, as documented, and as you have requested
> Many times you don't even want docker containers to go "to the network" directly and it shouldn't assume unsecure behaviour by default.
Docker containers do not have a network connection outside their own subnet by default, and only expose the ports that they have explicitly been configured in the Dockerfile to expose.
By determining the container's IP address you can talk to it directly but this is not really recommended, because it can and will change. This internal IP address is by default in an RFC1918 range, and will not be in any way accessible from the outside world.
> Moreover, CRITICALLY, you can't prevent Docker from doing that and you can ONLY secure the machine by adding another rule on top that supresses Dockers rule... and those dockers rule change over time making it easy for the blocking hack to stop working after an update and again make the machine unsecure.
You can prevent Docker from doing that, by not adding into the command line the additional option that tells it to hook containers up directly to the "outside world" interface bypassing any firewall you might set.
You choose to do this. Docker assumes that you know what you‘re doing.
You‘re also wrong in your last paragraph. There is the - easy - option to expose the port on your loopback, and re route to the docker bridge network by using a reverse proxy.
Also, comparing expectations of Docker vs. something like nginx is crazy.
Like what is, having full control over your own system? I don’t think there’s anything wrong with not messing with my firewall and leaving this part to me.
> is crazy
And this is why, exactly?
You could choose not to install docker, for once.
I came up with some rules including DOCKER-USER chain but I'd qualify them as hack relying on undocumented configuration. And I just have no idea how to configure firewalld because it puts another layer of complexity on top of iptables.
At least, in the sense that if you use nftables (the high level tooling/config) and firewalld (the high level tooling/config), there will be some incompatibilities.
So it's either/or.
(Yes yes I know iptables is antiquated but they should still be compatible with each other at the kernel level)
Personally I think the real problem here is docker. Injecting rules into iptables is a bit like blindly injecting lines of code into someone else's program sight unseen. I'm not aware of any other tools that are nearly so willing to do so.
edit to add: after reading the article completely, a few things stand out.
1. It is clear the author does not understand the details of the compose file and is new to Docker.
2. Proposed solution is also incomplete
3. Not understanding why you would want to wrap caddy (even though it's a static binary) in the same system is missing the point.
4. Blaming Docker for clear user error is crazy.
[0]: https://blog.hmrt.nl/posts/first_steps_arch_box/#set-up-tail...
I’ve stopped using ports after having a redis instance taken over by some crypto miner.
You just need to ensure that you're only exposing the *right* ports, and aren't just blindly opening everything up to the world.
By default nothing is exposed to the world. You do not need to expose your Redis server's port to anything.
If he'd bind the host port to localhost or put caddy in a container in the same vlan, it wouldn't have happened. From the blogpost I'm not even sure if he's aware of the binding option.
If you argue that a software shouldn't behave this way after being configured so explicitly, Archlinux not preconfiguring iptables to limit exposure like Debian or Ubuntu is worse, because it happens implicitly.
Hell, in the "container networking" docs, it even says it doesn't: "By default, when you create or run a container using docker create or docker run, the container doesn’t expose any of it’s ports to the outside world."
And archlinux not preconfiguring iptables is a very, very archlinux-y thing to do -- not sure what your point on that is supposed to be there.
If you don’t read the docs you don’t get to complain when you don’t understand the behavior.
Edit: the second paragraph on the first search result for “docker networking” says that because it’s trying to present things in a platform independent way the overview won’t cover iptables specifics and then links to the detailed docs of how it uses iptables. If you can’t read two paragraphs maybe don’t try to be an engineer.
It's insane to build something that optimizes ease of use, and then require users to understand it in depth to avoid footgunning.
If https://www.portainer.io/ would do this implicitly, your argument would be more valid. But for the docker command-line it's a bit too far-fetched.
Heck, this “issue” (which, I don’t agree is an issue) only exists so that people don't have to do an additional step. Its “ease of use” which violates the principle of least surprise most commonly.
Docker does not compete with LXD which just runs containers like VMs, but with distrobuilder + LXD + including the init.yml in the deploy process.
You must explicitly expose them.
If you expose everything else too, that's no-one's fault but yours.
Furthermore, the "container networking" page (https://docs.docker.com/config/containers/container-networki...) says that Docker creates iptables rules for the purpose of creating this mapping.
The clear implication is that, say, "exposing" port 8080 should have similar behavior to simply running a program on the host that listens on port 8080. It does do that, but it also silently punches holes in your firewall, unless you make Docker-specific changes to your firewall config to work around it.
Even if a knowledgeable person reads the docs, and then sees something like "click here for the platform-specific details of how iptables rules are managed", I think it's entirely reasonable for them not to realize that those platform-specific details are in fact security-critical.
It doesn't? You're explicitly telling it to do so and then go on crying about how docker is awful.
The blog post was written by someone who has a compose file which changes this default behavior, which is extremely unsurprising as that is the entire purpose of compose files. If you change the default behavior, then the default behavior no longer applies and you should read the docs pertaining to how you changed the behavior.
Neither the compose quickstart [1], nor the compose specification [2] mention anything about iptables nor firewalls. The compose specification adds more details than the quickstart, but... it's obtuse, and overall a 12,000 word document! Surely that incredibly important information that has demonstrably and unexpectedly led to external access should be contained in either of these documents! Surely you can agree that their documentation should contain either the word "iptables" or "firewall"?!
[1] https://docs.docker.com/compose/gettingstarted/ [2] https://docs.docker.com/compose/compose-file/
Tl;dr - If you need to add rules which load before Docker’s rules, add them to the DOCKER-USER chain.
Seriously, there's so much room for consolidation and accessibility of their documentation. In terms of relaying information on side effects and how to identify those side effects, this is so much less approachable than pandas and sqlalchemy documentation, and that's saying something.
Just take the L and do the reading.
Doc updates aren’t free, let’s not waste effort fixing a problem that doesn’t exist when there are much better uses for that effort. Moving the words around isn’t going to effect their ability to be understood by those who refuse to actually put eyes on them.
I found this right in the docker for linux documentation.
Can I ask, how else would you expect traffic to arrive at your container when you publish a port on the internet?
Maybe he also smells bad some days. So what? Docker is still wrong, and further, more wrong than the user.
Same thing 90% of people do.
The whole point of containers like Docker is to separate the allocation and control of resources via a middle way that is not quite virtualization. So a monolithic OS running on one computer is at one end of the spectrum, and a "separate hardware device" accessible by LAN is further along the spectrum, but it's a continuum.
So I feel like Docker's control of the host OS presents a similar surprise to us today as we felt when UPnP was in control of networked devices a few decades ago.
To a Docker or UPnP expert, it's just another fact of provisioning the application's resources. UPnP has often been deployed at the hands of inexperienced users, and so it is with Docker.
That doesn't qualify as a program?
"Hey, I got a new program to install on my computer!" "What's your new program called?" "This program is... Ubuntu Linux."