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」クレーム)。
iatJWTがイシューされた時間(”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 トークン認証を有効にする(非推奨)

caution
この設定はGitLab 16.0で削除されました。IDトークン認証は常に利用可能になり、JSONウェブトークンアクセスは常に制限されるようになりました。

自動IDトークン認証を有効にするには

  1. 左のサイドバーで「検索」または「移動」を選択してあなたのプロジェクトを検索します。
  2. Settings > CI/CDを選択します。
  3. アクセストークンを展開します。
  4. 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