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

教程:更新 HashiCorp Vault 配置以使用 ID Tokens

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

从 Vault 1.17 开始,当 JWT 包含 aud 声明时,JWT 身份验证登录要求角色上有绑定受众aud 声明可以是单个字符串或字符串列表。

本教程演示如何将您现有的 CI/CD 密钥配置转换为使用 ID Tokens

CI_JOB_JWT 变量已被弃用,但更新到 ID 令牌需要一些重要的配置更改才能与 Vault 协同工作。如果您的工作数量较多,一次性转换所有内容是一项艰巨的任务。

没有一种标准方法可以迁移到 ID tokens,因此本教程包含两种转换现有 CI/CD 密钥的方法。请选择最适合您用例的方法:

  1. 更新您的 Vault 配置:
  2. 更新您的 CI/CD Jobs

前置条件

本教程假设您熟悉 GitLab CI/CD 和 Vault。

要跟随本教程,您必须具备:

  • 运行 GitLab 16.0 或更高版本的实例,或使用 GitLab.com。
  • 您已经在使用的 Vault 服务器。
  • 使用 CI_JOB_JWT 从 Vault 获取密钥的 CI/CD jobs。

在以下示例中,请替换:

  • vault.example.com 为您的 Vault 服务器 URL。
  • gitlab.example.com 为您的 GitLab 实例 URL。
  • jwtjwt_v2 为您的身份验证方法名称。

方法 A:将 JWT 角色迁移到新的 Vault 身份验证方法

此方法并行创建第二个 JWT 身份验证方法,与当前正在使用的方法并存。之后,所有用于 GitLab 集成的 Vault 角色都将在新的身份验证方法中重新创建。

在 Vault 中创建第二个 JWT 身份验证路径

作为从 CI_JOB_JWT 过渡到 ID 令牌的一部分,您必须更新 Vault 中的 bound_issuer 以包含 https://

$ vault write auth/jwt/config \
    oidc_discovery_url="https://gitlab.example.com" \
    bound_issuer="https://gitlab.example.com"

进行此更改后,使用 CI_JOB_JWT 的 jobs 将开始失败。

您可以在 Vault 中创建多个身份验证路径,这使您能够按项目和 job 逐步过渡到 ID 令牌,而不会造成中断。

  1. 配置名称为 jwt_v2 的新身份验证路径,运行:

    vault auth enable -path jwt_v2 jwt

    您可以选择不同的名称,但其余示例假设您使用的是 jwt_v2,因此请根据需要更新示例。

  2. 为您的实例配置新的身份验证路径:

    $ vault write auth/jwt_v2/config \
        oidc_discovery_url="https://gitlab.example.com" \
        bound_issuer="https://gitlab.example.com"

重新创建角色以使用新的身份验证路径

角色绑定到特定的身份验证路径,因此您需要为每个 job 添加新角色。 如果 JWT 包含受众,则角色的 bound_audiences 参数是必需的,并且必须匹配 JWT 至少一个关联的 aud 声明。

  1. 重新创建用于暂存的名为 myproject-staging 的角色:

    $ vault write auth/jwt_v2/role/myproject-staging - <<EOF
    {
      "role_type": "jwt",
      "policies": ["myproject-staging"],
      "token_explicit_max_ttl": 60,
      "user_claim": "user_email",
      "bound_audiences": ["https://vault.example.com"],
      "bound_claims": {
        "project_id": "22",
        "ref": "master",
        "ref_type": "branch"
      }
    }
    EOF
  2. 重新创建用于生产的名为 myproject-production 的角色:

    $ vault write auth/jwt_v2/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": "22",
        "ref_protected": "true",
        "ref_type": "branch",
        "ref": "auto-deploy-*"
      }
    }
    EOF

您只需要在 vault 命令中将 jwt 更新为 jwt_v2,不要更改角色内的 role_type

方法 B:将 iss 声明迁移到角色中用于迁移窗口

此方法不需要 Vault 管理员创建第二个 JWT 身份验证方法并重新创建所有与 GitLab 相关的角色。

为每个角色添加 bound_issuers 声明映射

Vault 不允许在 JWT 身份验证方法级别上有多个 iss 声明,因为该级别的 bound_issuer 指令只接受单个值。但是,可以通过使用 bound_claims 映射配置指令在角色级别配置多个声明。

使用此方法,您可以为 Vault 提供多个 iss 声明验证选项。这支持 id_tokens 带有的 https:// 前缀的 GitLab 实例主机名声明,以及旧的非前缀声明。

要将 bound_claims 配置添加到所需角色,请运行:

