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

Posted

技术标签:

【中文标题】如何让 Docker 中的 GitLab Runner 看到自定义 CA 根证书【英文标题】:How to make GitLab Runner in Docker see a custom CA Root certificate 【发布时间】:2019-04-09 02:23:44 【问题描述】:

我已经安装并配置好了:

    ServerA 上运行在 HTTPS 上的本地 GitLab OmnibusServerB 中作为 Docker 服务安装的本地 GitLab-Runner

ServerA 证书由自定义 CA Root 生成

配置

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

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

ServerB 上安装了 Runner,如 Run GitLab Runner in a container - Docker image installation and configuration 中所述:

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"

此命令给出以下输出:

正在更新 CA 证书... 运行平台arch=amd64 os=linux pid=5 revision=cf91d5e1 version=11.4.2 在系统模式下运行。

正在注册跑步者...成功跑步者=8UtcUXCY Runner注册成功。随意启动它,但如果它已经在运行,配置应该会自动重新加载!

我检查过

$ 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

克隆到“My-Project.wiki”...

致命:无法访问“https://gitlab-ci-token:xxxxxxxxxxxxxxxxxxxx@ServerA/foo/bar/My-Project.wiki.git/”:服务器证书验证失败。 CAfile:/etc/ssl/certs/ca-certificates.crt CRLfile:无

错误:作业失败:退出代码 1

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

默认值:GitLab Runner 读取系统证书存储并根据系统中存储的 CA 验证 GitLab 服务器

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

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

并添加:

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

但还是不行。

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

【问题讨论】:

【参考方案1】:

不确定这是不是最好的方法,但至少它对我有用。您可以创建一个自定义的 gitlab 运行器映像并在其中添加您的根 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 .

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

离题,但相关且可能有用

Dockerized gitlab-runner 似乎也忽略了/etc/hosts 中的条目,所以如果你在自定义域上启动了 Gitlab,例如https://gitlab.local.net,您需要在启动/注册 gitlab runner 时传递来自 /etc/hosts 的值:

docker run -d --name gitlab-runner --restart always \
       --add-host="gitlab.local.net:192.168.1.100" \
       ...

如果你想启动docker:dind(docker in docker service)容器来构建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"
  ...

【讨论】:

感谢您的宝贵回答!我会尽快尝试的【参考方案2】:

你有两个选择:

忽略 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 所说,“每次运行者尝试访问 GitLab 服务器时都会读取此文件。”

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

【讨论】:

@AndreaLigios 检查 gitlab-runner 进程的日志输出;也许您可以合并有关您的设置的更多信息 - 您选择了几种安装跑步者的方法中的哪一种,等等。 你的意思是/srv/gitlab-runner/config/certs 我猜。无论哪种方式,它都不起作用……这件事让我发疯。我可以清楚地看到作为 Docker 服务安装的 Gitlab-Runner 正在接受 CA 根并更新其证书;记录它并检查,它就在那里。问题是 GitLab-CI 生成的 Runner 不是。 My configuration is the default one for a containerized GitLab-Runner,如果我让它从 gitlab-ci 打印 CA,则自定义 CA 不存在:/ 我重新编辑了问题,添加了所有详细信息和文档链接。您的答案中的 tls-ca-file 应该在 [[runners]] 部分,而不是在 [runners.docker] 部分,但它的工作方式不同:( 我怀疑文档中缺少一些东西,需要在 config.toml 中进行一些调整(例如 tls_verify 应该有什么值,什么 priviledge_mode 等等),单独的 tls-ca-file 恕我直言还不够。并且没有提到根据该页面,一切都应该在不做任何事情的情况下工作:/ 即使您的解决方案不起作用,我也已授予您的答案,因为您已经花了一些时间,而且我讨厌浪费东西。享受吧。【参考方案3】:

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

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 有人修复它或向我解释我错在哪里(做我的客人!)

【讨论】:

我已经按照您所说的“诀窍如下”的部分进行了操作,现在它似乎可以正常工作了! :) 我只是想知道,真的有必要指定卷吗?它的目的是什么?那部分实际上是做什么的? 您正在使用 Docker Runner 运行管道,该管道在 Docker 容器中运行。要复制/usr/local/share/ca-certificates 下的证书文件,您需要使证书文件在容器中可用。为此,您将本地路径(在我的情况下为/srv/gitlab-runner/config)映射到容器路径(/etc/gitlab-runner),这样当您在容器内执行cp /etc/gitlab-runner/certs/ca.crt ... 时,您就可以在后台从主机路径/srv/gitlab-runner/config/certs。如果不安装卷,cp 将找不到任何要复制的内容 @NewteqDeveloper,这是我写的一篇小文章,它以一种简单的方式涵盖了这个 Docker 概念:baeldung.com/docker-compose。 @AndreaLigios 不确定为什么这可以解决您的问题,看起来 Runner 图像已经在 init script 中做同样的事情。唯一的区别似乎是您没有将--fresh 标志传递给update-ca-certificates。有什么想法吗? 我应该指定它是 Runner Helper 图像正在执行此操作,而您正在做的是在 Runner 容器(而不是 Helper 容器)中运行相同的逻辑。通常,它是负责执行常见操作(例如 Git 提取等)的辅助映像。所以,是的,如果您需要在构建脚本中执行相同类型的操作(或 wget),那么您需要挂载/安装您的自定义 CA。【参考方案4】:

根据您提供的输出,我认为证书可能没问题,但您缺少 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 会起作用,但你会对中间人攻击更敏感

【讨论】:

感谢您的回答,我会尽快尝试(尽管我不相信 CRL 是强制性的)。正如在另一个答案according to the docs 中所说,tls-ca-file 应该留在[[runners]] 而不是[runners.docker] :) 另外,为什么要输出 DER 格式?这表示证书不支持 DER,所以我想 CRL 也不支持:docs.gitlab.com/runner/configuration/tls-self-signed.html @AndreaLigios 我在上面剪切并粘贴了您的配置。如果 runners.docker 部分不是放置 tls-ca 文件的正确位置,请随时编辑问题以避免后续错误:-) 我相应地编辑了答案 @AndreaLigios :您对 DER 格式的看法是正确的。我相应地编辑了答案 您复制粘贴了另一个答案,而不是我的问题。根据文档,它应该是[[runners]] ... tls-ca-file = "" ... [docker.runners]。看看吧:)

以上是关于如何让 Docker 中的 GitLab Runner 看到自定义 CA 根证书的主要内容,如果未能解决你的问题,请参考以下文章

kubernetes/docker 上的 gitlab:管道失败:清理 configmap 时出错:资源名称可能不为空

如何使用 Docker 部署 GitLab

如何在 gitlab-runner 中发布端口?

如何将存储库中的文件复制到用于作业的 Docker 容器中,在 gitlab-ci.yml

让 git 用户的 sshd 登录转发到(GitLab)Docker 容器

如何在gitlab.com中获得docker注册表用户名和密码?