在 CI 中使用外部密钥

  1. Tier: 基础版, 专业版, 旗舰版
  2. Offering: JihuLab.com, 私有化部署

密钥代表了您的 CI 作业完成工作所需的敏感信息。这些敏感信息可以是 API 令牌、数据库凭据或私钥。密钥来源于您的密钥提供者。

与 CI/CD 变量不同,密钥必须由作业明确要求,而不是总是提供给作业。阅读极狐GitLab CI/CD 流水线配置参考以获取有关语法的更多信息。

极狐GitLab 支持以下密钥管理提供者:

  1. HashiCorp Vault
  2. Azure Key Vault

极狐GitLab 选择了 HashiCorp Vault 作为第一个支持的提供者,并选择了 KV-V2 作为第一个支持的密钥引擎。

使用 ID 令牌来验证 Vault。使用 HashiCorp Vault 进行身份验证和读取密钥教程提供了有关使用 ID 令牌进行身份验证的更多详细信息。

您必须配置您的 Vault 服务器,然后才能在 CI 作业中使用 Vault 密钥

使用 HashiCorp Vault 与极狐GitLab 的流程由以下图表总结:

Flow between GitLab and HashiCorp

  1. 配置您的 Vault 和密钥。
  2. 生成您的 JWT 并将其提供给您的 CI 作业。
  3. Runner 联系 HashiCorp Vault 并使用 JWT 进行身份验证。
  4. HashiCorp Vault 验证 JWT。
  5. HashiCorp Vault 检查绑定声明并附加策略。
  6. HashiCorp Vault 返回令牌。
  7. Runner 从 HashiCorp Vault 读取密钥。

阅读 使用 HashiCorp Vault 进行身份验证和读取密钥教程以获取此功能的版本。它对所有订阅级别开放,支持向 Vault 写入和删除密钥,并支持多个密钥引擎。

您必须将以下 URL 中的 vault.example.com 替换为您的 Vault 服务器的 URL,将 gitlab.example.com 替换为您的极狐GitLab 实例的 URL。

Vault 密钥引擎#

History
    • generic 选项在 GitLab Runner 16.11 中引入。

极狐GitLab Runner 支持的 Vault 密钥引擎有:

密钥引擎secrets:engine:nameRunner 版本详情
KV 密钥引擎 - 版本 2kv-v213.4kv-v2 是极狐GitLab Runner 在未明确指定引擎类型时使用的默认引擎。
KV 密钥引擎 - 版本 1kv-v1generic13.4在极狐GitLab 15.11 中引入对 generic 关键字的支持。
AWS 密钥引擎generic16.11
Hashicorp Vault Artifactory Secrets 插件generic16.11这个密钥后端与 JFrog Artifactory 服务器(5.0.0 或更高版本)通信,并动态提供具有指定范围的访问令牌。

配置您的 Vault 服务器#

要配置您的 Vault 服务器:

  1. 确保您的 Vault 服务器运行版本为 1.2.0 或更高。

  2. 通过运行这些命令启用身份验证方法。它们为您的 Vault 服务器提供您极狐GitLab 实例的 OIDC 发现 URL,因此 Vault 可以在身份验证时获取公共签名密钥并验证 JSON Web 令牌 (JWT):

    shell
    $ vault auth enable jwt $ vault write auth/jwt/config \ oidc_discovery_url="https://gitlab.example.com" \ bound_issuer="gitlab.example.com"
  3. 在您的 Vault 服务器上配置策略,以授予或禁止对某些路径和操作的访问。此示例授予对生产环境所需密钥集的读取访问权限:

    shell
    1vault policy write myproject-production - <<EOF 2# 在 'ops/data/production/*' 路径上的只读权限 3 4path "ops/data/production/*" { 5 capabilities = [ "read" ] 6} 7EOF
  4. 在您的 Vault 服务器上配置角色,将角色限制为项目或命名空间,如本页面中的配置 Vault 服务器角色中所述。

  5. 创建以下 CI/CD 变量以提供有关您的 Vault 服务器的详细信息:

    • VAULT_SERVER_URL - 您的 Vault 服务器的 URL,例如 https://vault.example.com:8200。必填。
    • VAULT_AUTH_ROLE - 可选。在尝试进行身份验证时使用的角色。如果未指定角色,Vault 将使用配置身份验证方法时指定的默认角色。
    • VAULT_AUTH_PATH - 可选。身份验证方法挂载的路径,默认为 jwt
    • VAULT_NAMESPACE - 可选。用于读取密钥和身份验证的 Vault 企业命名空间。对于:
      • Vault,当未指定命名空间时使用 root ("/") 命名空间。
      • Vault 开源版,设置被忽略。
      • HashiCorp 云平台 (HCP) Vault,需要一个命名空间。HCP Vault 默认使用 admin 命名空间作为根命名空间。例如,VAULT_NAMESPACE=admin

在 CI 作业中使用 Vault 密钥#

  1. Tier: 专业版, 旗舰版
  2. Offering: JihuLab.com, 私有化部署

配置您的 Vault 服务器后,您可以通过使用 vault 关键字定义来使用存储在 Vault 中的密钥:

yaml
1job_using_vault: 2 id_tokens: 3 VAULT_ID_TOKEN: 4 aud: https://vault.example.com 5 secrets: 6 DATABASE_PASSWORD: 7 vault: production/db/password@ops 8 token: $VAULT_ID_TOKEN

在此示例中:

  • production/db 是密钥的路径。
  • password 是字段。
  • ops 是密钥引擎挂载的路径。
  • production/db/password@ops 转换为路径 ops/data/production/db
  • 使用 $VAULT_ID_TOKEN 进行身份验证。

