I'd still rather use docker. I don't mind that the daemon runs as root because there are some things that you need root for anyways! Like binding to privileged ports or setting up networks (use `internal: true` and the daemon will automatically set up iptables rules that limit traffic).
I deploy docker compose files with ansible so everything comes with built in security defaults like rootless, dropped caps, no new privileges, etc. I wish more containers supported running read only (its usually pretty easy to add, just overlooked) and distroless (common for go apps, less so otherwise).
There was a pretty good comment on reddit a while back with a list of hardenings for compose files [1]
Rootless is definitely the way to go. You can forward ports manually on the host if you really need to use privileged ports. I generally expose my containers through a reverse proxy, running bare metal on the host, and that completely bypasses the privileged port issue.
That privileged port thing is not true anymore for Docker created containers, since it lowers that limit and unprivileged containers can listen on any port.
docker run -ti --rm --user 1000:1000 --privileged=false alpine:latest
~ $ cat /proc/sys/net/ipv4/ip_unprivileged_port_start
0
~ $ id
uid=1000 gid=1000 groups=1000
~ $ nc -lvp 80
listening on [::]:80 ...
Also the iptable rules Docker creates is for routing traffic to container with destination NAT, to actually limit traffic you have to do it yourself by inserting rules in DOCKER_USER chain.
copy the single busybox statically linked binary into a container, and you can create a bunch of symlinks for its tools that you want to use (this is how busybox container itself works)
makes it trivial to do the dhi/rootless thing but do ad-hoc debugging and then remove the debugging tools entirely, leaving no trace/bloat behind (just one file)
This whole privileged port thing is an outdated convention from the time when Linux ran on mainframes. Depending on your use case, it can be perfectly fine to lower it. I have set to `net.ipvX.ip_unprivileged_port_start = 80` on my server so that I can run rootless containers without extra privileges and have them bind to ports 80 and up.
Nits: It's a Unix convention (not just Linux), and Unix traditionally ran on minicomputers (not mainframes). Mainframes had their own specialized OSes, although some could run Unix in a partition or virtual machine.
I've read that privileged ports was created as a trust model, so users connecting to a service using a privileged port would know that service was started by root on that server and therefore could be trusted. I always felt this was a bit wierd though, maybe I was missinformed, or maybe priviliged ports was already a thing and was just leveraged this way?
I deploy docker compose files with ansible so everything comes with built in security defaults like rootless, dropped caps, no new privileges, etc. I wish more containers supported running read only (its usually pretty easy to add, just overlooked) and distroless (common for go apps, less so otherwise).
There was a pretty good comment on reddit a while back with a list of hardenings for compose files [1]
1. https://www.reddit.com/r/selfhosted/comments/1pr74r4/comment...