Using SELinux with Containers

Posted on

Security-Enhanced Linux (SELinux) is a Linux kernel security module that provides a mechanism for supporting access control security policies, including mandatory access controls (MAC). Containers support running on hosts with SELinux enabled.

If you are just getting started with SeLinux, I highly recommend watching “Security-Enhanced Linux for mere mortals by Thomas Cameron”.

In the cloud, if you are looking to run containers on SELinux you will need to run on top of CentOS or Red Hat Enterprise Linux. These operating systems have the best support for SELinux and the corresponding policy modules.

I have recently been diving into SELinux for use within highly regulated environments. I have attempted to explain how SELinux works with Containers and how you can get started.

SELinux for Containers

SELinux policies for containers are defined by the container-selinux package. Docker CE requires this package (along with its dependencies) so that the processes and files created by Docker are able to run with limited system access. Containers leverage the container_t label which is simply an alias to svirt_lxc_net_t and container_file_t which is an alias to svirt_sandbox_file_t. More informaton is available on Dan Walsh’s blog.

By default, containers are run with the label container_t and are allowed to read/execute under /usr and read most content from /etc. The files under /var/lib/docker and /var/lib/containers have the label container_var_lib_t.

ls -Z /var/lib/docker
# drwx------. root root system_u:object_r:container_var_lib_t:s0 builder
# drwx--x--x. root root system_u:object_r:container_var_lib_t:s0 buildkit
# drwx------. root root system_u:object_r:container_var_lib_t:s0 containers
# drwx------. root root system_u:object_r:container_var_lib_t:s0 image
# drwx------. root root system_u:object_r:container_var_lib_t:s0 lost+found
# drwxr-x---. root root system_u:object_r:container_var_lib_t:s0 network
# drwx------. root root system_u:object_r:container_share_t:s0 overlay2
# drwx------. root root system_u:object_r:container_var_lib_t:s0 plugins
# drwx------. root root system_u:object_r:container_var_lib_t:s0 runtimes
# drwx------. root root system_u:object_r:container_var_lib_t:s0 swarm
# drwx------. root root system_u:object_r:container_var_lib_t:s0 tmp
# drwx------. root root system_u:object_r:container_var_lib_t:s0 trust
# drwx------. root root system_u:object_r:container_var_lib_t:s0 volumes
ls -Z /etc/docker
# dr--r--r--. root root unconfined_u:object_r:cert_t:s0  certs.d
# -rw-r--r--. root root system_u:object_r:container_config_t:s0 daemon.json
# -rw-------. root root system_u:object_r:container_config_t:s0 key.json

Containers do not have access to these folders because it can interfere with the container engine. The SELinux policy also prevents mounting protected files into containers by default.

docker run -it \
  -v /var/lib/docker/image/overlay2/repositories.json:/host/repositories.json \
  centos:7 cat /host/repositories.json
# cat: /host/repositories.json: Permission denied

docker run -it \
  -v /etc/passwd:/host/etc/passwd \
  centos:7 cat /host/etc/passwd
# cat: /host/etc/passwd: Permission denied

Files labeled with container_file_t are the only files that are writable by containers. If you want a volume mount to be writeable, you will needed to specify :z or :Z at the end. Their behavior is different so be careful which one you are using. Let’s start with :z:

ls -Z /var/lib/misc
# -rw-r--r--. root root system_u:object_r:var_lib_t:s0   postfix.aliasesdb-stamp

docker run -it \
  -v /var/lib/misc:/host/var/lib/misc:z \
  centos:7 echo "Relabeled!"

ls -Z /var/lib/misc
#-rw-r--r--. root root system_u:object_r:container_file_t:s0 postfix.aliasesdb-stamp

If you want to mount a folder so that only that container can access the folder, for example such as your logging daemon, swap out :z with :Z.

docker run -it \
  -v /var/log:/host/var/log:Z \
  fluentbit:latest

How to Enable SELinux for Containers

Enabling SELinux with containers is only supported on CentOS and Red Hat Enterprise Linux.

Amazon Linux 2 currently lacks the policy modules that make containers work with SELinux.

  1. Enable SELinux on the host operating system
  2. Install Docker CE with the container-selinux package
  3. Enabled the container cgroup boolean setsebool container_manage_cgroup 1
  4. Add "selinux-enabled": true to /etc/docker/daemon.json
  5. systemctl daemon-reload && systemctl restart docker

Conclusion

Container linux can be difficult to work with and may interfere with Kubernetes CNI drivers, CSI drivers, and some Ingress Controllers. Some common things to check for are access to privileged ports, or access to files on the host.