If there is a single best practice for container security, it is to avoid running containers as root. Rootless containers are making this much easier – almost effortless, even. In this blog, I’ll talk about why you should be avoiding root in containers, what rootless containers are, and how they are going to help.
Regular Containers Run as Root by Default
When you run a container today, the chances are that it’s running as root (unless you’ve done something to change the user ID). There are some exceptions – if you’re using podman or OpenShift, they don’t run containers as root by default. But in most cases today, when developers are using Docker images or deploying containers with Kubernetes, they are by default running as root. This leads to a myriad of containers having way more privileges than are required – increasing the attack surface and making privilege escalation more feasible.
Why You Shouldn’t Run Your Containers as Root
So, why is this dangerous? The thing is the root identity inside the container is exactly the same as it is on the host (virtual) machine. When an attacker manages to compromise a container that’s running as root, they are just one step away from taking over the host. That “one step” could be a container escape vulnerability – not a common event but they do happen from time to time. Often when a new container escape vulnerability is found they need privileges to be exploited, so a simple mitigation is to make sure your containers aren’t running as root.
Much more likely, a process can effectively escape from a container through misconfiguration – for example, access to files that have been mounted into the container. Unless you have policy enforcement of some kind in place (and Aqua’s solution can help with this policy enforcement), there is nothing to stop anyone mounting the host’s root directory into any container. From there, if the container is running as root, file and directory permissions will do nothing to protect the host from access or tampering by the container. Once the attackers are root on the host, they have access to everything. If you want to keep your applications safe, you want to make it a lot harder than that for an attacker to gain host root access.
What Are Rootless Containers and How They Can Help
Rootless containers, a relatively new and widely discussed concept, offer a more secure approach to running containers. By community definition on rootlesscontaine.rs, “rootless containers refer to the ability for an unprivileged user to create, run and otherwise manage containers”, i.e., being able to run containers without having to be root. The rootless approach is that although from the containers’ perspective you appear to be a root user, it’s not actually the root privileges on the host. Let’s look into how it works and what’s going on behind the scenes.
As we know, containers use Linux namespaces to isolate themselves from the host they run on. The extra thing that’s used to make containers rootless is the User namespace. This maps user (and group) IDs so that a process can appear from inside the namespace to be running under a different ID – including the root identity 0. Inside the namespace it can also have broader capabilities than it would have outside the namespace.
From inside a rootless container (or more precisely, inside its user namespace) application code can appear to be running as root, and it can perform privileged operations that it would not be permitted to perform outside that namespace. But from the host’s perspective, it’s a regular user, and if an attacker manages to escape the user namespace onto the host, it will have that regular non-root user ID, and none of the extra capabilities that it might have had inside the namespace.
The other important aspect of user namespaces is that you don’t need to be a privileged user to create one. With rootless containers, users can be authorized to run containers without giving them the equivalent of root privileges on the host. This is a huge advantage in environments like academia where it’s common for many users to share access to a common machine. Without rootless support, giving people permission to run containers on a machine is effectively the same as giving them root access.
In summary, rootless containers are good from a security perspective for two reasons:
- You don’t need to be a privileged user to create a rootless container
- Code can run inside a rootless container with root privileges, without having to run as the host’s root user.
For a closer look at how the user namespace works, check out this video where I use the Linux unshare command to demonstrate how rootless containers are created.
Rootless Containers Today
Though rootless containers are still quite new, they are gaining traction and support from the major vendors in the industry. Some tools, like Red Hat’s podman and Singularity containers have supported rootless containers for a while – Singularity call it “fakeroot” (which is arguably a more descriptive name). The latest update 20.10 of Docker moved support for rootless out of “experimental”, allowing unprivileged users to install and run the Docker daemon as well as individual rootless containers.
What about Kubernetes? There is work in progress, and Akihiro Suda has shown a proof-of-concept in a project called Usernetes.
Until rootless support is ready in Kubernetes, what can you do? The bottom line is that you want to avoid running containers as root, and there are tools to help you. Admission control webhooks can provide checks to stop the deployment of containers that run as root. (PodSecurityPolicy can do this too, although it may not be long for this world, so I wouldn’t advise taking your first steps with it now.) There are configuration checking tools that run over YAML looking for best practices, including whether workloads are defined not to run as root – we have included one of these tools, Polaris, in our open source project Starboard for surfacing security issues through the Kubernetes API. Also, Aqua’s container security solution includes flexible policy checks that can alert you of (or even prevent) containers running under the root identity.
Conclusion
In a perfect world, containers should run without root privileges by default. This is not trivial but when achieved, it significantly reduces the attack surface and avoids a lot of potential security issues, such as privilege escalation out of the container. Due to their security benefits, rootless containers are a big step forward in making this easier and improving your overall security posture. If the container, or the container runtime, is compromised, the attacker won’t automatically gain root privileges on the host.