In my previous post on volumes with podman, I touched on SELinux but I think it’s worthy of its own post to work through some details.
If your host has SELinux enabled, then container processes are confined to the
system_u:system_r:container_t:s0 domain. Volumes you pass to
podman will need to have appropriate labels, otherwise the container won’t be able access the volume, no-matter what the filesystem permissions are.
When running rootless containers (as your non-root user), files in your homedir will probably have the context of
unconfined_u:object_r:data_home_t:s0, however the context that is required for container volumes is
Fortunately, container volumes which podman creates at runtime will have the appropriate context set automatically. However, for host-dir volumes podman will not change the context by default, you will need to tell it to.
Let’s spin up a busybox container without setting the SELinux context and note that the container is not able to access the host-dir volume.
$ mkdir src $ ls -dZ src/ unconfined_u:object_r:user_home_t:s0 src/ $ podman run -dit --name busybox -v ./src:/dest busybox 395924189c95d05dae65d5616fbdd7054095b1c3318603642e03047af9c893c7 $ podman exec -it busybox touch /dest/file touch: /dest/file: Permission denied
OK, let’s delete that container and spin it up again but with the
:z SELinux volume option.
$ podman rm -f busybox 395924189c95d05dae65d5616fbdd7054095b1c3318603642e03047af9c893c7 $ podman run -dit --volume ~/src:/dest:z --name busybox busybox e5176a7acee86e17b42d417e7d2c570b2ecc51cccf6fd938688998d176e60df1 $ podman exec -it busybox touch /dest/file
OK, it didn’t error, that’s good! Let’s have a look on the host.
$ ls -Z ./src/file system_u:object_r:container_file_t:s0 ./src/file
Great! We were able to write the file and we can see on the host that it exists with the correct SELinux context.
:z option is critical as it tells podman to at least set the context to
Note however, that with this context, SELinux will not stop any other container from being able to access that same directory. Yes, that can introduce a security risk if applied incorrectly (or perhaps through a vulnerability), but it’s also how you would share the same volume between multiple containers.
So what if you wanted to restrict a volume to a specific container only? Well, that’s what the the UPPERCASE
:Z option is all about. It not only tells podman to set the context on the volume, like lowercase
:z, but it also ensures that other containers are not able to access it.
How does it do this? Each container process also has unique MCS (Multi-Category Security) categories. This is what podman uses for the private label, setting the SELinux context on the volume to match those of the process. For example, if the process runs in the confined domain with unique MCS categories
c123,c456 then the volume context will be set to match, e.g.
Let’s try a real world example with busybox running the
top command (note the UPPERCASE
$ mkdir -p src $ podman run -d --name busybox-top -v ./src:/dest:Z busybox top eceb13fee0e79cd328fde948e4dd9f1b39cddfc04f147e5eebcbfd2ee2d6abae
Looking for the container’s
top process running on the host we can see that its MCS label is
$ ps -eZ | grep container_t |grep top system_u:system_r:container_t:s0:c260,c602 26474 pts/0 00:00:00 top
Now let’s look at the host directory for the volume and note that it has a matching MCS label of
$ ls -Zd ./src system_u:object_r:container_file_t:s0:c260,c602 src
Note that if you attach that same host-dir volume to multiple containers, only the last container with that volume attached will be able to access it as the context is updated each time.
Proving protection with private labels
Let’s spin up a second busybox container running
iostat command this time, using the same host dir volume.
$ podman run -d --name busybox-iostat -v ./src:/dest:Z busybox iostat 1 1ad1ee6413f0b222468a2f540c4316a6a504c25245435fb51ee125f465514576
Let’s grab the MCS label for the
iostat process, which we can see is
$ ps -eZ | grep container_t |grep iostat system_u:system_r:container_t:s0:c327,c995 26876 pts/0 00:00:00 iostat
Now we can see that the label for the host dir has changed to match this new container (it used to be
$ ls -Zd ./src system_u:object_r:container_file_t:s0:c327,c995 src
Finally, if we try to touch a file inside each of the containers, we’ll see the original busybox container now fails.
$ podman exec busybox-top touch /dest/file touch: /dest/file: Permission denied
However, the second container running
iostat works, and the file has a matching label.
$ podman exec busybox-iostat touch /dest/file $ ls -Z src/file system_u:object_r:container_file_t:s0:c327,c995 src/file
This shows how uppercase :Z is the more secure of the two SELinux volume options.