You might be saying to yourself, “but I have rootless containers right now with Docker - I run my docker commands as a regular user and it works all the time.” Even though you are executing the docker command line tool without root, the docker daemon is executing those requests as root on your behalf […]

A preview of running containers without root in RHEL 7.6

Docker the root of all evil?

In fact it's exactly what is mentioned in the quote. The docker daemon itself runs as root.

# The docker 
$ ps -eaf | grep "[d]ocker"

# root       817     1  0 06:28 ?        00:00:00 /usr/bin/dockerd -H fd:// --containerd=/run/containerd/containerd.sock

One of the consequence is that any user has to belong to the docker group to be able to use launch a container. Let's try to run a simple example that is running a container with a standard user on the host (ubuntu) and the root user in the container.

# Sleep forever
$ docker run -d --rm --name busy busybox sleep infinity

$ docker ps

# CONTAINER ID        IMAGE               COMMAND             CREATED              STATUS              PORTS               NAMES
# 3070e49e27bf        busybox             "sleep infinity"    About a minute ago   Up About a minute                       busy

# The process on the host is run by root
$ ps -eaf | grep "[s]leep"

# root      1984  1956  0 06:33 ?        00:00:00 sleep infinity

It confirms that the process on the host is run by the root user. So if there is any issue a root access can be obtained on the host, it's a big risk.

Another consequence is that any pulled image—and also any container—will reside in /var/lib/docker that is owned by root and shared among all users.

$ ls -alsh /var/lib/docker

# ls: cannot open directory '/var/lib/docker': Permission denied

$ sudo ls -alsh /var/lib/docker

# total 60K
# 4.0K drwx--x--x 14 root root 4.0K Feb  9 06:28 .
# 4.0K drwxr-xr-x 40 root root 4.0K Feb  8 15:16 ..
# 4.0K drwx------  2 root root 4.0K Feb  8 15:09 builder
# 4.0K drwx------  4 root root 4.0K Feb  8 15:09 buildkit
# 4.0K drwx------  6 root root 4.0K Feb  9 06:41 containers
# 4.0K drwx------  3 root root 4.0K Feb  8 15:09 image
# 4.0K drwxr-x---  3 root root 4.0K Feb  8 15:09 network
# 4.0K -rwxr-xr-x  1 root root 1.5K Feb  8 15:12 nuke-graph-directory.sh
# 4.0K drwx------ 12 root root 4.0K Feb  9 06:41 overlay2
# [...]

Podman to the rescue!

What is Podman? Podman is a daemonless container engine for developing, managing, and running OCI Containers on your Linux System. Containers can either be run as root or in rootless mode. Simply put: alias docker=podman. More details here. — https://podman.io

There is several interesting things there:

Let's try to do the same thing with podman.

$ podman run -d --rm --name busy busybox sleep infinity

$ podman ps

# CONTAINER ID  IMAGE                             COMMAND         CREATED         STATUS             PORTS  NAMES
# fe7254c0c247  docker.io/library/busybox:latest  sleep infinity  25 seconds ago  Up 24 seconds ago         busy

# The process on the host is run by ubuntu (the unpriviledged user)
$ ps -eaf | grep "[s]leep"

# ubuntu   16626 16614  0 07:12 ?        00:00:00 sleep infinity

It's also possible to check through this command what are the user / group used on the host (huser / hgroup) and in the container (user / group).

$ podman top -l user group huser hgroup

# USER   GROUP   HUSER   HGROUP
# root   root    1000    1000

# ID 10000 correspond to the ubuntu user
$ id ubuntu

# uid=1000(ubuntu) gid=1000(ubuntu) groups=1000(ubuntu),4(adm),20(dialout),24(cdrom),25(floppy),27(sudo),29(audio),30(dip),44(video),46(plugdev),108(lxd),114(netdev),115(docker)

# We can see the difference between docker and podman if we run both at the same time
$ ps -eaf | grep "[s]leep"

# ubuntu    4299  4288  0 15:04 ?        00:00:00 sleep infinity
# root     10694 10669  0 15:18 ?        00:00:00 sleep infinity

So far so good and it goes the same with the images—and the other stuffs—that are stored by user and not shared with everyone and owned by root.

# Checking where the podman store is located
$ podman info | tail

#  ContainerStore:
#    number: 3
#  GraphDriverName: vfs
#  GraphOptions: {}
#  GraphRoot: /home/ubuntu/.local/share/containers/storage
#  GraphStatus: {}
#  ImageStore:
#    number: 1
#  RunRoot: /run/user/1000/containers
#  VolumePath: /home/ubuntu/.local/share/containers/storage/volumes

$ ls -alsh /home/ubuntu/.local/share/containers/storage

# total 40K
# 4.0K drwx------ 9 ubuntu ubuntu 4.0K Feb  8 14:47 .
# 4.0K drwx------ 4 ubuntu ubuntu 4.0K Feb  8 14:48 ..
# 4.0K drwx------ 2 ubuntu ubuntu 4.0K Feb  8 14:47 libpod
# 4.0K drwx------ 2 ubuntu ubuntu 4.0K Feb  8 14:47 mounts
# 4.0K -rw------- 1 ubuntu ubuntu   64 Feb  9 07:12 storage.lock
# 4.0K drwx------ 2 ubuntu ubuntu 4.0K Feb  8 14:47 tmp
# 4.0K drwx------ 3 ubuntu ubuntu 4.0K Feb  8 14:48 vfs
# 4.0K drwx------ 5 ubuntu ubuntu 4.0K Feb  9 07:12 vfs-containers
# 4.0K drwx------ 3 ubuntu ubuntu 4.0K Feb  8 14:48 vfs-images
# 4.0K drwx------ 2 ubuntu ubuntu 4.0K Feb  9 07:12 vfs-layers

PS: The grep trick grep "[s]leep" comes from this question/answer.