Are you deploying software using containers? Are you using Podman? Do you want to up your security game by running containers with as little privilege as possible? Boy, do I have an article for you!
What is Podman?
Podman is a Red Hat product aimed as a replacement for Docker. For 99% of tasks, it is indeed a true Docker replacement. A few of its features are support for root-less containers, uses the fork/exec model to start containers, is daemon-less, and more.
The advantages of a rootless container are obvious. If it can be prevented from running as root, you run it without root privileges.
With this article, I hope to help remove some hurdles that may crop up when you use Podman to deploy rootless containers.
Podman in rootless execution
If you are a seasoned IT professional, you might have committed either one of the following crimes:
- Running the
sudo, escalating its privileges
- Adding your user non-root user to the
dockergroup. big oof
As you might have realized by now, this is a terrible security practice. You are giving the Docker daemon root access to your machine. That exposes two methods of exploitation:
- The Docker daemon (
dockerd) runs as root. If
dockerdhas a security vulnerability, your entire system is compromised because
dockerdis a process owned by the
- An image that you use might have vulnerabilities. What if the vulnerable imgae is used by a container that is running as a process of the
rootuser? An attacker can use the vulnerable image to gain access to your entire system.
The solution is simple, don't run everything as root, even if you trust it. Remember, nothing is 100% secure. I present to you Podman's ability to manage containers without root access.
If you start a container using Podman as a non-root user, said container does not gain any additional privileges, nor will Podman ask you for a
Below are the benefits Podman provides when you use it for root-less containers (without any super-user privileges):
- You can isolate a group of common containers per local user. (e.g., run Nextcloud and MariaDB under user
nextcloud_userand containers Gitea and PostgreSQL under the user
- Even if a container/Podman gets compromised, it can not get complete control over the host system, since the user executing the container is not
root. But yes, the user under which the exploited container is running might as well be considered as user gone rogue.
Limits of root-less Podman
When you use root-full Podman/Docker, you are giving Podman/Docker super-user level privileges. That is certainly very bad, but it also means that all of the advertised functionalities work as intended.
Instead, when you run Podman containers without root privileges, it has some limits. Some of the major ones are as follows:
- Container images can not be shared across users. If
user0pulls the '
user1will have to separately pull the '
nginx:stable-alpine' image for themselves. There is no way [at least not yet] that allows you to share images between users. But, you can copy images from one user to another user, refer to this guide by Red Hat.
- Ports less than 1024 cannot be binded out of the box. A workaround exists.
- A root-less container may not be able to ping any hosts. A workaround exists.
- If you specify a UID in root-less Podman container, any UID that is not mapped to a pre-existing container may fail. Best to execute Podman from an existing user shell. Or better yet, create a systemd service to auto-start it.
Getting started with root-less Podman
Before you get started with the rootless execution of containers, there are a few prerequisites that need to be met.
Make sure you have
slirp4netns package is used to provide user-mode networking for unprivileged network namespaces. This is a necessary if you want your root-less container to interact with any kind of network.
You can install the
slirp4netns package on Debian/Ubuntu based Linux distributions using the
apt package manager like so:
sudo apt install slirp4netns
On Fedora/RHEL based Linux distributions, use the
dnf package manager to install
slirp4netns like so:
sudo dnf install slirp4netns
You Arch Linux users know how to do it with
pacman, but regardless, below is the command you might be looking for:
sudo pacman -Sy slirp4netns
Make sure that your
subgid are properly configured
Since root-less Podman containers are run by an existing user on the system, said non-root users need permission to run a root-less container as a UID that is not their own UID. This also applies to the GID.
Each user is given a range of UIDs that it is allowed to use. This is specified in the
/etc/subuid file; and the
/etc/subgid file is for the GIDs a user is allowed to use.
The format of this file is as following:
username:initial UID/GID allocated to user:range/size of allowd UIDs/GIDs
So, let us say my user,
pratham wants 100 UIDs for himself and
krishna wants 1000 UIDs for himself. Below is how the
/etc/subuid file would look like:
What this effectively means is that the user
pratham can use UIDs between '100000' and '100100'. Meanwhile, user
krishna can use UIDs between '100100' and '101100'.
Usually, this is already set up for each user you create. And usually, this range is set to '65536' usable GIDs/UIDs. But in some cases, this needs to be done manually.
But hold on, if this is not already done for your user, you do not need to do this by hand for each user. You can use the usermod command for this. Below is the command syntax to do so:
sudo usermod --add-subuids START-RANGE --add-subgids START-RANGE USERNAME
Replace the strings
USERNAME according to your needs.
/etc/subgidare set to
644and is owned by
Want to bind Ports less than 1024?
If you are using a reverse proxy for SSL, you will know that ports 80 and 443 need to be accessible by a certificate provider like Let's Encrypt.
If you try to bind ports lower than 1024 to a root-less container managed by Podman, you will notice that it is not possible. Well, it is possible, but that is not configured out of the box.
A non-root user is not allowed to bind anything on ports less than port 1024.
So, how do I bind ports lower than 1024 in root-less Podman? To do that, first determine the lowest port that you need. In my case, to deploy SSL, I need ports 80 and 443. So the lowest port that I need is port 80.
Once that is determined, add the following line to the
Essentially, you are changing the value of
net.ipv4.ip_unprivileged_port_start to the lowest port you need. If I substitute
YOUR_PORT_NUMBER with 80, I can bind port 80 with Podman in a root-less container.
WHERE ARE MY IMAGES?
No need to scream at me buddy. I was going to tell you, eventually...
As I pointed out earlier, a limitation of Podman is that it can not share images between users. They either need to be pulled for each user or be copied from one user to another user. Both of these take up 2x/3x/4x space (depending on how many duplicates exist).
The image for any user is stored in their home directory. Specifically, they are stored inside the
Give it a try!
Once all the prerequisites are satisfied, you can run the
podman run command from a non-user's shell and start a container.
Since I use Caddy Server for my SSL, I will use that in this tutorial. To run Caddy Server as a root-less container using Podman, while binding it ports lower than 1024, I will simply run the following command:
$ whoami pratham $ podman run -d --name=prathams-caddy -p 80:80 -p 443:443 caddy:alpine e6ed67eb90e6d0f3475d78b287af941bc873f6d62db60d5c13b1106af80dc5ff $ podman ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES e6ed67eb90e6 docker.io/library/caddy:alpine caddy run --confi... 2 seconds ago Up 2 seconds ago 0.0.0.0:80->80/tcp, 0.0.0.0:443->443/tcp prathams-caddy $ ps aux | grep caddy pratham 3022 0.0 0.0 85672 2140 ? Ssl 06:53 0:00 /usr/bin/conmon --api-version 1 -c e6ed67eb90e6d0f3475d78b287af941bc873f6d62db60d5c13b1106af80dc5ff [...] pratham 3025 0.1 0.3 753060 32320 ? Ssl 06:53 0:00 caddy run --config /etc/caddy/Caddyfile --adapter caddyfile
As you can see, the user
pratham is not
root and also that I did not use the
sudo command to escalate privileges of the user
pratham. I was able to run the Caddy Server container with root-less privileges using Podman.
The output of
ps command shows that the PID
3022 is of a process owned by the
pratham user. This process is the Caddy Server container (I have trimmed the output). The PID
3025 is a child process of PID
3022 which is also under the
Did I not address your issue?
I apologize if I did not cover your issue with root-less Podman containers. Since Podman is new (in software years), it will have some unexpected issues.
Fret not. I have included the official troubleshooting guide below. Refer to that when in doubt. It is also the one that will be updated frequently.
In this article, I demonstrate how you can start managing rootless containers using Podman. I talk about the necessary software that enables this functionality. I go over common issues you may face with root-less Podman containers and how to mitigate them.
I hope it helps you and if you need more details, check the official documentation where you might get a more technical troubleshooting guide.