🔐
GCPサービスアカウントの借用チェーンを検証してみた
はじめに
Google CloudのIAMには、サービスアカウントの借用(Impersonation)という強力な機能があります。この機能を使うと、あるサービスアカウントが別のサービスアカウントの権限を一時的に借用できます。
今回は、サービスアカウントの借用を連鎖させた場合の動作を検証してみました。具体的には、サービスアカウントA → B → Cという借用チェーンを構築し、最終的にCの権限が使えるかを確認します。
検証環境の構築
サービスアカウントの作成
まず、3つのサービスアカウントを作成します。
# プロジェクトIDを設定
export PROJECT_ID="your-project-id"
# サービスアカウントA(起点となるアカウント)
gcloud iam service-accounts create sa-account-a \
--display-name="Service Account A" \
--project=$PROJECT_ID
# サービスアカウントB(中間のアカウント)
gcloud iam service-accounts create sa-account-b \
--display-name="Service Account B" \
--project=$PROJECT_ID
# サービスアカウントC(最終的に借用したいアカウント)
gcloud iam service-accounts create sa-account-c \
--display-name="Service Account C" \
--project=$PROJECT_ID
IAMポリシーの設定
各サービスアカウント間で借用を可能にするため、適切なIAMロールを付与します。
# A → Bの借用を許可
gcloud iam service-accounts add-iam-policy-binding \
sa-account-b@$PROJECT_ID.iam.gserviceaccount.com \
--member="serviceAccount:sa-account-a@$PROJECT_ID.iam.gserviceaccount.com" \
--role="roles/iam.serviceAccountTokenCreator" \
--project=$PROJECT_ID
# B → Cの借用を許可
gcloud iam service-accounts add-iam-policy-binding \
sa-account-c@$PROJECT_ID.iam.gserviceaccount.com \
--member="serviceAccount:sa-account-b@$PROJECT_ID.iam.gserviceaccount.com" \
--role="roles/iam.serviceAccountTokenCreator" \
--project=$PROJECT_ID
検証用の権限設定
サービスアカウントCにのみ、Cloud Storage バケットへのアクセス権限を付与します。
# テスト用バケットの作成
export BUCKET_NAME="test-impersonation-$PROJECT_ID"
gsutil mb gs://$BUCKET_NAME
# サービスアカウントCにのみバケットへのアクセス権限を付与(オブジェクト作成権限を含む)
gsutil iam ch serviceAccount:sa-account-c@$PROJECT_ID.iam.gserviceaccount.com:objectAdmin \
gs://$BUCKET_NAME
借用チェーンの検証
サービスアカウントAのキーを作成
gcloud iam service-accounts keys create sa-account-a-key.json \
--iam-account=sa-account-a@$PROJECT_ID.iam.gserviceaccount.com
Pythonでの検証コード
借用チェーンを実装して、最終的にサービスアカウントCの権限でCloud Storageにアクセスできるか検証します。
# test_impersonation_chain.py
import google.auth
from google.auth import impersonated_credentials
from google.cloud import storage
import os
# プロジェクトIDとバケット名を設定
PROJECT_ID = "your-project-id"
BUCKET_NAME = f"test-impersonation-{PROJECT_ID}"
# サービスアカウントAの認証情報を設定
os.environ['GOOGLE_APPLICATION_CREDENTIALS'] = 'sa-account-a-key.json'
# 元の認証情報を取得(サービスアカウントA)
source_credentials, project = google.auth.default()
print(f"元の認証情報: {source_credentials.service_account_email}")
# サービスアカウントBを借用
sa_b_email = f"sa-account-b@{PROJECT_ID}.iam.gserviceaccount.com"
sa_b_credentials = impersonated_credentials.Credentials(
source_credentials=source_credentials,
target_principal=sa_b_email,
target_scopes=['https://www.googleapis.com/auth/cloud-platform']
)
print(f"借用中間アカウント: {sa_b_email}")
# サービスアカウントCを借用(Bの認証情報を使用)
sa_c_email = f"sa-account-c@{PROJECT_ID}.iam.gserviceaccount.com"
sa_c_credentials = impersonated_credentials.Credentials(
source_credentials=sa_b_credentials,
target_principal=sa_c_email,
target_scopes=['https://www.googleapis.com/auth/cloud-platform']
)
print(f"最終借用アカウント: {sa_c_email}")
# サービスアカウントCの権限でCloud Storageにアクセス
try:
storage_client = storage.Client(credentials=sa_c_credentials)
bucket = storage_client.bucket(BUCKET_NAME)
# テストファイルをアップロード
blob = bucket.blob("test-file.txt")
blob.upload_from_string("Hello from impersonation chain!")
print(f"✅ 成功: サービスアカウントCの権限でバケット '{BUCKET_NAME}' にアクセスできました")
# ファイルをリスト
blobs = list(bucket.list_blobs())
print(f"バケット内のファイル: {[blob.name for blob in blobs]}")
except Exception as e:
print(f"❌ エラー: {e}")
実行結果
# 必要なライブラリをインストール
pip install google-auth google-cloud-storage
# 検証スクリプトを実行
python test_impersonation_chain.py
実行結果の例:
元の認証情報: sa-account-a@your-project-id.iam.gserviceaccount.com
借用中間アカウント: sa-account-b@your-project-id.iam.gserviceaccount.com
最終借用アカウント: sa-account-c@your-project-id.iam.gserviceaccount.com
✅ 成功: サービスアカウントCの権限でバケット 'test-impersonation-your-project-id' にアクセスできました
バケット内のファイル: ['test-file.txt']
まとめ
Google Cloudのサービスアカウント借用機能は、複数段階のチェーンを構築できることを確認しました。
ただし、借用チェーンを使う際は、セキュリティと管理の複雑さのバランスを考慮する必要があります。
本番環境では、必要最小限の借用に留め、適切な監査とモニタリングを実施することが重要です。
Discussion