自签名证书或自定义证书颁发机构

引入于极狐GitLab Runner 0.7.0。

极狐GitLab Runner 提供两种配置用于验证 TLS 对端的证书的选项。

  • 对于连接到极狐GitLab 服务器:可以按照极狐GitLab 服务器自签名证书的支持选项部分中介绍的内容指定证书文件。

    解决了注册 Runner 时的 x509: certificate signed by unknown authority 问题。

    对于现存 Runner,当检查作业时,可以在 Runner 日志中看到相同的错误:

      Couldn't execute POST against https://hostname.tld/api/v4/jobs/request:
      Post https://hostname.tld/api/v4/jobs/request: x509: certificate signed by unknown authority
    
  • 适用如用户脚本、连接缓存服务器或外部 Git LFS 存储等其他场景的一个更加通用的方法:可以按照 Docker 和 Kubernetes 执行器的信任 TLS 证书部分中介绍的内容指定证书并在容器上安装。

    关于缺少证书的 Git LFS 操作的作业日志错误示例:

      LFS: Get https://object.hostname.tld/lfs-dev/c8/95/a34909dce385b85cee1a943788044859d685e66c002dbf7b28e10abeef20?X-Amz-Expires=600&X-Amz-Date=20201006T043010Z&X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=svcgitlabstoragedev%2F20201006%2Fus-east-1%2Fs3%2Faws4_request&X-Amz-SignedHeaders=host&X-Amz-Signature=012211eb0ff0e374086e8c2d37556f2d8ca4cc948763e90896f8f5774a100b55: x509: certificate signed by unknown authority
    

极狐GitLab 服务器自签名证书的支持选项

本部分介绍仅极狐GitLab 服务器需要自定义证书的情况。 如果其他主机(例如没有启用代理下载的对象存储服务)也需要自定义证书颁发机构(CA),请参见下一部分

极狐GitLab Runner 支持下列选项:

  • 默认 - 读取系统证书:极狐GitLab Runner 读取系统证书存储并依照存储在系统中的 CA 验证极狐GitLab 服务器。需要注意,Windows 不支持 从系统证书存储读取。

  • 指定自定义证书文件:极狐GitLab Runner 在注册gitlab-runner register --tls-ca-file=/path)中展示 tls-ca-file 选项, 并且它在 [[runners]] 部分的 config.toml 中。 允许您指定自定义证书文件。 每次 Runner 试图访问极狐GitLab 服务器时,都会读取这个文件。 如果您使用的是极狐GitLab Runner Helm chart,您需要按照为访问极狐GitLab 提供自定义证书中的描述配置证书。

  • 读取 PEM 证书:极狐GitLab Runner 从预定义的文件中读取证书(不支持 DER 格式):

    • 当极狐GitLab Runner 以 root 用户身份执行时,是 *nix 系统上的 /etc/gitlab-runner/certs/gitlab.example.com.crt

      如果您的服务器地址是 https://gitlab.example.com:8443/,那么在 /etc/gitlab-runner/certs/gitlab.example.com.crt 中创建证书文件。

      您可以使用 openssl 客户端将极狐GitLab 实例的证书下载到 /etc/gitlab-runner/certs

      openssl s_client -showcerts -connect gitlab.example.com:443 -servername gitlab.example.com < /dev/null 2>/dev/null | openssl x509 -outform PEM > /etc/gitlab-runner/certs/gitlab.example.com.crt
      

      您可以使用 openssl 这样的工具验证已正确安装了文件。例如:

      echo | openssl s_client -CAfile /etc/gitlab-runner/certs/gitlab.example.com.crt -connect gitlab.example.com:443 -servername gitlab.example.com
      
    • 当极狐GitLab Runner 以非 root 用户身份执行时,是 *nix 系统上的 ~/.gitlab-runner/certs/gitlab.example.com.crt
    • 其他系统上的 ./certs/gitlab.example.com.crt。如果极狐GitLab Runner 作为 Windows 服务运行,这无法生效,您需要指定自定义证书文件。

