GCP Workload Identity Federationを使用したOpenID Connectの設定

caution
CI_JOB_JWT_V2GitLab 15.9で非推奨となり、GitLab 16.5で削除される予定です。代わりにIDトークンを使用してください。

このチュートリアルでは、JSON Web Token(JWT) トークンと Workload Identity Federation を使って、GitLab CI/CD ジョブから Google Cloud への認証を実演します。この設定は、シークレットを保存する必要なく、オンデマンドで短命な認証情報を生成します。

始めるには、GitLabとGoogle Cloud間のIDフェデレーション用にOpenID Connect(OIDC) を設定します。GitLabでOIDCを使用する詳細については、クラウドサービスへの接続をお読みください。

このチュートリアルでは、Google CloudアカウントとGoogle Cloudプロジェクトを持っていることを前提としています。アカウントは Google Cloud プロジェクトで少なくともWorkload Identity Pool Admin権限を持っている必要があります。

このチュートリアルを完了するには

  1. Google Cloud Workload Identity Poolを作成します。
  2. ワークロード ID プロバイダを作成します。
  3. サービスアカウントのなりすましの権限を付与します。
  4. 一時クレデンシャルを取得します。

Google Cloud Workload Identity Pool を作成します。

以下のオプションで新しいGoogle Cloud Workload Identity Poolを作成します:

  • 名前:Name : ワー ク ロ ー ド ID プールの内部 フ ァ イ ル名 (GitLab など)。
  • Pool ID:ワークロード ID プールの Google Cloud プロジェクト内の一意の ID。gitlab など。こ の値はプールを参照する ために使用 さ れ、 URL に表示 さ れます。
  • 説明:省略可能。プールの説明。
  • 有効なプール:このオプションがtrue であることを確認します。

Google Cloudプロジェクトごとに、GitLabインストールごとに単一の_プールを_作成することをお勧めします。同じGitLabインスタンス上に複数のGitLabリポジトリとCI/CDジョブがある場合、同じ_プールに対して_異なる_プロバイダを使って_認証することができます。

ワークロード・アイデンティティ・プロバイダーの作成

