使用 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 总是 执行作业的用户的电子邮件。
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 版本。
{
  "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",
  "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",
  "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 获取 secrets。

配置自动 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