If you are reading this article you probably already know how to use DinD (DockerInDocker) in GitLab CI.
The default way is to set
privileged=true in your Runner-config.
This little flag makes everything work; but at the cost of security. There are many articles regarding this topic, eg. this one. The baseline is, if you run a container privileged, and the container uses the root-user inside, you can lose the whole server.
There are multiple ways of solving this security problem.
If you just need to build docker-images you could consider using BuildKit (-rootless) directly or some other docker image builder like buildah or Kaniko. If you want to learn more about alternate image builders visit blog.alexellis.io/building-containers-without-docker.
One thing I tried was to limit
privileged=true to the DinD container only, but I found no way to do that.
Even if this solution would work, you are still able to start a privileged container from the CI-Job via the privileged DinD - so no security gain.
Another option is to set
privileged=false; but you won’t be able to run DinD anymore.
Mounting the docker-socket into the container (DooD) is bad as well, because the docker-deamon normally runs as root.
Since version 20.10 docker supports a "Rootless mode".
You can either run your GitLab Runner with docker installed in "Rootless mode" or use
Because Docker was already installed on the host, I chose the rootless DinD container, because it was the easiest to implement for me at this point.
The general idea is to run DinD outside of the GitLab CI world but make it usable transparently from inside.
dind-rootless you still need to run the container in privileged mode, but it is more secure, because the user used inside the container has no root permissions.
While figuring out how to get this setup working I chose to reinstall my GitLab Runner using docker. The result is a way to automate the process installing a new GitLab Runner with DinD support on a server.
You can find the fruits of my work here: gitlab.com/nidomiro.de/server/gitlab-runner-config.
The security can potentially be optimized further by using a rootless docker on the host and/or by using a docker image builder like mentioned before. My choice was docker because I want to try the new buildx command in the future to test multi-CPU architecture builds.
If you have any questions or improvements, let me know in the comments below.