20.3.1.5 Socket Protection Practice
A focused guide to Socket Protection Practice, connecting core concepts with practical Docker and container operations.
The Docker daemon socket (/var/run/docker.sock) is a Unix domain socket that provides direct access to the Docker API. Any process with access to this socket can create, inspect, start, stop, and delete containers; create images; mount host directories; and launch containers with arbitrary configurations — including privileged containers. Mounting the Docker socket inside a container grants that container the ability to control the host's Docker daemon, which is functionally equivalent to root access on the host. Socket protection practice is the discipline of understanding this risk and applying appropriate controls.
The Risk of Docker Socket Exposure
The Docker socket is owned by root and the docker group. On the host, access to it is a form of privilege escalation — a user in the docker group can create containers that mount any host directory, including /, and gain root access to the host filesystem.
When the socket is mounted into a container:
docker run -v /var/run/docker.sock:/var/run/docker.sock some-image
The container process can call the Docker API directly. From inside the container:
docker run -v /:/host --privileged alpine chroot /host
This creates a new privileged container that mounts the host root filesystem and chroots into it — a complete container escape that gives full host root access. No kernel exploit is required. The socket provides an authorized path to this result.
Why the Socket Is Mounted in Practice
Despite the risk, the Docker socket is legitimately mounted for several purposes:
CI/CD image building — Building Docker images inside a CI runner container requires access to a Docker daemon. Mounting the host socket gives the CI container access to the host daemon for docker build and docker push.
Container management tools — Monitoring dashboards (Portainer, Watchtower, ctop), container management agents, and sidecars that restart or manage other containers require API access.
Log and metric collectors — Some monitoring tools need socket access to call docker stats or inspect container metadata.
Assessing Whether Socket Mount Is Necessary
Before mounting the socket, consider whether the actual requirement is met by a less dangerous alternative:
| Use case | Safer alternative |
|---|---|
| Build images in CI | Kaniko, Buildah, or a remote BuildKit daemon with TLS |
| Monitor container metrics | Expose specific metrics via an API endpoint or use the Docker stats API over TCP with TLS |
| Restart containers | Use an orchestrator (Kubernetes, Swarm) for lifecycle management rather than direct API calls |
| Pull images | Pre-pull images before starting the container; use init containers in Kubernetes |
If the socket must be mounted, apply the following controls.
Read-Only Socket Mount
The Docker socket is a Unix domain socket, not a filesystem. Mounting it read-only does not meaningfully restrict access — a read-only socket mount still allows all API calls because the Docker daemon performs actions server-side based on the client's request, and the socket is a bidirectional communication channel. This is a common misconception:
# This does NOT meaningfully restrict Docker API access:
docker run -v /var/run/docker.sock:/var/run/docker.sock:ro some-image
The :ro flag only controls whether the socket file itself can be replaced or deleted by the container — it does not restrict the API calls that can be made through the socket.
Docker Socket Proxy
A socket proxy is a process that sits between a container and the Docker socket, filtering which API calls are allowed. Docker Socket Proxy (github.com/Tecnativa/docker-socket-proxy) is the most widely used implementation. It exposes only the specific Docker API endpoints that the requesting container needs:
services:
socket-proxy:
image: tecnativa/docker-socket-proxy
volumes:
- /var/run/docker.sock:/var/run/docker.sock:ro
environment:
CONTAINERS: 1 # allow reading container info
SERVICES: 0 # deny service management
NETWORKS: 0 # deny network management
IMAGES: 0 # deny image operations
INFO: 1 # allow docker info
networks:
- proxy_net
dashboard:
image: portainer/portainer-ce
environment:
DOCKER_HOST: tcp://socket-proxy:2375
networks:
- proxy_net
networks:
proxy_net:
internal: true
The dashboard container connects to the proxy, not directly to the Docker socket. The proxy only passes the API calls specified by its environment variables. docker run and docker build calls are blocked; read-only container listing and info calls are allowed.
TLS-Protected Remote Docker API
Instead of mounting the Unix socket, connect to the Docker daemon over a TLS-protected TCP endpoint. The Docker daemon can be configured to listen on TCP with mutual TLS:
# On the host, configure dockerd with TLS
dockerd \
--tlsverify \
--tlscacert=ca.pem \
--tlscert=server-cert.pem \
--tlskey=server-key.pem \
-H=0.0.0.0:2376
The container connects using client certificates:
docker run \
-e DOCKER_HOST=tcp://host.docker.internal:2376 \
-e DOCKER_TLS_VERIFY=1 \
-v /path/to/certs:/certs \
my-ci-image \
docker build -t my-image .
TLS mutual authentication means the container must present a valid client certificate, and the daemon only responds to clients with certificates signed by the CA. This limits access to authorized clients rather than any process that can reach the socket.
Detecting Socket Exposure
To check whether a running container has the Docker socket mounted:
docker inspect my-container --format '{{range .Mounts}}{{if eq .Source "/var/run/docker.sock"}}SOCKET MOUNTED{{end}}{{end}}'
To find all running containers with socket access:
docker ps -q | xargs -I {} docker inspect {} --format '{{.Name}} {{range .Mounts}}{{.Source}} {{end}}' | grep docker.sock
Organizational Controls
For environments where the Docker socket must never be accessible to containers:
Docker authorization plugins can intercept API calls and reject any docker run that includes a /var/run/docker.sock mount. OPA (Open Policy Agent) can enforce this as a policy.
Kubernetes admission controllers block pod specs that mount /var/run/docker.sock via volume host path mounts, enforcing this at the cluster level.
Audit logging for Docker daemon operations captures all API calls with the client identity, making socket-based operations visible in security event logs.
Socket protection is not about preventing all socket access — it is about ensuring that access is intentional, scoped to the minimum required API surface, and visible to security operations.