Some customers may wish to install Replicated on a server with SELinux enabled.
The Replicated native and Kubernetes schedulers are compatible with SELinux as of v2.12.0.
Docker & SELinux
SELinux labels processes with domain types that can be given permission to manage system resources such as ports and files.
When used together, SELinux provides an additional layer of security around the isolation features offered by containers.
Docker starts containers in the unconfined_t
domain by default, which effectively bypasses the SELinux kernel.
Pass the --selinux-enabled
flag to docker to begin enforcement on containerized processes.
SELinux must also be enabled and enforcing on your system for this to take effect.
Run sestatus
or view the contents of /etc/selinux/config
to check the status of SELinux.
When started with the --selinux-enabled
flag, Docker starts containers in the svirt_lxc_net_t
domain.
The svirt_lxc_net_t
domain provides full networking capabilities, read/execute access to /usr,and full access to files labeled svirt_sandbox_file_t
.
This type is suitable for most containerized components, such as Redis, MySQL, or Nginx.
The spc_t domain
Some applications like Replicated are required to monitor hosts and launch other containers.
These cannot be run in the unmodified svirt_sandbox_file_t
domain.
Fortunately the spc_t
domain was designed for this use case.
Run a container in the spc_t
domain with the --security-opt
flag:
# docker >= 1.11
docker run --security-opt label=type:spc_t replicated
# docker <= 1.10
docker run --security-opt label:type:spc_t replicated
The install scripts configure Replicated to run in this domain.
Preparing Your Application for SELinux
The first step to packaging an application for SELinux is to identify volumes that must be accessed by containers.
The z
and Z
volume options tell Docker to relabel files in a directory before mounting them in a container.
In your Yaml config use the “z” option for volumes that must be shared between multiple containers and the “Z” option for volumes that only need to be accessible to a single container.
volumes:
- host_path: /dbdata
container_path: /var/lib/mysql
options: ["Z"]
Be careful not to relabel directories containing files required by other processes. Mounting /etc
or /var
with the “z” option would break most systems.
The second step is to identify components that cannot run within the svirt_lxc_net_t
domain and apply a different label to them.
security_options:
- label=type:my_app_t
If using a custom type as in this example, the relevant policy must be installed before starting the application.
Reusing an existing type such as spc_t
for these containers will obviate the need to write and distribute policy.
Debugging an Application
Let’s look at a simple example of packaging an application to run under SELinux.
If you create a release containing the following Redis component and attempt to install it on a server with SELinux enabled, you’ll notice the Redis container is crashing.
components:
- name: DB
containers:
- source: public
image_name: redis
version: latest
cmd: "[\"redis-server\", \"--appendonly\", \"yes\"]"
volumes:
- host_path: /data
container_path: /data
Since the app works without SELinux enabled, the first place to investigate is the SELinux audit log.
tail -f /var/log/audit/audit.log | grep avc
This will show permission denied errors similar to the following:
type=AVC msg=audit(1504739956.487:4194): avc: denied { setattr } for pid=6210 comm="chown" name="data" dev="sda1" ino=612444061 scontext=system_u:system_r:svirt_lxc_net_t:s0:c652,c951 tcontext=system_u:object_r:root_t:s0 tclass=dir
That record is reporting a denial of a container process (svirt_lxc_net_t) attempting to manage a directory named “data”. Find the exact target directory by searching for the reported inode.
find / -inum 612444061
# /data
Returning to the yaml config, notice the Redis container attempts to mount the hosts “/data” directory. On your server, check the SELinux label applied to this directory.
ls -Zd /data
# dr-xr-xr-x. root root system_u:object_r:root_t:s0 /data
The directory has the root_t label, which the container process cannot access. Update the yaml config for the volume with an option that will cause Docker to relabel the host directory with a context accessible to the container.
volumes:
- host_path: /data
container_path: /data
options: ["Z"]
This single redis container is the sole user of the /data directory, so we can use the “Z” options, which will label it with a context unique to this container.
After creating a new release with the updated config and upgrading the installed app, the Redis component works as expected.
Best Practices
- Add the
"z"
or"Z"
option to all volumes mounted in containers unless their content needs to be accessible to non-containerized processes. - Test applications with SELinux enabled while using the audit log to identify components with incorrect permissions.
- Consider the
spc_t
for containers designed to manage host systems.