使用 ID 令牌的 OpenID Connect (OIDC) 身份验证

引入于 15.7 版本。

您可以使用极狐GitLab CI/CD 的 ID 令牌对第三方服务进行身份验证。

ID 令牌

ID 令牌是可以添加到极狐GitLab CI/CD 作业的 JSON Web 令牌 (JWT)。它们可用于第三方服务的 OIDC 身份验证,并被 secrets 关键字用于与 HashiCorp Vault 进行身份验证。

ID 令牌在 .gitlab-ci.yml 中配置。例如:

job_with_id_tokens:
  id_tokens:
    FIRST_ID_TOKEN:
      aud: https://first.service.com
    SECOND_ID_TOKEN:
      aud: https://second.service.com
  script:
    - first-service-authentication-script.sh $FIRST_ID_TOKEN
    - second-service-authentication-script.sh $SECOND_ID_TOKEN

在此示例中,这两个令牌具有不同的 aud 声明。第三方服务可以配置为拒绝没有匹配其绑定受众的 aud 声明的令牌。您可以使用此功能来减少令牌可以用来进行身份验证的服务数量,降低令牌泄露的严重性。

令牌负载

每个 ID 令牌中包含以下标准声明:

字段 描述
iss 令牌的颁发者,是极狐GitLab 实例的域名 (“issuer” 声明)。
sub project_path:{group}/{project}:ref_type:{type}:ref:{branch_name} (“subject” 声明)。
aud 令牌的目标受众 (“audience” 声明)。在 ID 令牌 配置中指定。默认情况下为极狐GitLab 实例的域。
exp 过期时间 (“expiration time” 声明)。
nbf 令牌生效后的时间 (“not before” 声明)。
iat JWT 发布时间 (“issued at” 声明)。
jti 令牌的唯一标识符 (“JWT ID” 声明)。

该令牌还包括极狐GitLab 提供的自定义声明:

字段 何时有效 描述
namespace_id 总是 使用它来按 ID 将范围限定为群组或用户级别的命名空间。
namespace_path 总是 使用它来按路径将范围限定为群组或用户级别的命名空间。
project_id 总是 使用它来按 ID 确定项目范围。
project_path 总是 使用它来按路径确定项目范围。
user_id 总是 执行作业的用户 ID。
user_login 总是 执行作业的用户的用户名。
user_email 总是 执行作业的用户的电子邮件。
user_identities 用户偏好设置 用户外部身份列表(引入于 16.0)。
pipeline_id 总是 流水线的 ID。
pipeline_source 总是 流水线源
job_id 总是 作业 ID。
ref 总是 作业的 Git ref。
ref_type 总是 Git ref 类型,branchtag
ref_path 总是 作业的完整 ref。例如,refs/heads/main。引入于 16.0 版本。
ref_protected 总是 如果 Git ref 受保护,则为 true,否则为 false
environment 作业指定一个环境时 此作业部署到的环境(引入于 13.9 版本)。
environment_protected 作业指定一个环境时 如果部署的环境受到保护,则为 true,否则为 false(引入于 13.9 版本)。
deployment_tier 作业指定一个环境时 作业指定的环境的部署级别(引入于 15.2 版本)。
runner_id 总是 执行作业的 runner 的 ID。引入于 16.0 版本。
runner_environment 总是 作业使用的 runner 类型,gitlab-hostedself-hosted。引入于 16.0 版本。
sha 总是 作业的提交 SHA。引入于 16.0 版本。
ci_config_ref_uri 总是 访问顶级流水线定义的引用路径,例如 gitlab.example.com/my-group/my-project//.gitlab-ci.yml@refs/heads/main。引入于 16.2。除非流水线定义位于同一项目中,否则此声明为 null
ci_config_sha 总是 ci_config_ref_uri 的 Git 提交 SHA。引入于 16.2。除非流水线定义位于同一项目中,否则此声明为 null
project_visibility 总是 运行流水线的项目的可见性,可以是 internalprivatepublic。引入于 16.3。
{
  "namespace_id": "72",
  "namespace_path": "my-group",
  "project_id": "20",
  "project_path": "my-group/my-project",
  "user_id": "1",
  "user_login": "sample-user",
  "user_email": "sample-user@example.com",
  "user_identities": [
    {"provider": "github", "extern_uid": "2435223452345"},
    {"provider": "bitbucket", "extern_uid": "john.smith"},
  ],
  "pipeline_id": "574",
  "pipeline_source": "push",
  "job_id": "302",
  "ref": "feature-branch-1",
  "ref_type": "branch",
  "ref_path": "refs/heads/feature-branch-1",
  "ref_protected": "false",
  "environment": "test-environment2",
  "environment_protected": "false",
  "deployment_tier": "testing",
  "runner_id": 1,
  "runner_environment": "self-hosted",
  "sha": "714a629c0b401fdce83e847fc9589983fc6f46bc",
  "project_visibility": "public",
  "ci_config_ref_uri": "gitlab.example.com/my-group/my-project//.gitlab-ci.yml@refs/heads/main",
  "ci_config_sha": "714a629c0b401fdce83e847fc9589983fc6f46bc",
  "jti": "235b3a54-b797-45c7-ae9a-f72d7bc6ef5b",
  "iss": "https://gitlab.example.com",
  "iat": 1681395193,
  "nbf": 1681395188,
  "exp": 1681398793,
  "sub": "project_path:my-group/my-project:ref_type:branch:ref:feature-branch-1",
  "aud": "https://vault.example.com"
}

