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

使用 ID 令牌进行 OpenID Connect (OIDC) 认证

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

您可以使用 GitLab CI/CD 的 ID tokens 与第三方服务进行身份验证。

ID 令牌

ID tokens 是可以添加到 GitLab CI/CD 作业中的 JSON Web Tokens (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 令牌包含以下标准声明:

Field Description
iss 令牌的颁发者,即 GitLab 实例的域名(“issuer” 声明)。
sub 令牌的主题(“subject” 声明)。默认为 project_path:{group}/{project}:ref_type:{type}:ref:{branch_name}。可以使用 projects API 为项目配置。
aud 令牌的预期受众(“audience” 声明)。在 ID tokens 配置中指定。默认为 GitLab 实例的域名。
exp 过期时间(“expiration time” 声明)。
nbf 令牌生效的时间(“not before” 声明)。
iat JWT 颁发的时间(“issued at” 声明)。
jti 令牌的唯一标识符(“JWT ID” 声明)。

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

Field When Description
namespace_id Always 使用此通过 ID 限定到组或用户级别的命名空间。
namespace_path Always 使用此通过路径限定到组或用户级别的命名空间。
project_id Always 使用此通过 ID 限定到项目。
project_path Always 使用此通过路径限定到项目。
user_id Always 执行作业的用户 ID。
user_login Always 执行作业的用户名。
user_email Always 执行作业的用户邮箱。
user_access_level Always 执行作业用户的访问级别。Introduced in GitLab 16.9.
user_identities User Preference setting 用户的外部身份列表(introduced in GitLab 16.0)。
pipeline_id Always 管道 ID。
pipeline_source Always 管道来源
job_id Always 作业 ID。
ref Always 作业的 Git ref。
ref_type Always Git ref 类型,可以是 branchtag
ref_path Always 作业的完全限定 ref。例如,refs/heads/mainIntroduced in GitLab 16.0.
ref_protected Always 如果 Git ref 受保护则为 true,否则为 false
groups_direct User is a direct member of 0 to 200 groups 用户直接所属组的路径。如果用户直接所属组超过 200 个,则省略此字段。(Introduced in GitLab 16.11 and put behind the ci_jwt_groups_direct feature flag in GitLab 17.3.
environment Job specifies an environment 此作业部署到的环境。
environment_protected Job specifies an environment 如果部署的环境受保护则为 true,否则为 false
deployment_tier Job specifies an environment 作业指定环境的部署级别Introduced in GitLab 15.2.
environment_action Job specifies an environment 作业中指定的环境操作 (environment:action)。(Introduced in GitLab 16.5)
runner_id Always 执行作业的 runner ID。Introduced in GitLab 16.0.
runner_environment Always 作业使用的 runner 类型。可以是 gitlab-hostedself-hostedIntroduced in GitLab 16.0.
sha Always 作业的提交 SHA。Introduced in GitLab 16.0.
ci_config_ref_uri Always 顶级管道定义的 ref 路径,例如 gitlab.example.com/my-group/my-project//.gitlab-ci.yml@refs/heads/mainIntroduced in GitLab 16.2。除非管道定义位于同一项目中,否则此声明为 null
ci_config_sha Always ci_config_ref_uri 的 Git 提交 SHA。Introduced in GitLab 16.2。除非管道定义位于同一项目中,否则此声明为 null
project_visibility Always 运行管道的项目可见性。可以是 internalprivatepublicIntroduced in GitLab 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": "[email protected]",
  "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",
  "groups_direct": ["mygroup/mysubgroup", "myothergroup/myothersubgroup"],
  "environment": "test-environment2",
  "environment_protected": "false",
  "deployment_tier": "testing",
  "environment_action": "start",
  "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 身份验证。例如:

故障排除

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

401: unauthorized 状态码

此错误表示身份验证请求失败。当使用来自 GitLab 管道到外部服务的 OpenID Connect (OIDC) 身份验证时,401 Unauthorized 错误可能由以下常见原因引起:

  • 您使用了已弃用的令牌,如 $CI_JOB_JWT_V2,而不是声明 ID 令牌。有关更多信息,请参阅旧版本的 JSON Web Tokens 已弃用
  • 您在 .gitlab-ci.yml 文件和外部服务上的 OIDC 身份提供者配置之间不匹配 provider_name 值。
  • 您遗漏了 ID 令牌(由 GitLab 颁发)与外部服务期望的 aud(受众)声明之间的匹配。
  • 您没有在 GitLab CI/CD 作业中启用或配置 id_tokens: 块。

要解决此错误,请在作业中解码令牌:

echo $OIDC_TOKEN | cut -d '.' -f2 | base64 -d | jq .

确保:

  • aud(受众)与预期的受众匹配(例如,外部服务的 URL)。
  • sub(主题)在服务的身份提供者设置中映射。
  • GitLab ID 令牌默认不包含 preferred_username