次のオプションを使用して、前の手順で作成したワークロード ID プール内に新しい Google Cloud Workload Identity Providerを作成します:

  • プロバイダのタイプ:OpenID Connect(OIDC).
  • プロバイダ名:ワークロード ID プロバイダの親しみやすい名前。gitlab/gitlab など。
  • プロバイダ IDgitlab-gitlab のような、ワークロード ID プロバイダのプール内の一意の ID。この値はプロバイダを参照するために使用され、URL に表示されます。
  • Issuer(URL): GitLab インスタンスのアドレス。https://gitlab.com/https://gitlab.example.com/など。
    • アドレスはhttps:// プロトコルを使用する必要があります。
    • アドレスの末尾はスラッシュでなければなりません。
  • オーディエンス:手動で許可するオーディエンスをGitLabインスタンスのアドレス(https://gitlab.comhttps://gitlab.example.com など)に設定します。
    • アドレスはhttps:// プロトコルを使用する必要があります。
    • アドレスの末尾にスラッシュがあってはなりません。
  • プロバイダー属性のマッピング:以下のマッピングを作成します。attribute.X は Google の請求に存在させたい属性の名前で、assertion.XGitLab の請求から抽出する値です:

    属性(Google上)アサーション(GitLabより)
    google.subjectassertion.sub
    attribute.Xassertion.X

    Common Expression Language(CEL)を使って複雑な属性を作ることもできます。

    権限付与に使用したいすべての属性をマッピングする必要があります。例えば、次のステップでユーザーの電子メールアドレスに基づいて権限をマッピングする場合、attribute.user_emailassertion.user_email にマッピングする必要があります。

サービスアカウントのなりすましに対する権限の付与

Workload Identity PoolとWorkload Identity Providerを作成することで、Google Cloudへの_認証が_定義されます。この時点で、GitLab CI/CDジョブからGoogle Cloudへの認証が可能になります。しかし、Google Cloudに対する権限_(作成_者権限)はありません。

GitLab CI/CDジョブにGoogle Cloud上の権限を付与するには、以下の手順が必要です:

  1. Google Cloudサービスアカウントを作成します。好きな名前とIDを使うことができます。
  2. Google Cloudリソース上のサービスアカウントにIAM権限を付与します。これらの権限はユースケースによって大きく異なります。一般的には、このサービスアカウントにGoogle CloudプロジェクトとGitLab CI/CDジョブで使用したいリソースの権限を付与します。例えば、GitLab CI/CDジョブでGoogle Cloud Storageバケットにファイルをアップロードする必要がある場合、このサービスアカウントにCloud Storageバケットのroles/storage.objectCreator ロールを付与します。
  3. そのService Accountになりすますための外部IDの権限を与えます。このステップによって、GitLab CI/CDジョブがService AccountのなりすましによってGoogle Cloudに_権限を付与_できるようになります。このステップでは、_サービスアカウント自体に_IAM 権限を付与し、外部 ID にそのサービスアカウントとして振る舞う権限を与えます。外部アイデンティティはprincipalSet:// プロトコルを使って表現されます。

前のステップと同様、このステップは設定に大きく依存します。例えば、GitLab CI/CD ジョブがchris というユーザー名の GitLab ユーザーによって開始された場合に、my-service-account という名前のサービスアカウントになりすますことを許可するには、roles/iam.workloadIdentityUser という IAM ロールをmy-service-account の外部アイデンティティに付与します。外部アイデンティティは次のような形式をとります:

principalSet://iam.googleapis.com/projects/PROJECT_NUMBER/locations/global/workloadIdentityPools/POOL_ID/attribute.user_login/chris

PROJECT_NUMBER は Google Cloud プロジェクト番号、POOL_ID は最初のセクションで作成した Workload Identity Pool の ID(名前ではありません)です。

この設定も、前のセクションでアサーションからマッピングされた属性としてuser_login を追加したことを前提としています。

一時クレデンシャルの取得

OIDCとロールを設定した後、GitLab CI/CDジョブはGoogle Cloud Security Token Service(STS) から一時的なクレデンシャルを取得することができます。

CI/CD ジョブにid_tokens を追加します:

job:
  id_tokens:
    GITLAB_OIDC_TOKEN:
      aud: https://gitlab.example.com

ID トークンを使って一時的な認証情報を取得します:

PAYLOAD="$(cat <<EOF
{
  "audience": "//iam.googleapis.com/projects/PROJECT_NUMBER/locations/global/workloadIdentityPools/POOL_ID/providers/PROVIDER_ID",
  "grantType": "urn:ietf:params:oauth:grant-type:token-exchange",
  "requestedTokenType": "urn:ietf:params:oauth:token-type:access_token",
  "scope": "https://www.googleapis.com/auth/cloud-platform",
  "subjectTokenType": "urn:ietf:params:oauth:token-type:jwt",
  "subjectToken": "${GITLAB_OIDC_TOKEN}"
}
EOF
)"
FEDERATED_TOKEN="$(curl --fail "https://sts.googleapis.com/v1/token" \
  --header "Accept: application/json" \
  --header "Content-Type: application/json" \
  --data "${PAYLOAD}" \
  | jq -r '.access_token'
)"

どこに:

  • PROJECT_NUMBER は Google Cloud プロジェクト番号です(名前ではありません)。
  • POOL_ID は、最初のセクションで作成したワークロード ID プールの ID です。
  • PROVIDER_ID は、2 番目のセクションで作成したワークロード ID プロバイダの ID です。
  • GITLAB_OIDC_TOKEN はOIDCIDトークンです。

その結果得られた連携トークンを使って、前のセクションで作成したサービスアカウントになりすますことができます:

ACCESS_TOKEN="$(curl --fail "https://iamcredentials.googleapis.com/v1/projects/-/serviceAccounts/SERVICE_ACCOUNT_EMAIL:generateAccessToken" \
  --header "Accept: application/json" \
  --header "Content-Type: application/json" \
  --header "Authorization: Bearer FEDERATED_TOKEN" \
  --data '{"scope": ["https://www.googleapis.com/auth/cloud-platform"]}' \
  | jq -r '.accessToken'
)"

どこに:

  • SERVICE_ACCOUNT_EMAIL は、前のセクションで作成した、なりすますサービスアカウントの完全なメールアドレスです。
  • FEDERATED_TOKEN は前のステップで取得した連携トークンです。

このアクセストークンをベアラートークンとして使用すると、ほとんどの Google Cloud API やサービスの認証に使用できます。環境変数CLOUDSDK_AUTH_ACCESS_TOKEN を設定することで、この値をgcloud CLI に渡すこともできます。

動作例

Terraform を使って GCP で OIDC をプロビジョニングするための参考プロジェクトと、一時的な認証情報を取得するためのサンプルスクリプトをレビューします。

トラブルシューティング

  • curl レスポンスをデバッグする場合は、最新バージョンの curl をインストールしてください。-f の代わりに--fail-with-body を使用してください。 このコマンドはボディ全体を表示し、有用なエラーメッセージを含むことがあります。

  • ワークロード ID フェデレーションのトラブルシューティングに関する Google Cloud のドキュメントをレビューしてください。