Help us learn about your current experience with the documentation. Take the survey.

在 CI 中使用外部密钥

  • Tier: Free, Premium, Ultimate
  • Offering: GitLab.com, GitLab Self-Managed, GitLab Dedicated

密钥代表 CI 作业完成工作所需的敏感信息。这些敏感信息可以是 API 令牌、数据库凭据或私钥等。密钥从您的密钥提供程序中获取。

与始终传递给作业的 CI/CD 变量不同,密钥必须由作业明确要求。有关语法的更多信息,请阅读 GitLab CI/CD 管道配置参考

GitLab 支持以下密钥管理提供程序:

  1. HashiCorp Vault
  2. Google Cloud Secret Manager
  3. Azure Key Vault

GitLab 选择了 HashiCorp Vault 作为首个支持的提供程序,以及 KV-V2 作为首个支持的密钥引擎。

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

在 CI 作业中使用 Vault 密钥 之前,您必须 配置您的 Vault 服务器

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

GitLab 和 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 写入密钥和从 Vault 删除密钥,并支持多个密钥引擎。

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

Vault 密钥引擎

GitLab Runner 支持的 Vault 密钥引擎,使用 secrets:engine:name 关键字:

密钥引擎 secrets:engine:name Runner 版本 详情
KV 密钥引擎 - 版本 2 kv-v2 13.4 当未明确指定引擎类型时,kv-v2 是 GitLab Runner 使用的默认引擎。
KV 密钥引擎 - 版本 1 kv-v1generic 13.4 generic 关键字支持在 GitLab 15.11 中 引入
AWS 密钥引擎 generic 16.11
HashiCorp Vault Artifactory 密钥插件 generic 16.11 此密钥后端与 JFrog Artifactory 服务器(5.0.0 或更高版本)通信,并动态配置具有指定范围的访问令牌。

配置您的 Vault 服务器

要配置您的 Vault 服务器:

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

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

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

    vault policy write myproject-production - <<EOF
    # 对 'ops/data/production/*' 路径的只读权限
    
    path "ops/data/production/*" {
      capabilities = [ "read" ]
    }
    EOF
  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 Cloud Platform (HCP) Vault,需要命名空间。 HCP Vault 默认使用 admin 命名空间作为根命名空间。 例如,VAULT_NAMESPACE=admin

    在用户界面中提供这些值的支持正在 此问题中跟踪

在 CI 作业中使用 Vault 密钥

  • Tier: Premium, Ultimate
  • Offering: GitLab.com, GitLab Self-Managed, GitLab Dedicated

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

job_using_vault:
  id_tokens:
    VAULT_ID_TOKEN:
      aud: https://vault.example.com
  secrets:
    DATABASE_PASSWORD:
      vault: production/db/password@ops
      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 选项:

secrets:
  id_tokens:
    VAULT_ID_TOKEN:
      aud: https://vault.example.com
  DATABASE_PASSWORD:
    vault: production/db/password@ops
    file: false
    token: $VAULT_ID_TOKEN

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

使用不同的密钥引擎

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

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

job_using_vault:
  id_tokens:
    VAULT_ID_TOKEN:
      aud: https://vault.example.com
  secrets:
    JFROG_TOKEN:
      vault:
        engine:
          name: generic
          path: artifactory
        path: production/jfrog
        field: access_token
      file: false

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

配置 Vault 服务器角色

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

有界声明 是与 JWT 声明匹配的预定义值。通过有界声明,您可以限制对特定 GitLab 用户、特定项目甚至为特定 Git 引用运行的作业的访问。您可以根据需要拥有任意数量的有界声明,但它们都必须匹配才能成功进行身份验证。

将有界声明与 用户角色受保护分支 等 GitLab 功能结合使用,您可以调整这些规则以适应您的特定用例。在此示例中,仅允许为与生产发布使用的模式匹配的名称的受保护标签运行的作业进行身份验证:

$ vault write auth/jwt/role/myproject-production - <<EOF
{
  "role_type": "jwt",
  "policies": ["myproject-production"],
  "token_explicit_max_ttl": 60,
  "user_claim": "user_email",
  "bound_audiences": "https://vault.example.com",
  "bound_claims_type": "glob",
  "bound_claims": {
    "project_id": "42",
    "ref_protected": "true",
    "ref_type": "tag",
    "ref": "auto-deploy-*"
  }
}
EOF

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

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

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

故障排除

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

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

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 文件中添加以下行:

        ## 替换 <SECRET_NAME> 和 <VAULT_CERTIFICATE>
        ## 为您创建密钥时使用的实际值
        
        certsSecretName: <SECRET_NAME>
        
        envVars:
          - name: VAULT_CACERT
            value: "/home/gitlab-runner/.gitlab-runner/certs/<VAULT_CERTIFICATE>"

如果您使用 GitLab Development Kit (GDK) 在本地以开发模式运行 vault 服务器,您也可能会遇到此错误。您可以手动要求系统信任 Vault 服务器的自签名证书。 此 示例教程 说明了如何在 macOS 上执行此操作。

resolving secrets: secret not found: MY_SECRET 错误

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

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

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

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

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