VPC Service Controls(VPC-SC)をEnforced Modeに移行する際、「Request is prohibited by organization’s policy」エラーに遭遇することは珍しくありません。本記事では、実際の移行プロジェクトで経験したトラブルシューティング手法と、体系的な問題解決アプローチを解説します。
典型的なエラーパターン
GitHub Actions実行時のエラー
1
2
| Error 403: Request is prohibited by organization's policy.
For more information on VPC Service Controls, see https://cloud.google.com/vpc-service-controls/docs
|
このエラーは、以下の操作で頻繁に発生します:
terraform init
時のGCS state bucket アクセスterraform plan/apply
時の各種Google Cloud API呼び出し- BigQuery、Cloud Storage、Secret Manager等のリソース操作
段階的トラブルシューティング手法
ステップ1: Cloud Loggingでの詳細調査
まず、具体的にどのリクエストが拒否されているかをCloud Loggingで確認します:
1
2
3
4
| # Cloud Loggingクエリ例
protoPayload.serviceName="vpcservicecontrols.googleapis.com"
protoPayload.methodName="google.cloud.vpcservicecontrols.v1.VpcServiceControlsServiceV1.CheckViolation"
severity="ERROR"
|
重要な確認ポイント:
1
2
3
4
5
6
7
8
9
10
| {
"protoPayload": {
"authenticationInfo": {
"principalEmail": "github-actions-apply-dev@main-project-dev.iam.gserviceaccount.com"
},
"serviceName": "storage.googleapis.com",
"methodName": "google.storage.objects.get",
"resourceName": "projects/_/buckets/main-project-dev-tfstate/objects/terraform.tfstate"
}
}
|
これらの情報から、誰が、どのサービスの、どのメソッドでアクセス拒否されているかを特定できます。
ステップ2: Access Level設定の確認
サービスアカウントがAccess Levelに含まれているかを確認:
1
2
3
4
5
6
7
8
9
10
11
12
| # access_level定義の確認
locals {
access_level = {
service_accounts = {
main_project = [
# このリストに該当のサービスアカウントが含まれているか?
var.service_accounts_main_project["github-actions-apply-${var.env}"].member,
var.service_accounts_main_project["github-actions-plan-${var.env}"].member,
]
}
}
}
|
確認コマンド:
1
2
3
4
5
| # Terraform planで実際に作成されるリソースを確認
terraform plan -target=module.access_level
# 特定のAccess Levelの内容を確認
gcloud access-context-manager levels describe [ACCESS_LEVEL_NAME] --policy=[POLICY_ID]
|
ステップ3: Service Perimeter設定の確認
Access LevelがService Perimeterに含まれているかを確認:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
| # service_perimeter設定の確認
locals {
service_perimeter = {
default = {
access_levels = concat([
var.access_level_office_and_vpn_ips.id,
# GitHub Actions用のAccess Levelが含まれているか?
var.access_level_service_accounts["main_project"].id,
var.access_level_service_accounts["infrastructure_repo"].id,
])
resources = [
"projects/${var.google_projects["main-project-${var.env}"].number}",
"projects/${var.google_projects["infrastructure-repo-${var.env}"].number}",
]
}
}
}
|
ステップ4: リソースとプロジェクトの対応確認
エラーログのresourceNameとService Perimeterの保護対象が一致しているかを確認:
1
2
3
4
5
| # プロジェクト番号の確認
gcloud projects describe PROJECT_ID --format="value(projectNumber)"
# Service Perimeterの保護対象確認
gcloud access-context-manager perimeters describe [PERIMETER_NAME] --policy=[POLICY_ID]
|
よくある設定ミスと解決法
1. Access Levelは定義されているがService Perimeterに含まれていない
症状: Access Level自体は作成されているが、アクセスが拒否される
原因: Service Perimeterのaccess_levelsリストにAccess Levelが含まれていない
解決法:
1
2
3
4
5
| # Service Perimeterにaccess_levelを追加
access_levels = concat([
var.access_level_office_and_vpn_ips.id,
+ var.access_level_service_accounts["infrastructure_repo"].id,
])
|
2. モジュール間の変数連携エラー
症状: 「Reference to undeclared input variable」エラー
原因:
- access_levelモジュールでoutputが定義されていない
- service_perimeterモジュールでvariableが宣言されていない
- メインファイルでの変数受け渡しが漏れている
解決法: Terraformモジュール設計のベストプラクティスに従った変数連携の実装
3. プロジェクト番号とプロジェクトIDの混同
症状: 設定は正しく見えるがアクセスが拒否される
原因: VPC-SCはプロジェクト番号で動作するが、設定でプロジェクトIDを使用している
解決法:
1
2
3
4
5
| # Good: プロジェクト番号を使用
resources = ["projects/${var.google_projects["infrastructure-repo-${var.env}"].number}"]
# Bad: プロジェクトIDを使用
resources = ["projects/infrastructure-repo-dev"]
|
効果的なデバッグワークフロー
1. 段階的な権限追加
最初からすべての権限を設定せず、エラーログを見ながら段階的に追加:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
| # 最初は最小限の権限から開始
operations = {
"storage.googleapis.com" = {
methods = [
"google.storage.objects.get", # まずはこれだけ
]
}
}
# エラーログを確認して必要な権限を追加
operations = {
"storage.googleapis.com" = {
methods = [
"google.storage.objects.get",
"google.storage.objects.list", # 追加
"google.storage.objects.create", # 追加
]
}
}
|
1
2
3
4
5
6
7
| # モジュールごとの検証
terraform plan -target=module.access_level
terraform plan -target=module.service_perimeter
terraform plan -target=module.ingress_policy
# 全体の検証
terraform plan
|
3. リアルタイムログ監視
1
2
3
| # Cloud Loggingでリアルタイム監視
gcloud logging tail "protoPayload.serviceName=vpcservicecontrols.googleapis.com" \
--filter="severity=ERROR"
|
成功事例:実環境での解決プロセス
実際のプロジェクトでの解決プロセスを時系列で紹介:
1. 問題発生(Day 1)
- GitHub Actions実行時に403エラー発生
- すべてのTerraform operationが実行不可
2. 原因調査(Day 1-2)
- Cloud Loggingでエラーの詳細を分析
- 他環境との設定差分を特定
- Access LevelがService Perimeterに含まれていないことを発見
3. 修正実装(Day 2-3)
- 対象modulesにaccess_level_service_accountsのサポートを追加
- Service PerimeterにAccess Levelを追加
- モジュール間の変数連携を修正
4. 検証完了(Day 3)
- terraform plan/apply が正常実行
- VPC-SC違反ログが完全消滅
- 全てのGitHub Actionsワークフローが正常化
まとめ
VPC Service Controls Enforced Mode移行時のトラブルシューティングでは、以下のアプローチが効果的です:
- Cloud Loggingによる詳細分析: エラーの根本原因を特定
- 段階的な設定確認: Access Level → Service Perimeter → リソース対応の順序で確認
- 体系的なデバッグ: モジュールごとの個別検証から全体検証へ
- エラーベースの権限追加: 必要最小限から段階的に権限を拡張
VPC-SCの設定は複雑ですが、体系的なアプローチを取ることで、効率的に問題を解決できます。特に、Cloud Loggingの活用は問題の早期発見と解決に不可欠です。
今後VPC-SC移行を予定している組織は、事前にこれらのトラブルシューティング手法を把握しておくことで、スムーズな移行を実現できるでしょう。