ID 令牌使用 RS256 编码并使用专用私钥签名。如果指定,则令牌的到期时间设置为作业的超时时间,如果未指定超时时间,则设置为 5 分钟。

手动 ID 令牌身份验证

您可以使用 ID 令牌通过第三方服务进行 OIDC 身份验证。例如:

manual_authentication:
  variables:
    VAULT_ADDR: http://vault.example.com:8200
  image: vault:latest
  id_tokens:
    VAULT_ID_TOKEN:
      aud: http://vault.example.com:8200
  script:
    - export VAULT_TOKEN="$(vault write -field=token auth/jwt/login role=myproject-example jwt=$VAULT_ID_TOKEN)"
    - export PASSWORD="$(vault kv get -field=password secret/myproject/example/db)"
    - my-authentication-script.sh $VAULT_TOKEN $PASSWORD

使用 HashiCorp Vault 进行自动 ID 令牌身份验证

您可以使用 ID 令牌通过 secrets 关键字自动从 HashiCorp Vault 获取 secret。

如果您之前使用 CI_JOB_JWT 从 Vault 获取 secret,请了解如何使用更新 HashiCorp Vault 配置以使用 ID 令牌 教程切换到 ID 令牌。

配置自动 ID 令牌身份验证

如果定义了一个 ID 令牌,secrets 关键字会自动使用它来对 Vault 进行身份验证。例如:

job_with_secrets:
  id_tokens:
    VAULT_ID_TOKEN:
      aud: https://example.vault.com
  secrets:
    PROD_DB_PASSWORD:
      vault: example/db/password # authenticates using $VAULT_ID_TOKEN
  script:
    - access-prod-db.sh --token $PROD_DB_PASSWORD

如果定义了多个 ID 令牌,请使用 token 关键字指定应使用哪个令牌。例如:

job_with_secrets:
  id_tokens:
    FIRST_ID_TOKEN:
      aud: https://first.service.com
    SECOND_ID_TOKEN:
      aud: https://second.service.com
  secrets:
    FIRST_DB_PASSWORD:
      vault: first/db/password
      token: $FIRST_ID_TOKEN
    SECOND_DB_PASSWORD:
      vault: second/db/password
      token: $SECOND_ID_TOKEN
  script:
    - access-first-db.sh --token $FIRST_DB_PASSWORD
    - access-second-db.sh --token $SECOND_DB_PASSWORD

启用自动 ID 令牌身份验证(已废弃)

caution 此设置已在极狐GitLab 16.0 中移除。ID 令牌身份验证现在一直可用,并且 JSON Web 令牌访问始终受到限制。

要启用自动 ID 令牌身份验证:

  1. 在左侧边栏中,选择 搜索或转到 并找到您的项目。
  2. 选择 设置 > CI/CD
  3. 展开 令牌访问
  4. 打开 限制 JSON Web 令牌 (JWT) 访问 开关。

故障排除

400: missing token 状态码

此错误表明 ID 令牌所需的一个或多个基本组件丢失或未按预期配置。

要查找问题,管理员可以在实例的 exceptions_json.log 中查找失败的特定方法详情。

GitLab::Ci::Jwt::NoSigningKeyError

exceptions_json.log 文件中的此错误可能是因为数据库中缺少签名密钥并且无法生成令牌。要验证这是否是问题所在,请在实例的 PostgreSQL 终端上运行以下查询:

SELECT encrypted_ci_jwt_signing_key FROM application_settings;

如果返回的值为空,请使用下面的 Rails 代码片段生成一个新密钥并在内部进行替换:

  key = OpenSSL::PKey::RSA.new(2048).to_pem

  ApplicationSetting.find_each do |application_setting|
    application_setting.update(ci_jwt_signing_key: key)
  end