OpenID Connect(OIDC) IDトークンを使った認証
GitLab 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
この例では、2 つのトークンは異なるaud
クレームを持って aud
います。aud
サードパーティ・サービスは aud
、バインドされたオーディエンスと一致するクレームを持たない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 | 常に | ジョブを実行するユーザーのEメール。 |
user_identities | ユーザー設定 | ユーザーの外部IDのリスト(GitLab 16.0で導入)。 |
pipeline_id | 常に | パイプラインのID。 |
pipeline_source | 常に | パイプラインソース |
job_id | 常に | ジョブのID。 |
ref | 常に | ジョブのGit Ref. |
ref_type | 常に | Git 参照タイプ、branch またはtag のいずれか。 |
ref_path | 常に | ジョブの完全修飾参照。例えば、refs/heads/main 。 GitLab 16.0で導入されました。 |
ref_protected | 常に |
true Git ref が保護されている場合は常に、そうでない場合はfalse 。 |
environment | ジョブは環境を指定します | このジョブがデプロイする環境(GitLab 13.9で導入)。 |
environment_protected | ジョブは環境を指定します |
true false を指定します (GitLab 13.9 で導入されました)。 |
deployment_tier | ジョブは環境を指定します | ジョブが指定した環境のデプロイ階層。GitLab 15.2 で導入。 |
runner_id | 常に | ジョブを実行する Runner の ID。GitLab 16.0で導入。 |
runner_environment | 常に | ジョブが使用するランナーのタイプ。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 | 常に | Git commit SHA for theci_config_ref_uri . 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",
"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トークン認証
サードパーティのサービスを利用したOIDC認証にIDトークンを使用することができます。例えば
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トークン認証
secrets
キーワードを使用すると、HashiCorp Vault からシークレットを自動的に取得するために ID トークンを使用できます。
以前、CI_JOB_JWT
を使用して Vault からシークレットをフェッチしていた場合は、チュートリアルの「Update HashiCorp Vault configuration to use ID Tokens」を参照して ID トークンに切り替える方法を学んでください。
自動IDトークン認証の設定
ID トークンが 1 つ定義されている場合、secrets
キーワードは、Vault での認証にその ID トークンを自動的に使用します。例えば
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 トークン認証を有効にする(非推奨)
自動IDトークン認証を有効にするには
- 左のサイドバーで「検索」または「移動」を選択してあなたのプロジェクトを検索します。
- Settings > CI/CDを選択します。
- アクセストークンを展開します。
- Limit JSON Web Token(JWT) accesstoggle をオンにします。
トラブルシューティング
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)
end