Notes:

  • 如果您的极狐GitLab 服务器证书是由 CA 签署的,那么使用 CA 证书 (不是您的极狐GitLab 服务器签名的证书)。您或许也需要向链添加中级证书。 例如,如果您有初级、中级和根证书, 您可以把他们放入同一个文件中。

      -----BEGIN CERTIFICATE-----
      (Your primary SSL certificate: your_domain_name.crt)
      -----END CERTIFICATE-----
      -----BEGIN CERTIFICATE-----
      (Your intermediate certificate)
      -----END CERTIFICATE-----
      -----BEGIN CERTIFICATE-----
      (Your root certificate)
      -----END CERTIFICATE-----
    
  • 如果您为现存 Runner 更新证书,重启它
  • 如果您已经通过 HTTP 配置了 Runner,请将您的实例路径更新为 config.toml 中极狐GitLab 实例的新 HTTPS URL。
  • 一个临时且不安全的解决方法是跳过证书验证,在 .gitlab-ci.yml 文件中的 variables: 部分,将 CI 变量 GIT_SSL_NO_VERIFY 设置为 true

Git 克隆

Runner 使用 CI_SERVER_TLS_CA_FILE 注入缺失的证书以构建 CA 链。 这允许 git clone 和产物与不使用公开信任的证书的服务器一同工作。

这种方法很安全,但让 Runner 成为了单点信任。

Docker 和 Kubernetes 执行器的信任 TLS 证书

当我们想在容器上注册证书时,需要考虑两个上下文:

  • 用户镜像,用于运行用户脚本。 在这种情况下,用户必须掌握如何安装证书,因为它高度依赖镜像本身,并且 Runner 不知道如何在每个可能的场景中安装证书。

  • Runner Helper 镜像用于处理 Git、产物和缓存操作。在这种情况下,用户仅需要在特定位置使证书文件可用(例如,/etc/gitlab-runner/certs/ca.crt)。Docker 容器会自动为用户安装。

信任用户脚本证书

如果您的构建脚本需要与对端通过 TLS 通信,并且需要依赖自签名证书或自定义 CA,您需要在构建作业中安装证书,因为运行用户脚本的 Docker 容器默认没有安装证书文件。这可能需要使用自定义缓存主机,进行次要 git clone,或通过类似 wget 的工具获取文件。

