背景
Google CloudでVPC Service Controls(VPC-SC)を有効化した際、思わぬ落とし穴にはまりました。
具体的には「VPC-SC有効プロジェクトのインフラ作業後、別プロジェクトのTerraformが突然動かなくなる」という事象です。
VPC-SCとは
VPC-SCはGoogle Cloudのセキュリティ機能で、Cloud StorageやFirestoreなどのAPIを「ペリメーター(境界)」で囲い、境界外からのアクセスをブロックします。
アクセス制御はホワイトリスト型で、許可するものを明示的に列挙し、それ以外はすべてデフォルトで拒否されます。
代表的な保護対象サービスの例:
storage.googleapis.com(Cloud Storage)firestore.googleapis.comaiplatform.googleapis.com(Vertex AI)run.googleapis.com(Cloud Run)secretmanager.googleapis.com
事象:別プロジェクトのterraform applyがブロックされる
前提となる構成
| プロジェクト | VPC-SC | 役割 |
|---|---|---|
| プロジェクトA | 有効 | VPC-SCを設定している側 |
| プロジェクトB | 無効 | 別の案件・用途のプロジェクト |
TerraformのstateファイルはそれぞれのプロジェクトのCloud Storageバケットで管理しています。
- プロジェクトBのconfig.tf
terraform {
backend "gcs" {
bucket = "project-b-tfstate"
prefix = "terraform/state"
}
}
このGCSバケットへのアクセスがVPC-SCによってブロックされます。
操作の流れ
- プロジェクトAのVPC-SCを含んだTerraformを実行するため、ADCのquota_projectを設定
- プロジェクトAへの
terraform apply→ 成功 - 同じプリンシパルを使うため、再ログインせずにプロジェクトBのTerraformを実行
terraform apply→ 403エラーでブロック
プロジェクトBはVPC-SCが有効ではない。それでもブロックされる。
発生するエラー
terraform init または terraform apply の冒頭でstateバケットへのアクセスが失敗し、以下のようなエラーが出力されます。
│ Error: error loading state: Failed to open state file at │ gs://project-b-tfstate/terraform/state/default.tfstate: │ googleapi: got HTTP response code 403 with body: │ <!--?xml version='1.0' encoding='UTF-8'?--> │ │ <code>SecurityPolicyViolated</code> │ Request violates VPC Service Controls. │ | | <details>Request is prohibited by organization's policy. │ vpcServiceControlsUniqueIdentifier: XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX</details>
IAMの権限は問題ないのに403が返る点、SecurityPolicyViolated というエラーコードと Request violates VPC Service Controls. というメッセージが特徴です。
vpcServiceControlsUniqueIdentifier はVPC-SC違反ログをGoogle Cloudコンソールで検索する際に使用できる識別子です。
対処方法
先に対処方法から紹介します。
プロジェクトAの作業前
gcloud auth application-default set-quota-project <VPC-SC有効プロジェクトID>
作業終了後(他プロジェクトに戻る前に必ず実施)
rm ~/.config/gcloud/application_default_credentials.json gcloud auth application-default login --disable-quota-project # quota_project未設定の状態で再取得
現在の設定確認
cat ~/.config/gcloud/application_default_credentials.json
注意点
gcloud config set billing/quota_project はgcloud CLI向けの設定で、Terraformには効きません。
Terraform(ADC)には gcloud auth application-default set-quota-project が必要です。
詳しい解説
結論から言うとブロックされているのはアクセス先(プロジェクトB)では無く、アクセス元(プロジェクトA)側でした。
仕組みを理解するには VPC-SCのデプロイで必要になるquota_project設定がVPC-SCの評価でどう扱われるかを知る必要があります。
quota_projectが持つ二つの役割
gcloud auth application-default set-quota-project を実行すると、~/.config/gcloud/application_default_credentials.json に以下のように記録されます。
{
"type": "authorized_user",
"quota_project_id": "project-a"
}
Terraformはこのファイルを読んでGoogle Cloud APIを呼び出すため、このフィールドが残っている限り、どのディレクトリで apply してもquota_project=project-aとしてリクエストが飛び続けます。
quota_project には二つの役割があります:
| 役割 | 説明 |
|---|---|
| ① 課金・クォータの帰属先 | そのAPIコールの費用・クォータをどのプロジェクトに計上するか |
| ② VPC-SCにおけるリクエストの発信元 | どのペリメーターから発信されたリクエストかの判定に使われる |
VPC-SC有効化前は①しか意味を持ちませんでしたが、VPC-SC有効化後は②の役割も発動します。
VPC-SCの評価(Egressポリシー)
quota_project=project-a を設定すると、ローカルマシンからのリクエストであっても「プロジェクトAのペリメーター内部から発信されたリクエスト」として扱われます。
terraform apply(プロジェクトB、quota_project=project-a) └─ storage.googleapis.com へのAPIコール ├─ IAMチェック: OK(アカウントに権限あり) └─ VPC-SCチェック ├─ リクエストの発信元: プロジェクトAのペリメーター内部(quota_projectによる帰属) ├─ アクセス先: プロジェクトBのbucket(ペリメーター外部) └─ Egressポリシー: ペリメーター内→外への通信はデフォルトでブロック └─ 明示的なEgress許可なし → BLOCKED (403)
「ペリメーター内部から外部へのデータ持ち出し(Egress)を防ぐ」というVPC-SCの基本原則が発動しているため、アクセス先がVPC-SC未設定のプロジェクトであっても同様にブロックされます。
プロジェクトAへのデプロイ時は同プロジェクト内のため問題なくapply出来たと言う訳です。
VPC-SC有効化前はなぜ問題なかったか
VPC-SC有効化前は、アクセス制御はIAMのみで行われていました。
(VPC-SCなし) terraform apply(quota_project=project-a) └─ GCS APIコール └─ IAMチェック: アカウントに権限があるか? → あればOK
quota_project はこの場合課金先・クォータ消費先を指定するだけのフィールドで、アクセス可否には影響しません。
VPC-SCを有効にすることで quota_project が「リクエストの発信元ペリメーター」を決定するコンテキストとしても扱われるようになり、同じ操作でブロックされるようになりました。これはVPC-SCが意図通りに機能している結果です。
まとめ
| 項目 | VPC-SCなし | VPC-SCあり |
|---|---|---|
| アクセス制御の主体 | IAMのみ | IAM + VPC-SC (独立した追加レイヤー) |
quota_project の役割 |
課金・クォータ先の指定のみ | ・課金/クォータ先 ・リクエストの発信元ペリメーター判定にも使われる |
| IAM通過後のブロック | なし | あり (VPC-SC Egressポリシーで拒否) |
| デフォルト動作 | 許可(IAMで制御) | 拒否 (明示的に許可されたもののみ通す) |
| アクセス先にVPC-SCがなくてもブロックされるか | なし | あり (発信元ペリメーターのEgressポリシーで評価されるため) |
VPC-SCは強力なセキュリティ機能ですが、ADCのquota_projectという普段意識しない設定がapplyに必要になり、かつ「リクエストの発信元ペリメーター」として扱われブロックが発生する点は見落としがちです。
作業後のADCリセットを手順に組み込んでおくことをおすすめします。