$ vault write auth/jwt/role/myproject-staging - <<EOF
{
  "role_type": "jwt",
  "policies": ["myproject-staging"],
  "token_explicit_max_ttl": 60,
  "user_claim": "user_email",
  "bound_audiences": ["https://vault.example.com"],
  "bound_claims": {
    "iss": [
      "https://gitlab.example.com",
      "gitlab.example.com"
    ],
    "project_id": "22",
    "ref": "master",
    "ref_type": "branch"
  }
}
EOF

除了 bound_claims 部分外,您不需要更改任何现有角色配置。 请确保添加如上所示的 iss 配置,以确保 Vault 接受此角色的前缀和非前缀 iss 声明。

在进行下一步之前,您必须将此更改应用于所有用于 GitLab 集成的 JWT 角色。

如果需要,在所有项目都已迁移并且您不再需要 CI_JOB_JWT 和 ID 令牌的并行支持后,您可以将 iss 声明验证从身份验证方法迁移回角色。

从身份验证方法中移除 bound_issuers 声明

在所有角色都已使用 bound_claims.iss 声明更新后,您可以移除此验证的身份验证方法级别配置:

$ vault write auth/jwt/config \
    oidc_discovery_url="https://gitlab.example.com" \
    bound_issuer=""

bound_issuer 指令设置为空字符串会移除身份验证方法级别的发行者验证。 但是,由于我们将此验证移到了角色级别,此配置仍然安全。

更新您的 CI/CD Jobs

Vault 有两种不同的 KV Secrets Engines,您使用的版本会影响您在 CI/CD 中定义密钥的方式。

请查看 HashiCorp 支持门户上的 Which Version is my Vault KV Mount? 文章,以检查您的 Vault 服务器。

此外,如有需要,您可以查看 CI/CD 文档:

以下示例展示如何获取写入到 secret/myproject/staging/dbpassword 字段的暂存数据库密码。

VAULT_AUTH_PATH 变量的值取决于您使用的迁移方法:

  • 方法 A(将 JWT 角色迁移到新的 Vault 身份验证方法):使用 jwt_v2
  • 方法 B(将 iss 声明迁移到角色中用于迁移窗口):使用 jwt

KV Secrets Engine v1

secrets:vault 关键字默认使用 KV Mount 的 v2 版本,因此您需要显式配置 job 以使用 v1 引擎:

job:
  variables:
    VAULT_SERVER_URL: https://vault.example.com
    VAULT_AUTH_PATH: jwt_v2  # 如果使用方法 B,则为 "jwt"
    VAULT_AUTH_ROLE: myproject-staging
  id_tokens:
    VAULT_ID_TOKEN:
      aud: https://vault.example.com
  secrets:
    PASSWORD:
      vault:
        engine:
          name: kv-v1
          path: secret
        field: password
        path: myproject/staging/db
      file: false

如果需要,VAULT_SERVER_URLVAULT_AUTH_PATH 都可以 定义为项目或组 CI/CD 变量

我们使用 secrets:file:false 是因为 ID 令牌默认将密钥放在文件中,但我们需要它作为常规变量工作以匹配旧的行为。

KV Secrets Engine v2

对于 v2 引擎,您可以使用两种格式。

长格式:

job:
  variables:
    VAULT_SERVER_URL: https://vault.example.com
    VAULT_AUTH_PATH: jwt_v2  # 如果使用方法 B,则为 "jwt"
    VAULT_AUTH_ROLE: myproject-staging
  id_tokens:
    VAULT_ID_TOKEN:
      aud: https://vault.example.com
  secrets:
    PASSWORD:
      vault:
        engine:
          name: kv-v2
          path: secret
        field: password
        path: myproject/staging/db
      file: false

这与 v1 引擎的示例相同,但 secrets:vault:engine:name: 设置为 kv-v2 以匹配引擎。

您也可以使用短格式:

job:
  variables:
    VAULT_SERVER_URL: https://vault.example.com
    VAULT_AUTH_PATH: jwt_v2  # 如果使用方法 B,则为 "jwt"
    VAULT_AUTH_ROLE: myproject-staging
  id_tokens:
    VAULT_ID_TOKEN:
      aud: https://vault.example.com
  secrets:
      PASSWORD:
        vault: myproject/staging/db/password@secret
        file: false

提交更新的 CI/CD 配置后,您的 jobs 将使用 ID 令牌获取密钥,恭喜!

如果您已将所有项目迁移为使用 ID 令牌获取密钥,并且使用方法 B 进行了迁移,那么现在如果需要,可以将 iss 声明验证移回身份验证方法配置。