IDトークンを使用したOpenID Connect(OIDC)認証
- プラン: Free、Premium、Ultimate
- 提供形態: GitLab.com、GitLab Self-Managed、GitLab Dedicated
IDトークンは、JSON Webトークン (JSON Webトークン)で、GitLab CI/CDによって生成されます。CI/CDジョブは、サードパーティサービスとのOIDC認証にIDトークンを使用できます。対象となるサービスは次のとおりです:
たとえば、IDトークンを使用してHashiCorp Vaultで認証を行うフローは、次の図にまとめられています:
sequenceDiagram
participant GitLab as GitLab CI/CD
participant Runner as GitLab Runner
participant Vault as HashiCorp Vault
GitLab->>Runner: Generates an ID token (JWT) for the CI/CD job
Runner->>Vault: Runner authenticates with HashiCorp Vault using the token
Vault->>Vault: HashiCorp Vault verifies the token
Vault->>Vault: HashiCorp Vault checks bounded claims and attaches policies
Vault->>Runner: HashiCorp Vault returns the token
Runner->>Vault: Runner requests secrets from HashiCorp Vault
Vault->>Runner: Returns secrets
IDトークンは、secretsキーワードでも使用されます。
CI/CDジョブでIDトークンを設定する
IDトークンを使用するには、id_tokensキーワードでCI/CDジョブを設定します。
例:
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この例では、2つのトークンには異なるaudクレームが含まれています。サードパーティサービスは、バインドされたオーディエンスに一致するaudクレームを持たないトークンを拒否するように設定できます。この機能を使用して、トークンが認証に使用できるサービスの数を減らします。これにより、トークンが侵害された場合の重大度が軽減されます。
トークンのペイロード
各IDトークンには、次の標準クレームが含まれています:
| フィールド | 説明 |
|---|---|
iss | トークンの発行者。これはGitLabインスタンスのドメイン(「issuer」クレーム)です。 |
sub | トークンのサブジェクト(「subject」クレーム)。デフォルトはproject_path:{group}/{project}:ref_type:{type}:ref:{branch_name}です。プロジェクトAPIでプロジェクトに対して設定できます。 |
aud | トークンの対象オーディエンス(「audience」クレーム)。IDトークン設定で指定されます。デフォルトではGitLabインスタンスのドメイン。 |
exp | 有効期限(「expiration time」クレーム)。 |
nbf | トークンが有効になる時刻(「not before」クレーム)。 |
iat | JWTが発行された時刻(「issued at」クレーム)。 |
jti | トークンの固有識別子(「JWT ID」クレーム)。 |
トークンには、GitLabによって提供されるカスタムクレームも含まれています:
| フィールド | 使用時 | 説明 |
|---|---|---|
project_id | 常時 | ジョブを実行しているプロジェクトのID。マージリクエストパイプラインでは、これはソースブランチプロジェクトのIDです。 |
project_path | 常時 | ジョブを実行しているプロジェクトのパス。マージリクエストパイプラインでは、これはソースブランチプロジェクトのパスです。 |
namespace_id | 常時 | ジョブを実行しているプロジェクトのネームスペースID。マージリクエストパイプラインでは、これはソースブランチプロジェクトのネームスペースIDです。 |
namespace_path | 常時 | ジョブを実行しているプロジェクトのネームスペースパス。マージリクエストパイプラインでは、これはソースブランチプロジェクトのネームスペースパスです。 |
user_id | 常時 | ジョブを実行しているユーザーのID。 |
user_login | 常時 | ジョブを実行しているユーザーのユーザー名。 |
user_email | 常時 | ジョブを実行しているユーザーのメール。 |
user_access_level | 常時 | ジョブを実行しているユーザーのアクセスレベル。GitLab 16.9で導入されました。 |
job_project_id | 常時 | ジョブを実行しているプロジェクトのID。これを使用して、IDでプロジェクトにスコープを設定します。GitLab 18.4で導入されました。 |
job_project_path | 常時 | ジョブを実行しているプロジェクトのパス。これを使用して、パスでプロジェクトにスコープを設定します。GitLab 18.4で導入されました。 |
job_namespace_id | 常時 | ジョブを実行しているプロジェクトのネームスペースID。IDでグループまたはユーザーレベルのネームスペースにスコープを設定するために使用します。GitLab 18.4で導入されました。 |
job_namespace_path | 常時 | ジョブを実行しているプロジェクトのネームスペースパス。パスでグループまたはユーザーレベルのネームスペースにスコープを設定するために使用します。GitLab 18.4で導入されました。 |
user_identities | ユーザー設定で有効のとき | ユーザーの外部IDのリスト(GitLab 16.0で導入されました)。 |
pipeline_id | 常時 | パイプラインのID。 |
pipeline_source | 常時 | パイプラインソース。 |
job_id | 常時 | ジョブのID。 |
ref | 常時 | このジョブのGit ref。マージリクエストパイプラインでは、これはソースブランチrefsです。 |
ref_type | 常時 | Git refタイプ(branchまたはtag)。 |
ref_path | 常時 | ジョブの完全修飾参照。たとえばrefs/heads/mainなどです。マージリクエストパイプラインでは、これはソースブランチrefsパスです。GitLab 16.0で導入されました。 |
ref_protected | 常時 | Git参照が保護されている場合はtrue、それ以外の場合はfalse。 |
groups_direct | ユーザーが0 - 200のグループの直接メンバーであるとき | ユーザーの直接メンバーシップグループのパス。ユーザーが200を超えるグループの直接のメンバーである場合は省略されます。(GitLab 16.11で導入され、GitLab 17.3でci_jwt_groups_direct機能フラグの背後に置かれました。 |
environment | ジョブが環境を指定するとき | このジョブのデプロイ先の環境。 |
environment_protected | ジョブが環境を指定するとき | デプロイされた環境が保護されている場合はtrue、それ以外の場合はfalse。 |
deployment_tier | ジョブが環境を指定するとき | ジョブが指定する環境のデプロイ層。GitLab 15.2で導入されました。 |
environment_action | ジョブが環境を指定するとき | ジョブで指定された環境アクション(environment:action)。(GitLab 16.5で導入されました) |
runner_id | 常時 | ジョブを実行しているRunnerのID。GitLab 16.0で導入されました。 |
runner_environment | 常時 | ジョブで使用されるRunnerのタイプ。gitlab-hostedまたはself-hostedのいずれかになります。GitLab 16.0で導入されました。 |
sha | 常時 | ジョブのコミットSHA。GitLab 16.0で導入されました。 |
ci_config_ref_uri | 常時 | トップレベルのパイプライン定義への参照パス(例: gitlab.example.com/my-group/my-project//.gitlab-ci.yml@refs/heads/main)。GitLab 16.2で導入されました。パイプライン定義が同じプロジェクトにない場合、このクレームはnullです。 |
ci_config_sha | 常時 | ci_config_ref_uriのGitコミットSHA。GitLab 16.2で導入されました。パイプライン定義が同じプロジェクトにない場合、このクレームはnullです。 |
project_visibility | 常時 | パイプラインが実行されているプロジェクトの表示レベル。internal、private、またはpublicを指定できます。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": "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",
"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分(タイムアウトが指定されていない場合)に設定されます。
トラブルシューティング
400: missing tokenステータスコード
このエラーは、IDトークンに必要な基本コンポーネントが1つ以上欠落しているか、予期したとおりに設定されていないことを示しています。
管理者が問題を特定するには、失敗した特定の方法について、インスタンスの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トークンは非推奨を参照してください。.gitlab-ci.ymlファイルと外部サービスのOIDC Identity Providerの設定の間でprovider_nameの値が一致していない。- GitLabが発行したIDトークンと、外部サービスが予期する内容の間で、
aud(オーディエンス)クレームが欠落しているか、一致していない。 - GitLab CI/CDジョブで
id_tokens:ブロックを有効にしていないか、設定していない。
このエラーを解決するには、ジョブ内でトークンをデコードします:
echo $OIDC_TOKEN | cut -d '.' -f2 | base64 -d | jq .以下を確認してください:
aud(オーディエンス)が、予期されるオーディエンス(外部サービスのURLなど)と一致している。sub(サブジェクト)が、サービスのIdentity Providerの設定でマップされている。preferred_usernameが、デフォルトでGitLab IDトークンに存在しない。