1つの Workload Identity 連携から、複数の Google Cloud プロジェクトにアクセスしてみる
はじめに
こんにちは、すらぼです。
Google Cloud の Workload Identity 連携を使うと、AWS の EC2 インスタンスなどの外部ワークロードから Google Cloud リソースにアクセスできます。
ただ、Workload Identity 連携はプロジェクトリソースのため、複数のプロジェクトにアクセスしようとした時にどのような挙動になるのかが気になりました。
今回は、1つの Workload Identity プロバイダーで、2つの Google Cloud プロジェクトのリソースにアクセスできるかを検証しました。
やりたいこと
以下の構成を実現します。
- AWS の EC2 インスタンスから Google Cloud にアクセスする
- Workload Identity 連携のプロバイダーは1つだけ用意する
- そのプロバイダーを通じて、2つの異なる Google Cloud プロジェクトのリソース(Cloud Storage バケット)にアクセスする
前提条件
- AWS アカウントと EC2 インスタンスが利用可能であること
- Google Cloud プロジェクトが2つ用意されていること
- プロジェクトA(Workload Identity プールを作成するプロジェクト)
- プロジェクトB(アクセス先として追加するプロジェクト)
gcloudCLI がインストール済みであること
検証環境の準備
プロジェクトA: Workload Identity プールとプロバイダーの作成
まず、プロジェクトAに Workload Identity プールを作成します。
PROJECT_A, PROJECT_B, AWS_ACCOUNT_ID の3つは、ご自身の環境に併せて適宜書き換えてください。
# 環境変数の設定
$ export PROJECT_A="your-project-a-id"
$ export PROJECT_B="your-project-b-id"
$ export AWS_ACCOUNT_ID="123456789012"
$ export POOL_ID="aws-pool-260331"
$ export PROVIDER_ID="aws-provider-260331"
# プロジェクトAに切り替え
$ gcloud config set project $PROJECT_A
# Workload Identity プールの作成
$ gcloud iam workload-identity-pools create $POOL_ID \
--location="global" \
--display-name="AWS Pool"
# Workload Identity プロバイダーの作成(AWS 用)
$ gcloud iam workload-identity-pools providers create-aws $PROVIDER_ID \
--location="global" \
--workload-identity-pool=$POOL_ID \
--account-id=$AWS_ACCOUNT_ID \
--attribute-mapping="google.subject=assertion.arn,attribute.aws_account=assertion.account"
プロジェクトA: サービスアカウントの作成と権限付与
プロジェクトAにサービスアカウントを作成し、Workload Identity プールからの権限借用を許可します。
# サービスアカウントの作成
$ gcloud iam service-accounts create sa-for-aws \
--display-name="SA for AWS Workload"
# Workload Identity プールから権限借用を許可
$ gcloud iam service-accounts add-iam-policy-binding \
sa-for-aws@${PROJECT_A}.iam.gserviceaccount.com \
--role="roles/iam.workloadIdentityUser" \
--member="principalSet://iam.googleapis.com/projects/$(gcloud projects describe $PROJECT_A --format='value(projectNumber)')/locations/global/workloadIdentityPools/${POOL_ID}/*"
プロジェクトA: 検証用バケットの作成と権限付与
# 検証用バケットの作成
$ gcloud storage buckets create gs://${PROJECT_A}-wi-test --location=asia-northeast1
# サービスアカウントにバケットへのアクセス権を付与
$ gcloud storage buckets add-iam-policy-binding gs://${PROJECT_A}-wi-test \
--member="serviceAccount:sa-for-aws@${PROJECT_A}.iam.gserviceaccount.com" \
--role="roles/storage.objectViewer"
プロジェクトB: 検証用バケットの作成と権限付与
プロジェクトBにもバケットを作成し、プロジェクトAのサービスアカウントにアクセス権を付与します。
# プロジェクトBに切り替え
$ gcloud config set project $PROJECT_B
# 検証用バケットの作成
$ gcloud storage buckets create gs://${PROJECT_B}-wi-test --location=asia-northeast1
# プロジェクトAのサービスアカウントにプロジェクトBのバケットへのアクセス権を付与
$ gcloud storage buckets add-iam-policy-binding gs://${PROJECT_B}-wi-test \
--member="serviceAccount:sa-for-aws@${PROJECT_A}.iam.gserviceaccount.com" \
--role="roles/storage.objectViewer"
認証情報ファイルの作成(Cloud Shell で実行)
認証情報ファイル(credential config)の実態ははただの JSON ファイルです。Google Cloud の Cloud Shell で生成し、中身をコピーして EC2 のターミナル上からペーストする形でファイルを作成します。
# Cloud Shell で実行
$ gcloud config set project $PROJECT_A
# 認証情報ファイルの生成
$ gcloud iam workload-identity-pools create-cred-config \
projects/$(gcloud projects describe $PROJECT_A --format='value(projectNumber)')/locations/global/workloadIdentityPools/${POOL_ID}/providers/${PROVIDER_ID} \
--service-account=sa-for-aws@${PROJECT_A}.iam.gserviceaccount.com \
--aws \
--enable-imdsv2 \
--output-file=credential-config.json
# 中身を表示してコピー
$ cat credential-config.json
出力された JSON をコピーしておきます。
{
"universe_domain": "googleapis.com",
"type": "external_account",
"audience": "//iam.googleapis.com/projects/<プロジェクト番号>/locations/global/workloadIdentityPools/aws-pool-260331/providers/aws-provider-260331",
"subject_token_type": "urn:ietf:params:aws:token-type:aws4_request",
"token_url": "https://sts.googleapis.com/v1/token",
"credential_source": {
"environment_id": "aws1",
"region_url": "http://169.254.169.254/latest/meta-data/placement/availability-zone",
"url": "http://169.254.169.254/latest/meta-data/iam/security-credentials",
"regional_cred_verification_url": "https://sts.{region}.amazonaws.com?Action=GetCallerIdentity&Version=2011-06-15",
"imdsv2_session_token_url": "http://169.254.169.254/latest/api/token"
},
"service_account_impersonation_url": "https://iamcredentials.googleapis.com/v1/projects/-/serviceAccounts/sa-for-aws@<プロジェクトID>.iam.gserviceaccount.com:generateAccessToken"
}
EC2 インスタンスでの設定
認証情報ファイルの配置
EC2 にログインし、先ほどコピーした JSON をそのままペーストしてファイルを作成します。
$ cat <<'EOF' > ~/credential-config.json
{ここに Cloud Shell でコピーした JSON をペースト}
EOF
Python クライアントライブラリのインストール
EC2 では Google Cloud の Python クライアントライブラリを使って検証します。
$ sudo yum install -y python3.11 python3.11-pip
$ python3.11 -m pip install google-cloud-storage
環境変数の設定
# 認証情報ファイルのパスを環境変数に設定
$ export GOOGLE_APPLICATION_CREDENTIALS=~/credential-config.json
検証
これで準備が整ったので、実際にスクリプトを実行してアクセスできることを確認していきます。
プロジェクトAのバケットへのアクセス
検証用の Python スクリプトを作成します。
<プロジェクトAのID> と <プロジェクトAのバケット名> は、ご自身の環境にあわせて書き換えてください。
$ cat <<'EOF' > test_project_a.py
from google.cloud import storage
client = storage.Client(project="<プロジェクトAのID>")
blobs = client.list_blobs("<プロジェクトAのバケット名>")
for blob in blobs:
print(blob.name)
EOF
以下のコマンドで実行してみます。
$ python3.11 test_project_a.py
実行すると、事前にバケットに作成していた sample_a.txt が確認できました。

プロジェクトBのバケットへのアクセス
同じ認証情報のまま、プロジェクトBのバケットにもアクセスします。
$ cat <<'EOF' > test_project_b.py
from google.cloud import storage
client = storage.Client(project="<プロジェクトBのID>")
blobs = client.list_blobs("<プロジェクトBのバケット名>")
for blob in blobs:
print(blob.name)
EOF
同じように実行してみます。
$ python3.11 test_project_b.py
こちらも、バケットの中身が確認できましたね。

これで、 Workload Identity provider 1つで、複数の Google Cloud プロジェクトへのアクセス許可を実現できました。
まとめ
今回の検証では、1つの Workload Identity プロバイダーで2つの Google Cloud プロジェクトのリソースにアクセスできるかを確認しました。
「IAM のバインディングをプロジェクト跨ぎで実装できる」という点は理解していましたが、Workload Identity 連携のプールやプロバイダーに対しても同じようにプロジェクトを跨いで権限付与ができることを検証してみました。
同じような疑問や課題を持っている方の参考になれば幸いです。以上、すらぼでした。
参考資料






