contrib: add docker_client SELinux policy module to access socket in container

When running the docker daemon with `--selinux-enabled`, access to the docker
socket is prevented by SELinux. To access the socket, the container must be
started with `--privileged`, with SELinux disabled (`--security-opt label=disable`),
or with (e.g.) `--security-opt label=type:container_runtime_t`, which gives
it access to files restricted to the runtime ( `dockerd` daemon) itself.

While having access to the docker socket grants full `root` permissions on
the host (e.g. through starting a privileged container using the socket),
it may be preferable to restrict the container to just the socket.

This patch adds a `docker_client.process` SELinux CIL policy module that
defines a container domain (process type). It inherits the base container
template and grants the permissions needed to use the docker socket.

Without this (and the daemon running with `--selinux-enabled`);

    docker run -it --rm -v /var/run/docker.sock:/var/run/docker.sock docker:cli -H unix:///var/run/docker.sock version
    Client:
     Version:           28.4.0
     API version:       1.51
     Go version:        go1.24.7
     Git commit:        d8eb465
     Built:             Wed Sep  3 20:56:28 2025
     OS/Arch:           linux/amd64
     Context:           default
    permission denied while trying to connect to the Docker daemon socket at unix:///var/run/docker.sock: Get "http://%2Fvar%2Frun%2Fdocker.sock/v1.51/version": dial unix /var/run/docker.sock: connect: permission denied

With this:

    semodule -i /usr/share/udica/templates/base_container.cil
    semodule -i ./contrib/selinux/docker_client.cil

    docker run -it --rm -v /var/run/docker.sock:/var/run/docker.sock --security-opt label=type:docker_client.process docker:cli -H unix:///var/run/docker.sock version
    Client:
     Version:           28.4.0
     API version:       1.51
     Go version:        go1.24.7
     Git commit:        d8eb465
     Built:             Wed Sep  3 20:56:28 2025
     OS/Arch:           linux/amd64
     Context:           default

    Server: Docker Engine - Community
     Engine:
      Version:          28.4.0
      API version:      1.51 (minimum version 1.24)
      Go version:       go1.24.7

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
This commit is contained in:
Sebastiaan van Stijn
2025-09-26 17:36:34 +02:00
parent 2670796a01
commit 77bf85647c

View File

@@ -0,0 +1,57 @@
; docker_client.cil
;
; This file defines a "docker_client.process" *container domain* (process type)
; that can connect to the Docker daemon via /var/run/docker.sock. It assumes
; the docker socket is labeled with "container_var_run_t", and the dockerd
; daemon is running in the "container_runtime_t" domain;
;
; ls -Z /var/run/docker.sock
; # system_u:object_r:container_var_run_t:s0 /var/run/docker.sock
;
; ps -eZ | awk '/dockerd/{print $1; exit}'
; # system_u:system_r:container_runtime_t:s0
;
; It inherits the "container" (container_base.cil) udica template, which must
; be loaded before this. To load the "container_base" template;
;
; sudo semodule -i /usr/share/udica/templates/base_container.cil
;
; Or, to load all udica templates:
;
; sudo semodule -i /usr/share/udica/templates/*.cil
;
; Install this module:
;
; sudo semodule -i docker_client.cil
;
; Usage example:
;
; Use the '--security-opt label=type:docker_client.process' option to
; run a container with the docker_client process label. For example;
;
; docker run -it --rm \
; --security-opt label=type:docker_client.process \
; -v /var/run/docker.sock:/var/run/docker.sock \
; docker:cli -H unix:///var/run/docker.sock version
(block docker_client
(blockinherit container) ; make this a proper container domain (MCS, attributes, etc.)
; Allow opening /var/run/docker.sock by its pathname label.
; Replace container_var_run_t if your host uses a different label (e.g., var_run_t).
(allow process container_var_run_t (sock_file (read write open getattr)))
; Allow traversing /var/run (usually var_run_t) to reach the socket.
(allow process var_run_t (dir (search getattr read open)))
)
; Allow connecting to the daemons listening socket (dockerd runs in container_runtime_t).
(allow docker_client.process container_runtime_t (unix_stream_socket (connectto)))
; also include one (or both) of these if they exist on the host:
(optional docker_client_dc1
(allow docker_client.process docker_t (unix_stream_socket (connectto)))
)
(optional docker_client_dc2
(allow docker_client.process container_engine_t (unix_stream_socket (connectto)))
)