Docker in a Docker

Running a docker container from inside a docker container, I mean.

Of course one can define an image that instanciate a container as its default command, and this would lead to an infinite loop of forks … let’s see

The infinite containment

docker run -v /var/run/docker.sock:/var/run/docker.sock -name whocare alwaysfork

Ok, that is bad and I will not describe.

Container near a container

Maybe it is a bad thing, but most of the time docker and container is used interchangely, so I would had better written docker near a docker, that is cool.

What is near and why not “in”? it is like the infinite containment example, it is near because every contained execution is managed by the main daemon (dockerd) running in the host machine.

In fact in a infiniete containement you are not forking endless, but you are asking the dockerd to instanciate endlessly a new container, there is nothing that make one of the container a manager of the other, or a more authoritative manager than the other: every container that can access the /var/run/docker.sock socket and has the right can stop/remove every container in the machine.

Security concerns

I am not expert of security concerns, but everytime you do something “strange” there are great chances that that “strangeness” could lead to a security hole. (not being an expert I think even “not-strange” done by me can imply bad things)

Here the problem is due to the way docker is managing user, and mostly by how it manage the uid=0, root. The command by itself run the image standard command, and it is expected that the Dockerfile specify USER that will run the default command (and that is something != root).

But the weird part here is that being actually a container-near-container situation, at every instanciate point it could be switched to root with a

docker exec -u root -it myfunnyimage ./abadcommandforyou

this could be run from any container, call it aquitecontainer, all that is needed is the docker command in the image of aquitecontainer and that the socket is mounted as -v /var/run/docker.sock:/var/run/docker.sock and … so?

So you can switch to root from a container not running as root, because you can see the socket, and this is enough.

Two case are given:

  1. the containing container is running as root, so no particular needs to access the socket
  2. the containing container is running as a unprivileged user, but it has access to socket, so no particular needs to access the socket from the anyuserisused inside
  3. the containing container is instanciated by root, but running as unprivileged user, that again map to the calling user, that is root

Yes, the problem here is that docker daemon always map the “no-root” user to the uid of the user that call its api.

But really it is not enough

In fact to access /var/run/docker.sock a user must be part of docker group, when a container is instanciated with its default user the groups are not migrated, so the image’s definition of user’s group membership is something to take into account: if internal user of the docker has no access to the docker.sock it can not communicate with the dockerd running, so no more docker in docker, no more root migration