如何让 Docker 中的 GitLab Runner 看到自定义 CA 根证书

How to make GitLab Runner in Docker see a custom CA Root certificate

我已经安装并配置:

  1. 本地 GitLab OmnibusServerA 运行 在 HTTPS
  2. 本地 GitLab-Runner 作为 Docker 服务安装在 ServerB

服务器证书由自定义 CA Root 生成

配置

我已将 CA 根证书放在 ServerB 上:

/srv/gitlab-runner/config/certs/ca.crt

已按照 Run GitLab Runner in a container - Docker image installation and configuration:

中所述在 ServerB 上安装了 Runner
docker run -d --name gitlab-runner --restart always \
           -v /srv/gitlab-runner/config:/etc/gitlab-runner \
           -v /var/run/docker.sock:/var/run/docker.sock \
           gitlab/gitlab-runner:latest

已按照 Registering Runners - One-line registration command 中所述注册 Runner:

docker run --rm -t -i 
            -v /srv/gitlab-runner/config:/etc/gitlab-runner 
           --name gitlab-docker-runner gitlab/gitlab-runner register \
           --non-interactive \
           --executor "docker" \
           --docker-image alpine:latest \
           --url "https://MY_PRIVATE_REPO_URL_HERE/" \
           --registration-token "MY_PRIVATE_TOKEN_HERE" \
           --description "MyDockerServer-Runner" \
           --tag-list "TAG_1,TAG_2,TAG_3" \
           --run-untagged \
           --locked="false"

此命令给出了以下输出:

Updating CA certificates...
Runtime platform arch=amd64 os=linux pid=5 revision=cf91d5e1 version=11.4.2
Running in system-mode.

Registering runner... succeeded runner=8UtcUXCY
Runner registered successfully. Feel free to start it, but if it's running already the config should be automatically reloaded!

我检查过

$ docker exec -it gitlab-runner bash 

并且一次在容器中

$ awk -v cmd='openssl x509 -noout -subject' '
/BEGIN/{close(cmd)};{print | cmd}' < /etc/ssl/certs/ca-certificates.crt

并且自定义 CA 根正确存在

问题

当来自 GitLab-CI 的 运行 Gitlab-Runner 时,管道悲惨地失败告诉我:

$ git clone https://gitlab-ci-token:${CI_BUILD_TOKEN}@ServerA/foo/bar/My-Project.wiki.git


Cloning into 'My-Project.wiki'...


fatal: unable to access 'https://gitlab-ci-token:xxxxxxxxxxxxxxxxxxxx@ServerA/foo/bar/My-Project.wiki.git/': server certificate verification failed. CAfile: /etc/ssl/certs/ca-certificates.crt CRLfile: none


ERROR: Job failed: exit code 1

它无法识别 Issuer(我的自定义 CA Root),但根据 The self-signed certificates or custom Certification Authorities,第 n.1 点,它应该开箱即用:

Default: GitLab Runner reads system certificate store and verifies the GitLab server against the CA’s stored in system.

然后我尝试了第 n.3 点的解决方案,编辑

/srv/gitlab-runner/config/config.toml:

并添加:

[[runners]]
tls-ca-file = "/srv/gitlab-runner/config/certs/ca.crt"

但是还是不行。

如何让Gitlab Runner读取CA根证书?

您有两个选择:

忽略 SSL 验证

把这个放在你的 .gitlab-ci.yml 的顶部:

variables:
  GIT_SSL_NO_VERIFY: "1"

将 GitLab-Runner 指向正确的证书

official documentation 中所述,您可以使用 tls-*-file 选项来设置您的证书,例如:

[[runners]]
  ...
  tls-ca-file = "/etc/gitlab-runner/ssl/ca-bundle.crt"
  [runners.docker]
  ...

documentation 所述,"this file will be read every time when runner tries to access the GitLab server."

其他选项包括 tls-cert-file 以定义在需要时使用的证书。

根据您提供的输出,我认为证书可能没问题,但您缺少 CRL 文件:server certificate verification failed. CAfile: /etc/ssl/certs/ca-certificates.crt CRLfile: none

CRL 文件用于验证即使证书有效也未被 CA 所有者吊销。然后你应该需要:

1) 根据您的 CA 生成 CRL 文件:

openssl ca -gencrl -keyfile ca.key -cert ca.crt -out crl.pem

来源:https://blog.didierstevens.com/2013/05/08/howto-make-your-own-cert-and-revocation-list-with-openssl/

2) 指示跑步者使用它:

[[runners]]
  ...
  tls-ca-file = "/etc/gitlab-runner/ssl/ca-bundle.crt"
  crl-file = "/etc/gitlab-runner/ssl/ca.crl"

3) 当然设置GIT_SSL_NO_VERIFY会起作用,但是你会对中间人攻击更加敏感

虽然我仍然不明白为什么它不能开箱即用,我找到了哥伦布蛋

Gitlab-Runner配置:

[[runners]]
  name = "MyDockerServer-Runner"
  url = "https://MY_PRIVATE_REPO_URL_HERE/"
  token = "MY_TOKEN_HERE"
  executor = "docker"
  ...
  [runners.docker]
    image = "ubuntu:latest"

  # The trick is the following:
    volumes = ["/cache","/srv/gitlab-runner/config:/etc/gitlab-runner"]
    ...

Gitlab-ci.yml管道:

MyJob:
    image: ubuntu:latest

    script:
      - awk -v cmd='openssl x509 -noout -subject' '/BEGIN/{close(cmd)};{print | cmd}' < /etc/ssl/certs/ca-certificates.crt
      - git clone https://gitlab-ci-token:${CI_BUILD_TOKEN}@ServerA/foo/bar/My-Project.wiki.git
      - wget -O foo.png https://ServerA/foo/bar/foo.png 

    before_script:
      - apt-get update -y >/dev/null
      - apt-get install -y apt-utils dialog >/dev/null
      - apt-get install -y git >/dev/null
      - apt-get install -y wget >/dev/null

    # The trick is the following:
      - cp /etc/gitlab-runner/certs/ca.crt /usr/local/share/ca-certificates/ca.crt
      - update-ca-certificates

就是这样:

  • 挂载卷一次(根据 Docker 执行程序
  • 更新 CA 证书一次(根据 工作

一切都会按预期工作git clonewget https,等等...

一个很好的解决方法,直到 GitLab 的某人修复它或向我解释我错在哪里(做我的客人!)

不确定这是最好的方法,但至少它对我有用。您可以创建一个自定义的 gitlab runner 图像并在其中添加您的根 CA:

├── Dockerfile
└── myca.crt
# Dockerfile
FROM gitlab/gitlab-runner:latest
COPY myca.crt /usr/local/share/ca-certificates
RUN update-ca-certificates

构建它:

docker build -t custom-gitlab-runner .

然后重新运行所有命令,只记得使用这个新的图像名称。

题外话,但相关且可能有用

Docker 化的 gitlab-runner 似乎也会忽略你的 /etc/hosts 中的条目,所以如果你在自定义域上启动了 Gitlab,例如https://gitlab.local.net,当launching/registering gitlab runner:

时,你需要传递/etc/hosts的值
docker run -d --name gitlab-runner --restart always \
       --add-host="gitlab.local.net:192.168.1.100" \
       ...

如果要启动 docker:dind(docker 服务中的 docker)容器来构建 docker 图像,您还需要在 /srv/gitlab-runner/config/config.toml:

中设置这些值
[[runners]]
  url = "https://gitlab.local.net/"
  executor = "docker"
  pre_clone_script = "echo '192.168.1.100 gitlab.local.net registry.local.net' >> /etc/hosts"
  ...