GCP VPC Service Controlsの「境界」を突破せよ:アクセスレベルとingress/egressルールの泥臭い現実
クラウドアーキテクトとして多くの現場を見てきましたが、GCPの「VPC Service Controls(VPC-SC)」ほど、エンジニアの心臓をバクバクさせる機能は他にありません。
「あれ、この設定を入れた瞬間に本番環境のAPIが全滅したぞ?」
そんな冷や汗もののトラブルは、VPC-SCの境界定義を甘く見たときに起こります。今日は、ドキュメントの表面をなぞるだけでは決して見えてこない、VPC-SCのアクセスレベル評価と、イングレス/エグレスルールの深淵に切り込みます。
—
1. VPC-SCは「ファイアウォール」ではない
まず大前提を共有しましょう。VPC-SCは、いわゆるL3/L4のファイアウォールとは全く別物です。これは「APIリクエストのコンテキスト」を評価する、Google Cloudのデータプレーンに組み込まれた認可レイヤーです。
パケットがどのIPから来たかだけでなく、「そのユーザーは誰か」「どのデバイスか」「そのリクエストはサービス境界をまたぐ正当な理由があるか」を、Googleのバックエンドが超高速で判定しています。
—
2. 「アクセスレベル」の評価ロジックを読み解く
アクセスレベルは、リクエストが「境界内」として許容されるかどうかのゲートキーパーです。ここでのポイントは、「条件はANDではなく、原則ORで評価される」という点です。
よくある落とし穴:デバイスポリシー
「特定のIPレンジからのアクセスのみ許可」といった単純な条件だけでなく、Access Context Managerでデバイスポリシーを組み合わせることが多いはずです。ここで最もハマるのが、「デバイスが暗号化されているか」といった属性が、正しくクライアントから送信されるChromeなどのブラウザ経由でないと判定できないケースです。
# Access Level の定義例 (YAML形式)
- name: "accessPolicies/12345/accessLevels/Corporate_Office"
title: "Corporate Office Access"
basic:
conditions:
- ipSubnetworks:
- "203.0.113.0/24" # オフィス拠点のグローバルIP
members:
- "user:dev-team@example.com"
# ここにデバイスポリシーを追加すると、さらに厳密になる
devicePolicy:
requireScreenLock: true
allowedEncryptionStatuses:
- ENCRYPTED
現場のエンジニアがやりがちなミスは、ipSubnetworksの範囲を狭めすぎて、NATを通った後のIPアドレスを考慮漏れすることです。必ず出口のグローバルIPを正確に特定してください。
—
3. 境界を越えるための「イングレス・エグレスルール」設計
VPC-SCの境界をまたぐ通信は、標準ではすべて遮断されます。ここで登場するのが、特定のプロジェクトやサービスを「例外的に許可する」ためのイングレス(Ingress)およびエグレス(Egress)ルールです。
イングレスルール:外から境界内へのアクセス
外部プロジェクトのサービスアカウントが、境界内の Cloud Storage にアクセスする場合などに使います。
# Ingress Rule の設定例
ingressPolicies:
- ingressFrom:
sources:
- accessLevel: "accessPolicies/12345/accessLevels/Corporate_Office"
operations:
- methodSelectors:
- method: "google.storage.objects.get" # 具体的にメソッドを指定して最小権限に
serviceName: "storage.googleapis.com"
ingressTo:
resources:
- "projects/111222333" # 境界内のプロジェクトID
エグレスルール:境界内から外へのアクセス
ここが最も重要です。境界内のVMから、外部のAPIを叩く際、egressToでそのサービスを指定しないと、403 Forbiddenで弾かれます。
# Pythonでのトラブルシューティング用リクエスト
import requests
# 境界内のVMから外部APIへ
url = "https://external-api.example.com/v1/data"
headers = {"Authorization": "Bearer <TOKEN>"}
# VPC-SCにブロックされると、レスポンスコードは 403
# ログを確認するには、GCPコンソールの「VPC Service Controls」の拒否ログを見るのが鉄則
response = requests.get(url, headers=headers)
print(f"Status Code: {response.status_code}")
—
4. 現場のシニアが教える「デバッグの鉄則」
VPC-SCの設定変更は、常に「ドライランモード(監査モード)」から始めるのが鉄則です。いきなりEnforceしてはいけません。
1. ログを信じろ
Google Cloudの「ログエクスプローラ」で、protoPayload.metadata.violationReason を検索してください。ここには、「なぜ拒否されたか」の理由(例: NO_MATCHING_ACCESS_LEVEL)が克明に記されています。
2. 「境界」の範囲を見直す
複数のサービスを一つの境界に詰め込みすぎると、ルールが複雑化して管理不能になります。「マイクロサービスごとに境界を分ける」という戦略も、運用コストとのトレードオフを考えて検討してください。
3. APIリクエストの粒度を意識する
methodSelectorsで * を指定して全許可にするのは、セキュリティ的にNGです。必要なAPIメソッド(例: storage.buckets.get)だけを記述する癖をつけてください。
—
まとめ:ネットワークエンジニアの矜持
VPC-SCは、設定を間違えれば「動かない」という極めて厳しい結果を突きつけてきます。しかし、これは「意図しない通信」を物理的に遮断するための最強の防壁です。
パケットが境界のゲートを叩くとき、アクセスレベルがそれを審査し、ルールが通行許可証を与える。この一連のフローを脳内でイメージできるようになれば、あなたはもうVPC-SCのマスターです。
複雑な設定に立ち向かう皆さんの健闘を祈ります。もし詰まったら、まずは焦らず Dry Run ログを確認すること。それが、トラブルを最短で解決する唯一の道です。
コメント