Throughout the last months I’ve seen many discussions about Docker security, trying to “attack” the problem from different angles:
Some take the discussion into the infrastructure level, talking about container isolation achieved by Linux kernel mechanisms (namespaces, capabilities, cgroups) and comparing it to virtual machine isolation.
Other focus on operational aspects, where there is a discussion on how secured are the Docker Hub images and what should be the tactics for logging and patching.
On this post I would like to discuss a different angle which I feel is not discussed enough – the Docker Administration interfaces and how secured are they.
To manage Docker we use the docker command line – it provides interfaces for Docker’s operational tasks, like: start container, stop container, export container, delete container, etc.
This command line can be used to manage local and remote Docker daemons. It uses two main channels to communicate with the Docker daemon: UNIX socket for local management (/var/run/docker.sock) and TCP/SSL for remote management.
On this post we will focus on the local management, which is based on the UNIX socket.
As you can imagine, users with access to the docker command line are quite powerful – they can start every container, stop, import, export and so on. For this reason access to the docker command line is restricted to ‘root’ and to members of ‘docker’ group (a group that is created as part of Docker installation). This restriction is achieved by a simple UNIX file permissions on the /var/run/docker.sock UNIX socket file (access allowed to ‘root’ and ‘docker’ group).
Docker supplies a ‘whole or nothing’ approach, where you either get admin access to Docker or no access. It does not supply admin segregation controls, where different users can be granted with different admin rights to different containers.
The following diagram describes ‘alice’ and ‘bob’, two UNIX users, member of ‘docker’ group. These users have full administrative access to all Docker commands, allowing them to manage all the images and containers, regardless of their origin and owner.
User Privilege Elevation
So we understand that ‘docker’ group members can fully manage Docker environment. But what about the Docker host? Does these users get extra privileges on the host itself? Well, the answer is yes. These users can easily surrogate into real ‘root’ account on the host! This privilege elevation is possible by leveraging the following Docker properties:
- Docker containers run as ‘root’ user id.
- Container can be configured to use host resources.
One example is volume mounts, where a container can get direct read/write access to host directories.
Combining #1 and #2 creates a flaw: members of ‘docker’ group can create a ‘root’ container. This container can be configured with read/write access to host shared resources (e.g. host volumes). When such access is made from the container to the host shared resource, it will be made as ‘root’ as the container is running as ‘root’…
The following example demonstrate how user ‘alice’, a member of group ‘docker’, can obtain elevated privileges on the host by running a container that creates a root setuid program on the host:
[alice@docker] cp /bin/sh /home/alice
[alice@docker] docker run –rm –v /home/alice:/host busybox /bin/sh –c “chwon root.root /host/sh && chmod a+s /host/sh”
As you can see, Alice copies a shell program into her home directory and runs a container that adds ‘setuid’ flag on Alice’s copied shell. This is possible as container is running under ‘root’ and access to this file was supplied to container through volume mount.
Alice can then run her new setuid shell program to become ‘root’.
Container Privilege Elevation
Up until now we’ve discussed users: how alice and bob, non root users, can become root on the host if they are granted with membership to docker group. The question is whether a similar elevation of privileges can be done by a regular container? Can a container, which you’ve downloaded from the Docker Hub, get full ‘root’ access on your host?
Well, yes! And I am not talking about super-privileged containers (containers that run with –privileged parameter). I am talking about a regular container. Well, almost regular. The only caveat is that this container needs access to Docker UNIX socket (/var/run/docker.sock). This is possible by running the container with one of the following volume mount options:
# direct access to the docker socket
docker run -v /var/run/docker.sock:/var/run/docker.sock …
# access to /var/run directory
docker run -v /var/run:/var/run …
# access to /var directory
docker run -v /var:/var…
# access to root file system (where docker socket is located)
docker run -v /:/host …
Since this container is running as ‘root’ and it has access to Docker socket, it can use Docker CLI (which can be installed on the container) to spawn additional container on the host. What’s more interesting is that this innocent container can launch super-privileged container (with –privileged parameter), which will allow it to obtain root access to the host…
For the purpose of the demo I’ve created a public image ‘jerbi/docker_cli’ on the Docker Hub.
If you will download and run this image while providing it with a Docker socket, it will create a user ‘hacked’ on your system.
It does that by accessing your Docker socket and running a super-privileged container. This privileged container then uses ‘nsenter’ to get out of Linux namespace jail and run a command on your host (as root).
To try out the ‘jerbi/docker_cli’ container, run the following command:
docker run –rm -v /var/run/docker.sock:/var/run/docker.sock jerbi/docker_cli
The sources of this demo are also available on GitHub: https://github.com/jerbia/container_hack.
Conclusion and Possible Mitigation
Applying proper administration controls on your Docker environment insure that admins users and containers can only access resources needed for their operation. Docker does not come with built-in administrative controls therefore I suggest taking the following actions to mitigate the risk:
- Administration segregation is not possible with Docker. Separate sensitive containers, which you don’t want other administrators to manage, into dedicated machines with limited access.
- Members of ‘docker’ group can obtain full root access to Docker hosts.
Treat these users as root accounts! Apply extended auditing and password controls for these users.
If possible, drop ‘setuid’ and ‘setgid’ capabilities from running containers.
- Special attention should be taken when running containers with access to the Docker socket. Consider using SELinux to limit the ability of these containers to execute programs on the host with root privileges.