Skip to main content
Redhat Developers  Logo
  • Products

    Platforms

    • Red Hat Enterprise Linux
      Red Hat Enterprise Linux Icon
    • Red Hat AI
      Red Hat AI
    • Red Hat OpenShift
      Openshift icon
    • Red Hat Ansible Automation Platform
      Ansible icon
    • View All Red Hat Products

    Featured

    • Red Hat build of OpenJDK
    • Red Hat Developer Hub
    • Red Hat JBoss Enterprise Application Platform
    • Red Hat OpenShift Dev Spaces
    • Red Hat OpenShift Local
    • Red Hat Developer Sandbox

      Try Red Hat products and technologies without setup or configuration fees for 30 days with this shared Openshift and Kubernetes cluster.
    • Try at no cost
  • Technologies

    Featured

    • AI/ML
      AI/ML Icon
    • Linux
      Linux Icon
    • Kubernetes
      Cloud icon
    • Automation
      Automation Icon showing arrows moving in a circle around a gear
    • View All Technologies
    • Programming Languages & Frameworks

      • Java
      • Python
      • JavaScript
    • System Design & Architecture

      • Red Hat architecture and design patterns
      • Microservices
      • Event-Driven Architecture
      • Databases
    • Developer Productivity

      • Developer productivity
      • Developer Tools
      • GitOps
    • Automated Data Processing

      • AI/ML
      • Data Science
      • Apache Kafka on Kubernetes
    • Platform Engineering

      • DevOps
      • DevSecOps
      • Ansible automation for applications and services
    • Secure Development & Architectures

      • Security
      • Secure coding
  • Learn

    Featured

    • Kubernetes & Cloud Native
      Openshift icon
    • Linux
      Rhel icon
    • Automation
      Ansible cloud icon
    • AI/ML
      AI/ML Icon
    • View All Learning Resources

    E-Books

    • GitOps Cookbook
    • Podman in Action
    • Kubernetes Operators
    • The Path to GitOps
    • View All E-books

    Cheat Sheets

    • Linux Commands
    • Bash Commands
    • Git
    • systemd Commands
    • View All Cheat Sheets

    Documentation

    • Product Documentation
    • API Catalog
    • Legacy Documentation
  • Developer Sandbox

    Developer Sandbox

    • Access Red Hat’s products and technologies without setup or configuration, and start developing quicker than ever before with our new, no-cost sandbox environments.
    • Explore Developer Sandbox

    Featured Developer Sandbox activities

    • Get started with your Developer Sandbox
    • OpenShift virtualization and application modernization using the Developer Sandbox
    • Explore all Developer Sandbox activities

    Ready to start developing apps?

    • Try at no cost
  • Blog
  • Events
  • Videos

My advice on SELinux container labeling

April 11, 2025
Daniel Walsh
Related topics:
ContainersLinuxSecurity
Related products:
Podman Desktop