安装证书步骤如下:

  1. 将必要文件映射为 Docker 卷,这样运行脚本的 Docker 容器就可以看见它们了。 您可以通过将卷添加到 config.toml 文件的 [runners.docker] 的密钥中来实现。 例如:

    • Linux:

        [[runners]]
         name = "docker"
         url = "https://example.com/"
         token = "TOKEN"
         executor = "docker"
      
         [runners.docker]
           image = "ubuntu:latest"
      
           # Add path to your ca.crt file in the volumes list
           volumes = ["/cache", "/path/to-ca-cert-dir/ca.crt:/etc/gitlab-runner/certs/ca.crt:ro"]
      
  2. 仅 Linux:使用 pre_build_script 中映射的文件(例如 ca.crt),这些 pre_build_script

    1. 将其复制到 Docker 容器中的 /usr/local/share/ca-certificates/ca.crt
    2. 通过运行 update-ca-certificates --fresh 安装它。例如(命令根据您使用的分布而有所不同):

      • 在 Ubuntu 上:

          [[runners]]
            name = "docker"
            url = "https://example.com/"
            token = "TOKEN"
            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
            """
        
      • 在 Alpine 上:

          [[runners]]
            name = "docker"
            url = "https://example.com/"
            token = "TOKEN"
            executor = "docker"
        
            # Copy and install CA certificate before each job
            pre_build_script = """
            apk update >/dev/null
            apk add ca-certificates > /dev/null
            rm -rf /var/cache/apk/*
        
            cp /etc/gitlab-runner/certs/ca.crt /usr/local/share/ca-certificates/ca.crt
            update-ca-certificates --fresh > /dev/null
            """
        

如果您仅需要可以使用的极狐GitLab 服务器 CA cert,您可以从存储在 CI_SERVER_TLS_CA_FILE 变量的文件对其进行检索。

curl --cacert "${CI_SERVER_TLS_CA_FILE}"  ${URL} -o ${FILE}

信任其他 CI/CD 阶段的证书

引入于极狐GitLab 13.3。

您可以在 Linux 或 Windows 上将证书文件分别映射到 /etc/gitlab-runner/certs/ca.crtC:\GitLab-Runner\certs\ca.crt。 Runner Helper 镜像在开始阶段安装用户定义的 ca.crt 文件, 并在进行克隆或上传产物等操作时使用它。

Docker

  • Linux:

      [[runners]]
       name = "docker"
       url = "https://example.com/"
       token = "TOKEN"
       executor = "docker"
    
       [runners.docker]
         image = "ubuntu:latest"
    
         # Add path to your ca.crt file in the volumes list
         volumes = ["/cache", "/path/to-ca-cert-dir/ca.crt:/etc/gitlab-runner/certs/ca.crt:ro"]
    
  • Windows:

      [[runners]]
       name = "docker"
       url = "https://example.com/"
       token = "TOKEN"
       executor = "docker"
    
       [runners.docker]
         image = "mcr.microsoft.com/windows/servercore:21H2"
    
         # Add directory holding your ca.crt file in the volumes list
         volumes = ["c:\\cache", "c:\\path\\to-ca-cert-dir:C:\\GitLab-Runner\\certs:ro"]
    

Kubernetes

为 Kubernetes 中运行的作业提供证书文件:

  1. 将证书作为 Kubernetes secret 存储在您的命名空间中:

    kubectl create secret generic <SECRET_NAME> --namespace <NAMESPACE> --from-file=<CERT_FILE>
    
  2. 将 secret 作为卷挂载在您的 Runner 中,用适当的值替换 <SECRET_NAME><LOCATION>

    gitlab-runner:
      runners:
       config: |
         [[runners]]
           [runners.kubernetes]
             namespace = "{{.Release.Namespace}}"
             image = "ubuntu:latest"
           [[runners.kubernetes.volumes.secret]]
               name = "<SECRET_NAME>"
               mount_path = "<LOCATION>"
    

    mount_path 是容器中存储证书的目录。 如果您将 /etc/gitlab-runner/certs/ 用作 mount_path 并且将 ca.crt 用作您的证书文件,您的证书将在您容器中的 /etc/gitlab-runner/certs/ca.crt 中可用。

  3. 作为作业的一部分,将映射的证书文件安装到系统证书存储区。 例如,在 Ubuntu 容器中:

    script:
      - cp /etc/gitlab-runner/certs/ca.crt /usr/local/share/ca-certificates/
      - update-ca-certificates
    

由于 Kubernetes 执行器在处理 Helper 镜像的 ENTRYPOINT 时存在的问题,映射的证书文件不会自动安装到系统证书存储。

故障排查

请参考通用的 SSL 故障排查文档。

此外,您可以使用 tlsctl 工具从 Runner 端调试极狐GitLab 证书。

当尝试从私有镜像仓库拉取执行器镜像时报错 x509: certificate signed by unknown authority

当 runner 被调度到的 Docker 主机或 Kubernetes 节点不信任私有镜像仓库使用的证书时,就会出现此错误。为了解决此错误,请将相关的根证书颁发机构或证书链添加到系统的信任存储中,并重新启动容器服务。

如果您使用的是 Ubuntu 或 Alpine,请运行以下命令:

cp ca.crt /usr/local/share/ca-certificates/ca.crt
update-ca-certificates
systemctl restart docker.service

如果您使用的是其他操作系统,请阅读操作系统的文档以查找安装受信任证书的适当命令。

取决于您的极狐GitLab Runner 版本和 Docker 主机环境,您还可能需要禁用 FF_RESOLVE_FULL_TLS_CHAIN 功能标志。

在作业中出现 apt-get: not found 错误

在 runner 执行时,pre_build_script 命令在每个作业之前执行。如果您添加特定于某些发行版的命令,例如,当您为用户脚本安装证书时,使用 apkapt-get,则您的 CI 作业可能会失败,如果它们使用基于不同发行版的镜像。

例如,如果您的某些 CI 作业基于 Ubuntu 镜像而运行,而有些基于 Alpine 镜像而运行,并且您添加了 Ubuntu 命令,那么在 Alpine 基础镜像的作业中就会出现 apt-get: not found 错误。要解决此问题,您可以:

  • pre_build_script 编写为与发行版无关。
  • 使用标签来确保 runner 只获取与镜像兼容的作业。