Add Gitlab Runner To Docker Group

Add Gitlab Runner To Docker Group

Reading time1 min
#DevOps#Containers#CI/CD#GitLab#Docker#Security

Add GitLab Runner to the Docker Group: Practical, Maintainable Permissions

Encountering this during a CI run?

Got permission denied while trying to connect to the Docker daemon socket at unix:///var/run/docker.sock: Get http:///var/run/docker.sock/v1.24/images/json: dial unix /var/run/docker.sock: connect: permission denied

Root access, sudo, or chowning /var/run/docker.sock may “solve” the error. Each introduces risk. In multi-user environments—or any regulated infrastructure—privilege escalation creates audit and attack surface headaches.

Instead, align with Docker’s least privilege guidance: add the GitLab Runner user to the docker group. Offload container daemon access to a supplementary group, which streamlines permission boundaries.


Why Use the Docker Group for GitLab Runner?

ApproachSecurityFuture MaintenanceAuditability
Run as rootWorstPoorOpaque
Sudo in jobsModerateFrictionDiffuse
docker groupTargetedCleanTraceable
  • Running unprivileged users with Docker group access shrinks the attack surface.
  • Granting only what’s necessary preserves traceability.
  • No need to sprinkle sudo across dozens of .gitlab-ci.yml files.

Note: All group members still control the Docker daemon—a well-known caveat. On hardened multi-tenant hosts, consider separate daemons or socket proxies.


Step-by-Step: Assign Docker Group Membership to GitLab Runner

Some sites run vanilla GitLab Runner, others deploy via Helm chart or as a systemd service. The following reference assumes gitlab-runner user (default install on Ubuntu 20.04+ or similar).

1. Verify Docker and Group Setup

Ensure Docker Engine ≥ 20.10 is running:

sudo systemctl status docker
docker version

Check the docker group exists and your user is part of it:

getent group docker
groups $USER

If gitlab-runner is absent, continue.

2. Identify GitLab Runner Execution Context

Find the Runner’s service user:

systemctl status gitlab-runner | grep 'User='
ps aux | grep gitlab-runner

Typical output:

User=gitlab-runner

On distributions without explicit User=, use ps to check.

3. Assign Docker Group

sudo usermod -aG docker gitlab-runner

The -aG flags ensure existing groups are preserved.
Known Issue: Group membership is only picked up by new login sessions. Systemd does not always auto-refresh—see below.

4. Bounce GitLab Runner Service

Force session reload:

sudo systemctl restart gitlab-runner

For shell executors, a log-out/log-in cycle is mandatory.
Check:

id gitlab-runner

Expected: docker listed in groups.

5. Pipeline Test: Docker Daemon Access

Add to .gitlab-ci.yml:

docker-access-check:
  image: docker:24.0.7
  script:
    - docker info

Result: job logs should contain daemon details (number of containers, storage driver, etc.)—not permission errors.


Common Pitfalls/Edge Cases

  • Custom Docker socket location: If you run Docker with a custom socket (e.g., /run/docker.sock), adjust bind mounts in the Runner config.
  • SELinux/AppArmor interference: On hardened hosts, MAC policies may still block docker daemon access despite Unix group membership. Check audit logs if permission issues persist.
  • Group refresh delay: If groups gitlab-runner omits docker after all steps, the systemd service may cache group info. Workaround: fully log out sessions or forcibly restart affected services/users.
  • Kubernetes executor: The above applies to shell or systemd runners; with k8s, Docker socket access is handled through volume mounts and pod security policies—not group assignments.

Gotcha: This method gives the Runner full control over the Docker daemon, including host access via volume mounts. For highly sensitive workloads, prefer rootless Docker or isolated build environments.


Why Not Sudo?

Permitting sudo docker (even with NOPASSWD) in CI risks lateral privilege escalation. It also increases ambiguity: Does a failed docker command mean a permissions error or a deeper misconfiguration?
Group-based access is explicit, easier to audit (/etc/group), and easily reversed.


Example: Real-World CI Failure

A broken pipeline, pre-fix:

$ docker build -t myimage .
Got permission denied while trying to connect to the Docker daemon socket...

Post-fix:

$ docker info
Client:
 Context:    default
 Server:
  Containers: 8
  ...

Add the group, restart services, re-run the job—no more hunting for stray sudo prompts.


Alternate Approaches (Not Used Here)

  • docker:dind images enable self-contained DinD, but complicate caching, storage, and networking.
  • Rootless Docker offers better isolation—requires additional config and still maturing for all cases.

Summary:
Direct group assignment is a pragmatic, well-understood fix for runner permission errors against Docker’s root-owned Unix socket.
Configure once, automate for new runners, and review access as your environment evolves.

If stuck, inspect runner logs (/var/log/gitlab-runner/), audit group memberships, and scan Docker daemon logs for additional permission denials.

Questions or edge-case findings? Raise a merge request or discuss with your sysadmin team.
No silver bullets—but this gets most teams >95% to friction-free Docker-powered CI/CD.