Share:

    After receiving an email where someone was moving from Docker to Podman and hit some SELinux issues, I decided to write an article about it.

    Leveraging SELinux for container security

    First, sadly, while Docker has SELinux support, it is disabled by default. I believe this is a big mistake, since SELinux is the best tool to protect the file system from container breakout. SELinux has blocked most of the container breakout scenarios over the past decade-plus.

    SELinux has had a reputation for being difficult to manage, mainly because it attempts to control communication paths between applications running on a host. These applications can be configured multiple different ways, causing SELinux to block communication paths. These varied configurations require thorough SELinux knowledge to set booleans or fix file system labels to allow the applications to communicate in a safe and secure manner. 

    Containers fix this by simplifying the way applications work. When an application is run inside of a container, SELinux can just control the exterior of the container. The application can do whatever it wants within the container, but if it needs to communicate outside of the container, it does it through the network.

    SELinux controls the outside of the container through process labeling and file system labels. A database, web service, AI model server, mail server... All look the same to SELinux when these applications are running in a container.

    I often say SELinux and containers are a marriage made in heaven. For a better understanding of how SELinux works, check out my SELinux coloring book.

    Cover of the SELinux Coloring Book.
    The SELinux Coloring Book.

    Most users of container technology do not even know that SELinux is controlling the processes. But the main exception to this is when users poke holes in the container and leak information from the host into the container.

    The primary way the people leak information into containers is through volume mounts. 

    The rest of this article will discuss how container engines Podman and Docker (although most of these can also be handled in the Kubernetes world) can allow access to these volume mounts.

    Let’s look at 7 different ways you can adjust the container engines to allow them to run and the ramification of these settings.

    When analyzing security features of containers, there are multiple different security tools involved. The following analysis assumes that all other security mechanisms have failed and only SELinux stands between you and an exploited system.

    1. Run container normally

    On Podman, this is the default and requires no modifications. With Docker, the Docker daemon needs to be configured with the --selinux-enabled option.

    Security ramifications

    This is the most secure way a container is run. An escaped container process has no access to any host files at all other than container content within the container from an SELinux point of view.

    Recommendation

    I strongly recommend that all containers run with SELinux separation enabled and enforcing.

    2. Run container with a private volume 

    Use the volume or mount :Z option. This option tells the container engine to relabel the content under the volume for the exclusive use of the container. Depending on the size of the volume, this can take some time, since the relabel needs to modify every file in the volume. This will only happen the initial time the container uses the volume. 

    Example: the file label unconfined_u:object_r:container_file_t:s0:c124,c967 for containers running with the s0:c124,c967 MCS label.

    Note

    If you have a volume which contains millions of files, relabeling might be too cumbersome. If the source Volume for this content is a file system, one option you could investigate for the volume would be to use a context mount for the entire file system. Search for a description of context mounts under the mount man page. 

    -v /SOURCE:/DEST:Z
    --mount type bind,source=/SOURCE,dest=/DEST,Z
    $ podman run -ti -v ./db:/var/lib/mariadb:Z quay.io/rhatdan/mariadb

    Security ramification

    The container has full read/write access over the volume, but other containers are blocked from using it, even if they escaped confinement. If the container process escapes, it only has access to this volume and its other content.

    Recommendation

    If it is not necessary to share the volume with other containers, use the :Z option.

    Note

    Do not relabel default system files and directories, like /home, /etc, /var/log, etc. Relabeling system content might cause other non-containerized confined services on the machine to fail. For these types of containers, look at recommendations 6 or 7.

    3. Run two or more containers sharing the same volume

    Use the volume or mount :Z option. This option tells the container engine to relabel the content under the volume with the container shared SELinux label. Depending on the size of the volume, this can take some time because the relabel needs to modify every file in the volume. This will only happen the initial time the container uses the volume. The second container to use this volume will not relabel.

    Example: the file label unconfined_u:object_r:container_file_t:s0 for all containers. Note that the MCS label for this container volume is s0. This means the file has no categories, so any container can read/write the content from an SELinux point of view.

    -v /SOURCE:/DEST:z
    --mount type bind,source=/SOURCE,dest=/DEST,z
    $ podman run -d -v ./shared:/shared:z quay.io/rhatdan/app1
    $ podman run -ti -v ./shared:/shared:z quay.io/rhatdan/app2

    Security ramification

    Both containers have full read/write access over the volume, but other containers are NOT blocked from using it, if they escaped confinement. If a third container’s processes escape they have access to this volume.

    Recommendation

    When it is necessary to share the volume with other containers, use the :z option or look at option 5. Use the volume or mount :z option. 

    4. Run two or more containers sharing the same volume (option 2)

    Another option is to run each container with the same SELinux label. The container engines allow users to select which MCS label to run with. In this case, use the :Z option.

    --security-opt label=level:s0:c100,c259
    $ podman run -d --security-opt label=level:s0:c1,c2 -v ./shared:/shared:Z quay.io/rhatdan/app1
    $ podman run -ti --security-opt label=level:s0:c1,c2 -v ./shared:/shared:Z quay.io/rhatdan/app2
    $ podman run --security-opt label=level:s0:c1,c2 fedora cat /proc/self/attr/current; echo
    system_u:system_r:container_t:s0:c1,c2

    Security ramification

    These containers can read/write the volume, but if a process in the second container escapes, it is able to attack the processes in the first container and potentially able to ptrace them and see their memory.

    Processes that escape from other other containers running on the system are not able to read/write the content on the system.

    Recommendation

    I prefer to use the :z option because of its simplicity, but if the content of the volume is really sensitive, this mechanism might be preferable. Containers running within the same pod share the same SELinux label, so sharing volumes between containers in a pod is simpler.

    5. Run a container with a host volume that can not be relabeled

    Sometimes it is necessary to run a container with a host directory that is not only used by the container but also by host processes—for example, if a container needs to examine all of the logs in /var/log or scan users' content in their home directory for files. 

    In this case, most users can use option 2 and turn off SELinux separation. But those who want more security can write a new SELinux type to allow access to the content.

    --security-opt label=type:container_logreader_t
    $ podman run -d --security-opt label=type:container_logreader_t -v /var/log:/logs docker.io/rhatdan/loganalyze

    Security ramification

    In the preceding example, a new SELinux type was created that runs with standard container protections, but has additional ability to read all of the log file types. This loosens the security only slightly and allows the defined process to run as a container but have read/only access to a particular directory.

    This is much better than disabling SELinux separation all together, but a lot more complex.

    Recommendation

    Investigate the Udica SELinux project, which can create SELinux policy for just this situation. 

    The Udica can simply inspect a container’s configuration and generate a tailored SELinux policy for it. In the following example, the same container will be started to analyze logs. First, create the container, then pipe the output of podman inspect to Udica, creating a policy based on the container.

    $ podman create –name logreader -d -v /var/log:/logs docker.io/rhatdan/loganalyze
    $ podman inspect -l | udica mylog_container
    $ sudo semodule -i mylog_container.cil \ /usr/share/udica/templates/{base_container.cil,log_container.cil}
    $ podman run –replace –name logreader --security-opt label=type:mylog_container.process -d -v /var/log:/logs docker.io/rhatdan/loganalyze

    6. Run container with SELinux separation disabled 

    --security-opt label=disabled
    $ podman run --security-opt label=disable fedora cat /proc/self/attr/current; echo
    unconfined_u:unconfined_r:spc_t:s0

    The spc_t SELinux type is an unconfined type ("super privileged container").

    Containers run with the --privileged flag or with --pid=host or --ipc=host also set this option.

    Security ramification

    If processes within the container escape to the host gaining access to the host file system, they have full access to every file that UID=$USER has access to. If running rootful containers, then it has full access to every file on the host system (ignoring Linux capabilities, DAC_READ_SEARCH and DAC_OVERRIDE). The escaped container process also has full access to every process that its UID is able to interact with.

    For example, an escaped container process running a rootless container has the ability to read and write the $HOME/.ssh content.

    Recommendation

    This option should be rarely used, only in situations when it is necessary to leak major parts of the system into the container; for example, a container needs to examine the entire home directory volume mounted into it. 

    7. Run system with SELinux disabled

    stopdisablingselinux.com. It makes me cry.

    Because the container engines have lots of ways to get the job done, including disabling SELinux separation, this must never happen.

    Conclusion

    Containers make SELinux a lot easier to deal with. In most cases, SELinux just works and the user does not need to worry about it. It quietly protects the containerized process and the host system in the background.

    When holes are poked into the container, SELinux has several options to deal with it.

    Learn more about SELinux: 

    • SELinux Coloring Book
    • How SELinux improves Red Hat Enterprise Linux security
    • Red Hat Dan on Tech: What to know when writing SELinux policies
    • How SELinux separates containers using Multi-Level Security
    Last updated: April 16, 2025

    Related Posts

    • How to transition from Docker to Podman

    • How custom SELinux policies secure servers and containers

    • Deploy and test Kubernetes containers using Podman Desktop

    • Rootless containers with Podman: The basics

    • How to run SQL Server with SELinux enabled on RHEL 9

    • How SELinux improves Red Hat Enterprise Linux security

    Recent Posts

    • Cloud bursting with confidential containers on OpenShift

    • Reach native speed with MacOS llama.cpp container inference

    • A deep dive into Apache Kafka's KRaft protocol

    • Staying ahead of artificial intelligence threats

    • Strengthen privacy and security with encrypted DNS in RHEL

    What’s up next?

    Read Podman in Action for easy-to-follow examples to help you learn Podman quickly, including steps to deploy a complete containerized web service.

    Get the e-book
    Red Hat Developers logo LinkedIn YouTube Twitter Facebook

    Products

    • Red Hat Enterprise Linux
    • Red Hat OpenShift
    • Red Hat Ansible Automation Platform

    Build

    • Developer Sandbox
    • Developer Tools
    • Interactive Tutorials
    • API Catalog

    Quicklinks

    • Learning Resources
    • E-books
    • Cheat Sheets
    • Blog
    • Events
    • Newsletter

    Communicate

    • About us
    • Contact sales
    • Find a partner
    • Report a website issue
    • Site Status Dashboard
    • Report a security problem

    RED HAT DEVELOPER

    Build here. Go anywhere.

    We serve the builders. The problem solvers who create careers with code.

    Join us if you’re a developer, software engineer, web designer, front-end designer, UX designer, computer scientist, architect, tester, product manager, project manager or team lead.

    Sign me up

    Red Hat legal and privacy links

    • About Red Hat
    • Jobs
    • Events
    • Locations
    • Contact Red Hat
    • Red Hat Blog
    • Inclusion at Red Hat
    • Cool Stuff Store
    • Red Hat Summit
    © 2025 Red Hat

    Red Hat legal and privacy links

    • Privacy statement
    • Terms of use
    • All policies and guidelines
    • Digital accessibility

    Report a website issue