[How-to] Own CA Certificate in GitLab CI with dind service (docker-in-docker)

Today I struggled to try to connect to a private registry from within a gitlab-runner running docker-in-docker (or dind). The CI stopped with the error x509: certificate signed by unknown authority. I finally figured it out with some inspiration from this issue in the gitlab-runner repo.

Step 1: CA as an Environment Variable

The easiest way to get your CA certificate into your runner is by using environment variables. To do so we must copy the content of our certificate into a runner variable in GitLab under Project -> Settings -> CI/CD -> variables.

In the following example I created an environment variable called CA_CERTIFICATE:

Gitlab CI – Add Environment Variable

Step 2: Configure .gitlab-ci.yml

For the sake of simplicity we will use docker-in-docker with TLS disabled:

my_job:
  # ...
  image:
    name: docker:19.03
  variables:
    DOCKER_HOST: tcp://localhost:2375
    DOCKER_TLS_CERTDIR: ""
  services:
    - name: docker:19.03-dind
  # ...

.gitlab-ci.yml – Dind without TLS

Next, we have to pass our certificate as an environment variable to the dind service container. Important: this will not happen automatically!

my_job:
  # ...
  variables:
    # ...
    CA_CERTIFICATE: "$CA_CERTIFICATE"
  services:
    - name: docker:19.03-dind
  # ...

.gitlab-ci.yml – Pass env Variable to Service Container

Finally, we can override the container command and properly install our CA certificate before starting the docker service:

my_job:
  # ...
  services:
    - name: docker:19.03-dind
      command:
        - /bin/sh
        - -c
        - echo "$CA_CERTIFICATE" > /usr/local/share/ca-certificates/my-ca.crt && update-ca-certificates && dockerd-entrypoint.sh || exit

.gitlab-ci.yml – Install CA Certificate in Service Container

And we're done!

A full example of the .gitlab-ci.yml looks like this:

stages:
  - image_build

image_build:
  stage: image_build
  image:
    name: docker:19.03
  variables:
    DOCKER_HOST: tcp://localhost:2375
    DOCKER_TLS_CERTDIR: ""
    CA_CERTIFICATE: "$CA_CERTIFICATE"
  services:
    - name: docker:19.03-dind
      command:
        - /bin/sh
        - -c
        - echo "$CA_CERTIFICATE" > /usr/local/share/ca-certificates/my-ca.crt && update-ca-certificates && dockerd-entrypoint.sh || exit
  script:
    - docker info
    - docker login -u $DOCKER_USERNAME -p $DOCKER_PASSWORD $DOCKER_REGISTRY
    - docker build -t "${DOCKER_REGISTRY}/my-app:${CI_COMMIT_REF_NAME}" .
    - docker push "${DOCKER_REGISTRY}/my-app:${CI_COMMIT_REF_NAME}"

.gitlab-ci.yml – Example dind with own CA Certificate