在极狐GitLab 从 Vault 获取密钥后,该值会保存在一个临时文件中。此文件的路径存储在一个名为 DATABASE_PASSWORD 的 CI/CD 变量中,类似于类型为 file 的变量

要覆盖默认行为,请显式设置 file 选项:

yaml
1secrets: 2 id_tokens: 3 VAULT_ID_TOKEN: 4 aud: https://vault.example.com 5 DATABASE_PASSWORD: 6 vault: production/db/password@ops 7 file: false 8 token: $VAULT_ID_TOKEN

在此示例中,密钥值直接放入 DATABASE_PASSWORD 变量中,而不是指向保存它的文件。

使用不同的密钥引擎#

默认情况下使用 kv-v2 密钥引擎。要使用不同的引擎,请在配置中在 vault 下添加一个 engine 部分。

例如,设置 Artifactory 的密钥引擎和路径:

yaml
1job_using_vault: 2 id_tokens: 3 VAULT_ID_TOKEN: 4 aud: https://vault.example.com 5 secrets: 6 JFROG_TOKEN: 7 vault: 8 engine: 9 name: generic 10 path: artifactory 11 path: production/jfrog 12 field: access_token 13 file: false

在此示例中,密钥值从 artifactory/production/jfrog 中获取,字段为 access_tokengeneric 密钥引擎可用于 kv-v1、AWS、Artifactory 和其他类似的 Vault 密钥引擎

配置 Vault 服务器角色#

当 CI 作业尝试进行身份验证时,它会指定一个角色。您可以使用角色将不同的策略组合在一起。如果身份验证成功,这些策略将附加到生成的 Vault 令牌上。

绑定声明是与 JWT 声明匹配的预定义值。通过绑定声明,您可以将访问限制为特定的极狐GitLab 用户、特定的项目,甚至是针对特定 Git 引用运行的作业。您可以拥有任意多的绑定声明,但它们必须全部匹配才能成功进行身份验证。

结合绑定声明与极狐GitLab 的功能,如用户角色受保护分支,您可以根据您的具体用例量身定制这些规则。在此示例中,仅允许针对生产发布使用的模式匹配名称运行的受保护标签的作业进行身份验证:

shell
1$ vault write auth/jwt/role/myproject-production - <<EOF 2{ 3 "role_type": "jwt", 4 "policies": ["myproject-production"], 5 "token_explicit_max_ttl": 60, 6 "user_claim": "user_email", 7 "bound_audiences": "https://vault.example.com", 8 "bound_claims_type": "glob", 9 "bound_claims": { 10 "project_id": "42", 11 "ref_protected": "true", 12 "ref_type": "tag", 13 "ref": "auto-deploy-*" 14 } 15} 16EOF

始终通过使用提供的声明之一(如 project_idnamespace_id)将您的角色限制在项目或命名空间上。如果没有这些限制,任何由此极狐GitLab 实例生成的 JWT 都可能被允许使用此角色进行身份验证。

有关 ID 令牌 JWT 声明的完整列表,请阅读使用 HashiCorp Vault 进行身份验证和读取密钥教程的工作原理部分。

您还可以为生成的 Vault 令牌指定一些属性,例如生存时间、IP 地址范围和使用次数。完整的选项列表可在 Vault 关于为 JSON Web 令牌方法创建角色的文档中找到。

故障排除#

自签名证书错误:certificate signed by unknown authority#

当 Vault 服务器使用自签名证书时,您会在作业日志中看到以下错误:

plaintext
ERROR: Job failed (system failure): resolving secrets: initializing Vault service: preparing authenticated client: checking Vault server health: Get https://vault.example.com:8000/v1/sys/health?drsecondarycode=299&performancestandbycode=299&sealedcode=299&standbycode=299&uninitcode=299: x509: certificate signed by unknown authority

您有两种选择来解决此错误:

  • 将自签名证书添加到极狐GitLab Runner 服务器的 CA 存储中。如果您使用 Helm chart 部署极狐GitLab Runner,您必须创建自己的极狐GitLab Runner 镜像。
  • 使用 VAULT_CACERT 环境变量配置极狐GitLab Runner 以信任证书:
    • 如果您使用 systemd 来管理极狐GitLab Runner,请参阅如何为极狐GitLab Runner 添加环境变量
    • 如果您使用 Helm chart 部署极狐GitLab Runner:
      1. 为访问极狐GitLab 提供自定义证书,并确保添加 Vault 服务器的证书,而不是极狐GitLab 的证书。如果您的极狐GitLab 实例也使用自签名证书,您应该能够在同一个 Secret 中添加这两个证书。

      2. 在您的 values.yaml 文件中添加以下行:

        yaml
        1## 将 <SECRET_NAME> 和 <VAULT_CERTIFICATE> 都替换为您用来创建 secret 的实际值 2 3certsSecretName: <SECRET_NAME> 4 5envVars: 6 - name: VAULT_CACERT 7 value: "/home/gitlab-runner/.gitlab-runner/certs/<VAULT_CERTIFICATE>"

如果您在本地开发模式下使用 极狐GitLab 开发工具包 (GDK) 运行 vault 服务器,您可能也会遇到此错误。您可以手动要求系统信任 Vault 服务器的自签名证书。

resolving secrets: secret not found: MY_SECRET 错误#

当极狐GitLab 无法在 vault 中找到密钥时,您可能会收到此错误:

plaintext
ERROR: Job failed (system failure): resolving secrets: secret not found: MY_SECRET

检查 vault 值是否在 CI/CD 作业中正确配置

您可以使用 Vault CLI 的 kv 命令来检查密钥是否可检索,以帮助确定 CI/CD 配置中 vault 值的语法。例如,检索密钥:

shell
$ vault kv get -field=password -namespace=admin -mount=ops "production/db" this-is-a-password

实践教程#

可以查看极狐GitLab 官网资源中心中的博客文章