> Warning: Rootless Podman relies on the unprivileged user namespace usage (CONFIG_USER_NS_UNPRIVILEGED) which has some serious security implications, see Security#Sandboxing [2] applications for details.
Accordingly, I've since set sysctl `kernel.unprivileged_userns_clone` to `0` on my system which disables rootless containers, but is now supposedly safer.
The dialog on this is a bit controversial, it seems rootless podman is pardoxically both more secure and less secure at the same time. Rootless podman doesn't have root access, but with user namespaces turned on, podman has access to kernel apis that have not been rigorously tested for non-root users. Someone explained this on Security SO a bit more in depth [3]:
> The reason for this is that much of the kernel that is only intended to be reachable by UID 0 is not audited particularly well, given that the code is typically considered to be trusted. That is, a bug that requires a UID of 0 is rarely considered a serious bug. Unfortunately, unprivileged user namespaces make it possible for unprivileged users to access this very same code and exploit security bugs.
[1] https://wiki.archlinux.org/title/Podman#Rootless_Podman [2] https://wiki.archlinux.org/title/Security#Sandboxing_applica... [3] https://security.stackexchange.com/a/209533
The concern isn't that podman itself might use that extra attack surface (because, you give podman so much more rights by making it setuid root), but that other untrusted binaries (like a virus) might use unpriviledged namespaces to exploit the kernel.
TBH, by the time you are worrying about privilege escalation from userspace threats on a typical single-user linux machine, you have already lost.
A smart threat will just modify your $PATH or bash aliases to replace su and sudo with wrappers that execute their own commands the next time you use su/sudo to do something legitimate.
BTW, if I remember correctly Podman isn’t setuid root except some very small helper binaries, almost all of the process of creating the container can be done without root privileges.
If it's a system you use interactively you have other problems. For a server yes, unprivileged containers are a very bad idea, not doubt.
Does the exposed kernel surface actually extend to the processes running in the contained environment?
Unprivileged user namespaces give an unprivileged user the opportunity to use syscalls like chroot, mount, etc. which they historically couldn't use. Container managers like Docker and Podman drop those "capabilities" after creating the container, so an application running inside a container isn't that unsafe (probably, at least everybody is doing it nowadays for production servers). I think a more problematic scenario is that someone who gets hold of an unprivileged user can then create an user namespace without dropping those capabilities and then use a local root exploit based on those syscalls you normally weren't able to use.
If you're running rootless and using namespaces to allow non-root users access to previously root-only kernel APIs, then a bunch of prior assumptions may no longer hold, and there's a new attack space available to target that has always existed, but was of no use previously to exploit.
Can't the issue be avoided by simply launching the application as a non-root user within the container namespace?
Yes, though the issue currently is that with the likes of (rootfull) docker containers, users end up setting docker to not need to call sudo every time. Meaning, if an attacker accesses your workstation (or a server), they will be able to run docker containers as root. This may as well be giving the attacker access to root as you can really easily give yourself full root access if you can launch rootfull containers. Having (rootfull) docker run access is pretty much the same as having root access.
[0] https://news.ycombinator.com/item?id=28395329 [1] https://kind.sigs.k8s.io/
There is an Arch Linux devtools project providing some shell scripts to automate setting up clean build chroots, but they're of course focused on setting up an isolated Arch system, and still require running as root. The true poor man's way to do this without being root is to use fakeroot and fakechroot, which is what the Debian builds do. The examples from Debian would all run debootstrap to set up a minimal Debian in the chroot, but you can just run "fakeroot fakechroot <any command>" to use your own build tools and bootstrap your own build environment. That way you don't even require a container runtime and don't need to open up the attack surface of user namespaces.
EDIT: Looks like they don't provide either an Ubuntu/Debian executable or an Ubuntu root image, which is a bit unfortunate. Odd that someone would make a project and ignore the most common Linux distro...
It's not surprising given it's a Redhat project, but it does put me off using it as I'm most comfortable with debian derived environments.
I've used buildah to set up a C/C++ dev environment in a Ubuntu toolbox at work without any major issues.
(Eventually people will come around to the Nix model. Especially because it's, essentially, like what happens when you install apps on phones.)
I have an application in a Kubernetes-managed container which needs to do exactly this to access the host system (to open LUKS containers and mount their contents), so I have it run in privileged mode (i.e. with access to all syscalls) and give it the full host filesystem as a bind mount, so it can do:
nsenter -m /host/proc/1/ns/mnt mount $DEV $PATH
(The actual nsenter invocation is slightly more complicated, but that's the basic gist.)Side-note: Since there will inevitably be a comment along the lines of "but then what do you even need isolation for", I'm very explicitly using Kubernetes as a deployment mechanism only. Other pods within the same Kubernetes are strictly isolated, but this one deliberately runs with practically no isolation. But I still get the consistent environment that Kubernetes provides (rolling upgrades, log shipping, liveness probes, etc.).
This allows you to easily deploy generic ones you download from the community, and since they usually ship the script that was used to build it, it's easy to extend them with your own changes by creating your own script that uses a generic public one (the base, not the script) as a starting point, allowing everyone to share work. (e.g. get an nginx container and do the small bits to customize it for you in a script, and you don't need to worry about the building or system setup of container)
In addition to the normal chroot stuff, it uses cgroups functionality on linux to constrain it even more such as limiting CPU and RAM or disk IO, and can lock down a bunch of functionality from even root inside, and you also usually have to specifically allow whatever internal ports are listening externally (and not necessarily on the same port).
So containers are what you get when you take the idea of a chroot and try to extend and build upon it towards the direction of a true virtual machine, but without going to the step of fully emulating hardware. The benefit is that they are super lightweight and can more easily share CPU and RAM. The downside is that you're exposing more of your base system kernel to it, so it's likely somewhat less secure than a true hypervisor (but very likely more secure than just running those processes on the base system).
So, now that we have a shared base of what a container is (sort of, I'm not sure enough on the specifics to assume I didn't make some missteps in that description), rootless containers extend that so that a regular system user can run a container which internally runs as root, but not the real parent system root, but it works for the container because the kernel uses namespaces to allow it. This is both cool because it allows for root to be used even less on a system and scary because as another comment in this thread noted, it exposes some kernel APIs to "root" users (run and controlled by system users) which might not normally be checked as much for security problems since you have to be root already to use them.
https://jvns.ca/blog/2020/04/27/new-zine-how-containers-work...
- the process’s view of other processes (i.e. ps isn’t isolated)
- the process’s view of the kernel’s VFS, (i.e. mount isn’t isolated)
- the process’s view of the networking stack (i.e. ifconfig and iptables aren’t isolated, and socket numbers are global)
- the process’s view of users on the system (i.e. uids/gids are global)
And so with time, the hostname, IPC, cgroups…
And more are planned on being added like the kernel keyring, and /dev/log.
“containers” means a lot of different things to different people but the main things people want are.
- resource bundling: “take everything your app needs to run, and tar it up so that it all stays together. Don’t make me worry too much about missing libraries.
- sandboxing: don’t make me have to worry too much about what else is going on the system when I run my thing and reduce the surface area for attacks.
- delivery (the big value add): give me a bunch of tooling to create that tar, version it, and get it running on a bunch of different systems without have to worry too much about the underlying OS, hardware, network setup, or storage.
And bonus for things like k8s.
- service bundling: give me a bunch of tooling to get many of those tars running on different systems and don’t make me worry too much about service discovery, load balancing, software crash recovery, hardware crash recovery, deployments, task scheduling, secrets, config files and more.
https://fly.io/blog/sandboxing-and-workload-isolation/
https://devops.stackexchange.com/questions/2826/difference-b...
For further reading, searching for ⟬docker vs chroot⟭ yields a bunch of interesting articles.
A "container" (whether Docker or LXC or Podman) is a bundle of isolations that includes the filesystem as well as processes and users, and constraints on memory, CPU, networking, and kernel calls.
The differences between Docker, LXC, Podman, etc. are the config, management, etc. of containers; e.g. Docker abstracts over the chroot directories, using a set of content-addressed tarballs (called "images"), and provides commands for starting/stopping/listing/etc. the containers that are running.
You may be right that LXC has switched over to runc since then. I haven't kept up. I would be surprised though.
One very interesting piece of tech coming from podman, is toolbox (https://github.com/containers/toolbox). Basically throwaway (or keeparound) rootless containers with their own root directory but shared HOME. Install hundreds of dev-dependencies to build this one piece of software? Yeah, not gonna install those packages permanently. Spin up a toolbox, build it, install it in my home/.local.
You have root in the container without having root in the host system. That takes care of a lot of issues as well.
I basically no longer have development packages installed and run some applications with lots of dependencies out of toolboxes.