使用 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 类型,可以是 branch 或 tag。 |
ref_path |
Always | 作业的完全限定 ref。例如,refs/heads/main。Introduced 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-hosted 或 self-hosted。Introduced 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/main。Introduced in GitLab 16.2。除非管道定义位于同一项目中,否则此声明为 null。 |
ci_config_sha |
Always | ci_config_ref_uri 的 Git 提交 SHA。Introduced in GitLab 16.2。除非管道定义位于同一项目中,否则此声明为 null。 |
project_visibility |
Always | 运行管道的项目可见性。可以是 internal、private 或 public。Introduced 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)
end401: 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。