GCP Project Setup(impersonation方式・鍵レス)
概要
このスキルは、新しいリポジトリを GCP 複数プロジェクト環境に安全に追加するための impersonation(鍵レス)方式セットアップを自動化する。
秘密鍵をディスクに保存せず、ユーザー認証を土台にサービスアカウント(SA)になりすます方式。
cd するだけでそのリポジトリ専用の GCP 認証が有効になる。
CLI と SDK は認証経路が違う(重要)
- gcloud / bq CLI は
.mise.tomlのCLOUDSDK_AUTH_IMPERSONATE_SERVICE_ACCOUNTを読む。- Node / Python の Google SDK はこの変数を読まない。ADC (
~/.config/gcloud/application_default_credentials.json) を見る。- ADC はグローバル単一ファイルなので複数リポジトリで衝突する。 そこで per-repo ADC ファイルを分離し、
.mise.tomlのGOOGLE_APPLICATION_CREDENTIALSで切り替える(Step 6.5)。SDK を使うリポジトリでは必須。「鍵レス」の正確な意味:SA キー(JSON 鍵)はディスクに置かない。ただし per-repo ADC には ユーザー本人の OAuth refresh_token が埋め込まれる(SA キーより低リスクだが長命資格情報ではある)。
前提確認
作業開始前に以下を確認すること:
# ユーザー認証が生きているか
gcloud auth print-access-token 2>&1 | head -1
# → トークンが返れば OK。エラーなら `gcloud auth login` を先に実行
認証が切れていたらユーザーに gcloud auth login の実行を依頼して止まること。
引数
| 引数 | 必須 | 例 | 説明 |
|---|---|---|---|
| リポジトリ名 | ✅ | effectuation_score |
~/code/ 以下のディレクトリ名 |
| GCPプロジェクトID | ✅ | innovation-score |
GCP コンソールのプロジェクトID |
| 権限セット | ❌ | bigquery+gcs(デフォルト)/ vertexai |
付与する権限の種類 |
実行ステップ
Step 1: 変数セット
REPO_NAME="<リポジトリ名>"
PROJECT_ID="<GCPプロジェクトID>"
USER_ACCOUNT="<あなたのGoogleアカウント>"
SA_NAME="${REPO_NAME//_/-}-local-dev" # アンダースコアをハイフンに変換
SA_EMAIL="${SA_NAME}@${PROJECT_ID}.iam.gserviceaccount.com"
REPO_PATH="$HOME/code/${REPO_NAME}"
SA 名はアンダースコアが使えないため
_→-に変換する。
Step 2: SA 作成
gcloud iam service-accounts create "${SA_NAME}" \
--display-name="Local Dev (impersonation)" \
--project="${PROJECT_ID}"
既存の場合は already exists エラーが出るが続行して問題ない。
Step 3: 権限付与
デフォルト(bigquery+gcs):
for ROLE in \
"roles/bigquery.dataEditor" \
"roles/bigquery.jobUser" \
"roles/serviceusage.serviceUsageConsumer" \
"roles/storage.objectAdmin"; do
gcloud projects add-iam-policy-binding "${PROJECT_ID}" \
--member="serviceAccount:${SA_EMAIL}" \
--role="${ROLE}" \
--condition=None \
--format="value(etag)"
done
bigquery.dataEditorだけではクエリ実行ができない。bigquery.jobUserが必ず必要。serviceusage.serviceUsageConsumerは SDK/quota project 経由で API を呼ぶ際に必須 (無いとCaller does not have required permission to use project ...で失敗する)。
vertexai オプション追加時(上記に加えて):
gcloud projects add-iam-policy-binding "${PROJECT_ID}" \
--member="serviceAccount:${SA_EMAIL}" \
--role="roles/aiplatform.user" \
--condition=None
Step 4: TokenCreator 権限(impersonation の核心)
# ⚠️ --project を必ず明示すること。省略すると active config のプロジェクトを見に行って失敗する
CLOUDSDK_CORE_PROJECT="${PROJECT_ID}" \
gcloud iam service-accounts add-iam-policy-binding "${SA_EMAIL}" \
--member="user:${USER_ACCOUNT}" \
--role="roles/iam.serviceAccountTokenCreator" \
--project="${PROJECT_ID}"
Step 5: IAM 反映待ち(最大 60 秒)
IAM 変更は即時反映されない。トークンが取れるまでリトライする:
echo "IAM 反映待ち..."
for i in $(seq 1 6); do
TOKEN=$(gcloud auth print-access-token \
--impersonate-service-account="${SA_EMAIL}" 2>/dev/null)
if [ -n "$TOKEN" ]; then
echo "✅ ${i}回目で反映完了"
break
fi
echo " ${i}/6 まだ反映中... (10秒待機)"
sleep 10
done
[ -z "$TOKEN" ] && echo "❌ 60秒経過しても反映されず。数分後に再試行を" && exit 1
Step 6: .mise.toml 作成
cat > "${REPO_PATH}/.mise.toml" << EOF
# ${REPO_NAME} (${PROJECT_ID}) ローカル開発環境
# impersonation方式: 秘密鍵を持たずSAになりすます
[env]
# SDK(Python/R/クライアントライブラリ)が読む既定プロジェクト
GOOGLE_CLOUD_PROJECT = "${PROJECT_ID}"
# gcloud / bq CLI が読む既定プロジェクト(CLIはGOOGLE_CLOUD_PROJECTを見ない)
CLOUDSDK_CORE_PROJECT = "${PROJECT_ID}"
# quota/課金プロジェクトを固定(ADC使用時の誤プロジェクト参照を防止)
GOOGLE_CLOUD_QUOTA_PROJECT = "${PROJECT_ID}"
# SDK・gcloud がこのSAになりすます(鍵レス)※CLIのみ有効。SDKはStep 6.5のADCを使う
CLOUDSDK_AUTH_IMPERSONATE_SERVICE_ACCOUNT = "${SA_EMAIL}"
# SDK(Node/Python)用 ADC。CLIのIMPERSONATE変数はSDKに効かないため必須(Step 6.5で生成)
GOOGLE_APPLICATION_CREDENTIALS = "${HOME}/.config/gcloud/${REPO_NAME}_adc.json"
EOF
GOOGLE_CLOUD_PROJECTとCLOUDSDK_CORE_PROJECTは別物。両方必要。 SDK(Python/R)は前者、gcloud/bq CLI は後者を参照する。GOOGLE_APPLICATION_CREDENTIALSは SDK 用 ADC のパス。実体は Step 6.5 で生成する。
Step 6.5: SDK 用 per-repo ADC を生成(SDK を使うリポジトリは必須)
CLOUDSDK_AUTH_IMPERSONATE_SERVICE_ACCOUNT は gcloud/bq CLI 専用で、Node/Python の
Google SDK には効かない。SDK は ADC を見るが、グローバル ADC は単一ファイルのため複数
リポジトリで衝突する。横断ヘルパーで per-repo ADC(~/.config/gcloud/<repo>_adc.json)を
生成する。ブラウザ再ログインは不要(グローバル ADC の refresh_token を共有して生成する)。
通常は repo-local の入口として mise run reauth を使い、その裏側でこの横断ヘルパーを呼ぶ。
# 通常の入口
mise run reauth
# 横断ヘルパーを直接呼ぶのは、共通フローを明示的に使いたいときだけ
bash ~/.agents/skills/origin-gcp-project-setup/refresh_adc.sh
このヘルパーは ~/code/*/.mise.toml を走査し、CLOUDSDK_AUTH_IMPERSONATE_SERVICE_ACCOUNT
を持つ全リポジトリの per-repo ADC を生成・更新し、GOOGLE_APPLICATION_CREDENTIALS 行が
無ければ .mise.toml に追記する。最後にグローバル ADC を素のユーザー認証へ戻す
(未設定リポジトリが誤った SA で動くのを防ぐ)。
利用者向けの通常導線は各 repo の mise run reauth で、repo-local に起動しても
裏側では全 repo の per-repo ADC 整合性をまとめて更新しうる。
前提:authorized_user の source ADC が必要。active gcloud config に
auth/impersonate_service_accountが永続設定されている環境では、 ふつうにgcloud auth application-default loginを打つとimpersonated_service_accountADC ができてしまうことがある。 その場合はbash ~/.agents/skills/origin-gcp-project-setup/re-auth.shを使い、 一時CLOUDSDK_CONFIGで user ADC を取り直す。gcloudが PATH に無い constrained shell でも、re-auth.sh/refresh_adc.shは/opt/homebrew/share/google-cloud-sdk/bin/gcloudなどの代表的な設置先を自動検出する。
Step 7: mise trust
cd "${REPO_PATH}" && /opt/homebrew/bin/mise trust .mise.toml
Step 8: end-to-end 検証
cd "${REPO_PATH}"
eval "$(/opt/homebrew/bin/mise env -s bash)"
echo "=== プロジェクト確認 ==="
echo "GOOGLE_CLOUD_PROJECT: $GOOGLE_CLOUD_PROJECT"
echo "CLOUDSDK_CORE_PROJECT: $CLOUDSDK_CORE_PROJECT"
echo "IMPERSONATE: $CLOUDSDK_AUTH_IMPERSONATE_SERVICE_ACCOUNT"
echo "GAC(SDK用ADC): $GOOGLE_APPLICATION_CREDENTIALS"
echo ""
echo "=== CLI 実行確認(bq が誰として動くか)==="
bq query --use_legacy_sql=false --format=pretty \
'SELECT SESSION_USER() AS running_as' 2>&1 | grep -vE "^$" | tail -6
echo ""
echo "=== SDK 実行確認(Node が誰として動くか)==="
node -e "const {BigQuery}=require('@google-cloud/bigquery'); new BigQuery({projectId:process.env.GOOGLE_CLOUD_PROJECT}).query('SELECT SESSION_USER() AS u').then(([r])=>console.log('SDK running_as:', r[0].u)).catch(e=>console.error('ERR:', e.message))"
期待する出力(CLI・SDK 両方):
| running_as |
| <sa-name>@<project-id>.iam.gserviceaccount.com |
SDK running_as: <sa-name>@<project-id>.iam.gserviceaccount.com
ユーザーアカウント(会社ドメインのメールアドレス)が表示されたら impersonation が効いていない。
CLI は SA だが SDK だけユーザーになる場合は Step 6.5 の per-repo ADC 未生成
(refresh_adc.sh を実行)。
完了後の報告
以下をユーザーに伝える:
- 作成した SA:
${SA_EMAIL} - 付与した権限: 付与したロール一覧
- 作成ファイル:
${REPO_PATH}/.mise.toml、~/.config/gcloud/${REPO_NAME}_adc.json(SDK用ADC) - 毎日の使い方:
cd ~/code/${REPO_NAME}するだけで CLI も SDK も自動切替 - 再認証が必要な場合(RAPT/refresh_token 失効時のみ・24h ポリシーまたは数週間〜数ヶ月に1回):
これ1コマンドでbash ~/.agents/skills/origin-gcp-project-setup/re-auth.shgcloud auth login --update-adc・全リポジトリの per-repo ADC 再生成をまとめて実行する。 Google Ads OAuth も更新が必要な場合は--adsオプションを追加:bash ~/.agents/skills/origin-gcp-project-setup/re-auth.sh --adsper-repo ADC は生成時の refresh_token を焼き込むため、再認証では自動更新されない。
re-auth.shが内部でrefresh_adc.shを呼び出し、全リポジトリ分を一括再生成する。 active gcloud config に SA impersonation が永続設定されていても、re-auth.shは一時CLOUDSDK_CONFIGを使うためその影響を受けない。 通常の入口はbash ... re-auth.shではなく各 repo のmise run reauth。
トラブルシューティング
| エラー | 原因 | 対処 |
|---|---|---|
NOT_FOUND: Service account ... does not exist |
--project 省略で active config のプロジェクトを参照 | Step 4 の CLOUDSDK_CORE_PROJECT 指定を確認 |
PERMISSION_DENIED: Failed to impersonate |
IAM 未反映 or TokenCreator 未付与 | Step 5 のリトライを待つ。それでも失敗なら Step 4 を再実行 |
SESSION_USER() がユーザーアカウントを返す |
impersonation が効いていない | CLOUDSDK_AUTH_IMPERSONATE_SERVICE_ACCOUNT 環境変数を確認 |
bq: Reauthentication failed |
土台のユーザー認証が期限切れ(RAPT など) | bash ~/.agents/skills/origin-gcp-project-setup/re-auth.sh を実行 |
SDK だけ Caller does not have required permission to use project / serviceusage エラー |
per-repo ADC 未生成。SDK がグローバル ADC(別 SA)を見ている | Step 6.5 の refresh_adc.sh を実行し、.mise.toml に GOOGLE_APPLICATION_CREDENTIALS があるか確認 |
| CLI は SA だが SDK だけユーザー/別 SA で動く | GOOGLE_APPLICATION_CREDENTIALS 未設定 or 指す ADC が古い |
.mise.toml を確認し refresh_adc.sh を再実行 |
application_default_credentials.json must be authorized_user ... got 'impersonated_service_account' |
active gcloud config の auth/impersonate_service_account が ADC 作成に混入 |
re-auth.sh を使って一時 CLOUDSDK_CONFIG で user ADC を作る |
gcloud: No such file or directory |
constrained shell の PATH に Google Cloud SDK が無い | re-auth.sh / refresh_adc.sh の自動検出を使う。手動なら SDK の bin を PATH に追加 |