Custom CA and self-hosted Gitlab instance and runners with Docker executor

Replace this template with your information

Describe your question in as much detail as possible:

How can I use docker runners with my own CA in a CI/CD pipeline?

  • What are you seeing, and how does that differ from what you expect to see?

As mentioned in the documentation there, there are few ways of preparing the runner to be able to recognize self-signed CA, please check here: Self-signed certificates or custom Certification Authorities | GitLab

So I have this on every runner as configuration:

  executor = "docker"
  # Copy and install CA certificate before each job
  pre_build_script = """
  apt-get update -y > /dev/null
  apt-get install -y ca-certificates > /dev/null
  cp /etc/gitlab-runner/certs/ca.crt /usr/local/share/ca-certificates/ca.crt
  update-ca-certificates --fresh > /dev/null
    volumes = ["/cache", "/etc/gitlab-runner/certs/ca.crt:/etc/gitlab-runner/certs/ca.crt:ro"]

Which works like a charm, but I’m restricted to use only Debian/Ubuntu based images…
How I know that? I tried to run an Alpine container and the pipeline failed because apt-get is not a valid command. (this is step of the preparation process)

Are you using self-managed or The DevSecOps Platform | GitLab

I do use self-hosted Gitlab instance.

  • Runner (Hint: /admin/runners):

I do use self-hosted runners, with a Docker executor.

  • Add the CI configuration from .gitlab-ci.yml and other configuration if relevant (e.g. docker-compose.yml)
  name: aquasec/trivy
  entrypoint: [""]
    GIT_STRATEGY: fetch
    GIT_CHECKOUT: "true"
    - apk update
    - apk add git bash
    - >

      export COMMIT_BEFORE_SHA="$(git rev-parse HEAD~1)"
      export COMMIT_SHA="$(git rev-parse HEAD~0)"
      export COMMIT_BEFORE_SHA="$(git rev-parse HEAD~1)"
      export COMMIT_SHA="$(git rev-parse HEAD~0)"

      FILES=`git diff "${COMMIT_BEFORE_SHA}" "${COMMIT_SHA}" --name-only`

      for FILE in "${FILES[@]}"; do
          # Check if the file exists
          if [ -e "$FILE" ]; then
              echo "Scanning file $FILE"
              trivy fs --scanners vuln,secret,misconfig "$FILE"
              echo "File $FILE does not exist."
  • What troubleshooting steps have you already taken? Can you link to any docs or other resources so we know where you have been?

I really don’t have a clue how to do next.

Thanks for taking the time to be thorough in your request, it really helps! :blush:


Yeah, this is a tricky one. I spent many hours on this and I think GitLab could improve experience about those use cases.

Bottom line - yes, you are correct. With a setup like this, pre-script works only with Debian-based images. This is the reason why I personally don’t use it like that, as I have a bunch of alpine images as well (I like to keep runners as generic as possible). However, if you want to continue using this method, I guess you could register another runner with same executor, and have different tags between two - one e.g. docker-debian, and another docker-alpine. Then you could define a different pre-script on Runner level that would be compatible with Alpine images (apk add…) and in your jobs specify those runner tags.

Second way would be to remove that pre-script on Runner level and do it per-job level as before_script (again depending on the image). However, this is also quite repetitive, so you would probably need to setup some nice templating/importing for across all your projects. Never done it, but shouldn’t be too big effort, depends how many projects you already have.

Third way would be to get rid of that pre-script certificate installation completely and just inject CA when the explicit request needs it. This is also not ideal, but I do it like that for now. CA cert I’m keeping as a file variable at the top group level. Or, if it’s your GitLab’s certificate CA, you can use predefined CI_SERVER_TLS_CA_FILE in most cases. Example - uploading a file to GitLab’s package registry:

curl --cacert $CA_CERT --header "JOB-TOKEN: $CI_JOB_TOKEN" --upload-file $filename "${CI_API_V4_URL}/projects/${CI_PROJECT_ID}/packages/generic/$i/$version/$filename"

Not 100% sure if this would work with your job here, depends if trivy has a parameter to pass this variable.

Perhaps there are more ways as well. This is just from my experience so far. Hope it helps! :slight_smile:

1 Like

Yeah, thanks for the replay.

I’m glad that I’m not alone :-))) Anyway, probably I will get rid of globally defined pre-script and use it on a project basis depends on the pipeline I needs to execute. Unfortunately most of the time Gitlab CI/CD should interact with the code which is hosted in the same Gitlab instance :slight_smile:

Will get used to it.
Thanks again.

1 Like