{{< details >}}

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

{{< /details >}}

{{< alert type=”note” >}}

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

{{< /alert >}}

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

CI_JOB_JWT 变量已被弃用,但更新为 ID 令牌需要进行一些重要的配置更改,以便与 Vault 一起使用。如果你有多个作业,一次性转换所有内容是一项艰巨的任务。

没有一种标准方法来迁移到 ID Tokens,因此本教程包括两种转换现有 CI/CD 密钥的方法。选择最适合你用例的方法:

  1. 更新你的 Vault 配置:
  2. 更新你的 CI/CD 作业

先决条件

本教程假设你熟悉极狐GitLab CI/CD 和 Vault。

要跟随本教程,你必须拥有:

  • 运行极狐GitLab 16.0 或更高版本的实例,或在 JihuLab.com 上。
  • 一个你已经在使用的 Vault 服务器。
  • 使用 CI_JOB_JWT 从 Vault 检索密钥的 CI/CD 作业。

在下面的示例中,替换:

  • vault.example.com 为你的 Vault 服务器的 URL。
  • gitlab.example.com 为你的极狐GitLab 实例的 URL。
  • jwtjwt_v2 为你的认证方法名称。

方法 A:迁移 JWT 角色到新的 Vault 认证方法

此方法在并行使用的现有 JWT 认证方法中创建了第二个 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 的作业将开始失败。

你可以在 Vault 中创建多个认证路径,这使你能够在项目的作业基础上过渡到 ID Tokens 而不会中断。

  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"
    

重新创建角色以使用新的认证路径

角色绑定到特定的认证路径,因此你需要为每个作业添加新角色。如果 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 声明验证。这支持带有 https:// 前缀的极狐GitLab 实例主机名声明,该声明附带 id_tokens,以及旧的无前缀声明。

要将 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 Tokens 的并行支持后,将 iss 声明验证的迁移从认证方法恢复到角色。

从认证方法中移除 bound_issuers 声明

在所有角色都更新了 bound_claims.iss 声明后,你可以移除此验证的认证方法级别配置:

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

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

更新你的 CI/CD 作业

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

此外,如果需要,你可以查看以下 CI/CD 文档:

以下示例显示了如何获取写入 secret/myproject/staging/db 中的 password 字段的暂存数据库密码。

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

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

KV Secrets Engine v1

secrets:vault 关键字默认为 KV Mount 的 v2,因此需要显式配置作业以使用 v1 引擎:

job:
  variables:
    VAULT_SERVER_URL: https://vault.example.com
    VAULT_AUTH_PATH: jwt_v2  # 或 "jwt" 如果你使用了方法 B
    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 Tokens 默认情况下将密钥放入文件中,但我们需要它作为常规变量以匹配旧行为。

KV Secrets Engine v2

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

长格式:

job:
  variables:
    VAULT_SERVER_URL: https://vault.example.com
    VAULT_AUTH_PATH: jwt_v2  # 或 "jwt" 如果你使用了方法 B
    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  # 或 "jwt" 如果你使用了方法 B
    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 配置后,你的作业将使用 ID Tokens 获取密钥,恭喜你!

如果你已迁移所有项目以使用 ID Tokens 获取密钥,并且在迁移过程中使用了方法 B,现在可以选择将 iss 声明验证移回认证方法配置。