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

note 从 Vault 1.17 开始,当 JWT 包含 aud 声明时,JWT auth login 需要在角色上绑定 audiencesaud 声明可以是单个字符,也可以是字符串列表。

本教程演示如何转换现有的 CI/CD secret 配置以使用 ID 令牌

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

迁移到 ID 令牌并没有一个标准方法,因此本教程包括两种将现有 CI/CD secret 转换的方法。选择最适合您用例的方法:

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

先决条件

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

要继续操作,您必须具备:

  • 运行极狐GitLab 15.9 或更高版本的实例,或者位于 JihuLab.com 上。
  • 您已经在使用的 Vault 服务器。
  • CI/CD 作业使用 CI_JOB_JWT 从 Vault 检索 secret。

在下面的示例中,替换:

  • vault.example.com 为您的 Vault 服务器 URL。
  • gitlab.example.com 为您的极狐GitLab 实例 URL。
  • jwt or jwt_v2 为您的 auth 方法名称。

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

此方法会创建一个与现有方法并行的第二个 JWT 身份验证路径。然后,重新创建用于极狐GitLab 集成的所有 Vault 角色。

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

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

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

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

您可以在 Vault 中创建多个身份验证路径,使您能够在不中断的情况下按作业基础过渡到项目上的 IT 令牌。

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

    vault auth enable -path jwt_v2 jwt
    

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

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

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

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

角色绑定到特定的身份验证路径,因此您需要为每个作业添加新角色。

  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_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_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 声明验证的迁移从认证方法恢复到角色。

从 auth 方法移除 bound_issuers 声明

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

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

直接将 bound_issuer 设置为空字符串会删除 auth 方法级别的验证。但是,由于我们已将此验证移动到角色级别,因此此配置仍然安全。

更新您的 CI/CD 作业

Vault 有两个不同的 KV Secrets Engine,您使用的版本会影响您在 CI/CD 中定义 secret 的方式。

HashiCorp 支持门户上的检查我的 Vault KV Mount 是哪个版本可以检查您的 Vault 服务器。

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

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

The following examples show how to obtain the staging database password written to the password field in secret/myproject/staging/db.

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

  • 方法 A(迁移 JWT 角色到新的 Vault auth 方法):使用 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
    VAULT_AUTH_ROLE: myproject-staging
  id_tokens:
    VAULT_ID_TOKEN:
      aud: https://gitlab.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 令牌默认将 secret 放置在文件中,但我们需要它以常规变量的方式匹配旧的行为。

KV Secrets Engine v2

v2 引擎可以使用两种格式。

长格式:

job:
  variables:
    VAULT_SERVER_URL: https://vault.example.com
    VAULT_AUTH_PATH: jwt_v2
    VAULT_AUTH_ROLE: myproject-staging
  id_tokens:
    VAULT_ID_TOKEN:
      aud: https://gitlab.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
    VAULT_AUTH_ROLE: myproject-staging
  id_tokens:
    VAULT_ID_TOKEN:
      aud: https://gitlab.example.com
  secrets:
      PASSWORD:
        vault: myproject/staging/db/password@secret
        file: false

提交更新的 CI/CD 配置后,您的作业将使用 ID 令牌获取 secret。

如果您已经将所有项目迁移到使用 ID 令牌获取 secret,并且使用方法 B 进行迁移,则现在可以将 iss 声明验证移回 auth 方法配置(如果需要)。