
この記事はenechain Advent Calendar 2025の24日目の記事です。
こんにちは、enechainのeSquare Live ecosystemチームのJingです。
皆さんはGKEを利用している時に、原因不明の接続の失敗に悩まされた経験は無いでしょうか?
本記事では、複雑なGoogle Cloudの挙動を整理するためのフレームワークとして、「繋がらない」問題の裏側、4つのプレーンについて紹介したいと思います。
この記事の対象読者:
この記事は、次のようなエンジニアを想定しています。
- GKE上でワークロードを動かしている
- Cloud SQL、Pub/Sub、Secret Manager、Cloud StorageなどのGoogle Cloudサービスを呼び出している
PermissionDeniedやタイムアウト、よく分からない接続失敗に何度も悩まされてきた
「1回のAPIコールなのに、なんでこんなにややこしいの?」と感じている方の参考になればと思います。
この記事から得られるもの:
読み終わる頃には、次のことができるようになることを目指しています。
- GKE上のPodがGoogle Cloudサービスに対して行う1つの操作が、4つの独立したcontrol planeで順に判定されることを理解する
- 具体的なエラーや失敗を、どのcontrol planeで起きているかにマッピングできる
- そのマッピングを使って、当てずっぽうではなく、体系立ててデバッグできるようになる
- はじめに
- Network Control Plane: ネットワーク到達性はあるか?
- Identity Control Plane: このリクエストを投げているのは誰か?
- Authorization Control Plane: このアイデンティティは何をしてよいか?
- Resource Control Plane: 妥当な対象リソースは存在するか?
- まとめ: 4つのプレーンを通過して
はじめに
GKE上のPodがGoogle Cloudサービスを呼び出すとき、プラットフォームの内部では、次の4段階のバリデーションが順に行われています。
Network Control Plane
サービスエンドポイントへのネットワーク到達性はあるか?
Identity Control Plane
このリクエストを行っているのは、検証可能なGoogleアイデンティティ(誰)か?
Authorization Control Plane
そのアイデンティティに対して、このリソースへのこの操作は許可されているか?
Resource Control Plane
操作対象となるリソースが存在するか?また、そのリソースの状態は適切か?
リクエストが成功するのは、この4つすべてのバリデーションをクリアしたときだけです。どこか1箇所でも失敗すると、エラーが返されます。
この記事の残りでは、次の例を通して各プレーンを見ていきます。
GKE上のPodがPub/Subと通信しようとしている。
途中で、Cloud SQLやCloud Storageなど他のサービスにもこのモデルをどう一般化できるかを簡単に触れます。
Network Control Plane: ネットワーク到達性はあるか?
アプリケーションの視点では、GKE上のPod → Pub/Subのリクエストは「Pub/SubへのAPIコール」です。
一方、プラットフォームの視点では、それはネットワークトラフィック、即ちIPヘッダ(送信元・宛先IP、プロトコル)やTCP/UDPヘッダ(ポート番号)を持つパケットの集合にすぎません。
このパケットが目的地に届くか否かは、VPC、Firewall、Private Google Access (PGA)などで構成される「Network Control Plane」によって厳密に検証されます。この制御プレーンがパケットの整合性を確認し、ネットワーク到達性を許可して初めて、通信が成立するのです。
基本となる構成要素
VPC: ネットワーク境界
Virtual Private Cloud (VPC)は、Network Control Planeの「土台」であり、論理的に隔離されたグローバルなネットワーク空間を定義します。
- プライベートIPアドレス空間: このVPC内で使用可能なIPアドレスの範囲
- トラフィックの分離境界: インターネットや他のVPCから隔離された環境
VPCは最初に「このパケットは、私の管理下にある空間のものか?」を定義します。
サブネットとルート: アドレスと経路
VPCという広大な空間の中で、トラフィックが実際にどこに存在し、どこへ向かうべきかを決定します。
サブネット: VPCを地域ごとの具体的なIPブロックに分割する。GKEのPodやNodeは必ず特定のサブネットに紐づき、IPアドレスが付与される
ルート: パケットの宛先を見て、次の問いに答える
「その宛先へ到達するための有効なネクストホップ(ゲートウェイやピアリング先)は定義されているか?」
もし適切なルートが存在しなければ、Network Control Planeは有効な経路がないと判断し、パケットの転送を許可しません。
ファイアウォールルール: トラフィックの許可証
「道」があっても、「通行許可」があるとは限りません。ファイアウォールは、パケットの属性(五元組)に基づいて厳格なセキュリティチェックを行います。
検証項目: 送信元IPアドレス、宛先IPアドレス、プロトコル、ポート番号
判定ロジック: 優先度順にルールを評価し、明示的なallowがない限り、暗黙の拒否ルールによってパケットはドロップされる
つまり、ファイアウォールはNetwork Control Planeにおける「検問所」として機能し、許可されたトラフィックのみを通過させます。
境界の拡張: マルチプロジェクトとGoogle管理サービスへの接続
現実のシステム構成が単一のVPCだけで完結することは稀です。Network Control Planeは、プロジェクトの境界を越えるトラフィックや、VPCの外側にあるGoogle管理サービス(Pub/Sub等)へのアクセスについても、厳格なルールに基づいて検証します。
Shared VPC: 管理境界とネットワーク境界の分離
大規模な組織では、ガバナンスや権限分離を目的として、ネットワーク基盤とアプリケーション(サービス)を別々のGoogle Cloudプロジェクトで管理するのが一般的です。
Shared VPCは、このようにプロジェクトが分かれていても、複数の「サービスプロジェクト」が単一のネットワーク境界である「ホストVPC」を共有可能にする仕組みです。具体的には、ホストVPC内のサブネットがサービスプロジェクトへ共有され、GKE上のPod等はそのサブネットのIPアドレスを使用して稼働します。
そのため、プロジェクトの壁を越えていても、パケットはホストVPC上で定義されたルートテーブルとファイアウォールルールに基づいて一元的に検証されます。
Network Control Planeの視点では:
同一ネットワークとしての認識: GKE上のPodがどのサービスプロジェクトに所属していようと、ホストVPCのサブネットに属している限り、それは「ホストVPCの内側にあるリソース」として扱われる
一元的なセキュリティ施行: 通信の可否を決めるのは「ホストVPC上のファイアウォールルール」である。ここで許可されないパケットは、たとえ同じ組織内の通信であってもドロップされる
VPCピアリング: 別々のVPCをつなぐ
VPCピアリングは、2つの独立したVPC間を接続し、Googleの内部ネットワークを経由してプライベートIPアドレスによる相互通信を可能にする仕組みです。
Network Control Planeの視点では:
ピアリングされたVPCを「拡張されたネットワーク」と見なしますが、通信を成立させるには双方向の合意と許可が必須条件となります。
ルート交換: 双方のVPCが互いのIPレンジ(CIDR)を正しく認識し、ルート情報のインポート/エクスポート設定が双方向で有効になっているかを検証する
ファイアウォール: ピアリングは「接続」を提供するだけで、両側のVPCのファイアウォールルールで、相手側のIPレンジからのトラフィックが明示的に許可されているかを検証する
例えば、GKE上のPodからCloud SQLをプライベートIPアドレスで利用するPrivate Services Accessも、技術的な実体はこのVPCピアリングです。Cloud SQLインスタンスはGoogle管理の「プロデューサーVPC」内に作成されます。GKEクラスタのVPC内で予約したIPレンジ(例:10.x.x.x/24)が割り当てられ、両VPC間に自動的にピアリング接続が確立されます。
Private Google Access: 内部から外部への抜け道
Pub/SubやCloud StorageなどのGoogleマネージドサービスは、VPCの内部ではなく、Googleのパブリック領域にエンドポイント(外部IPアドレス)を持ちます。そのため、通常これらのサービスへアクセスする際は、インターネット経由での通信が必要になります。
しかし、外部IPアドレスを持たない(プライベートIPアドレスのみの)GKE上のPodが、どうやってこれらにアクセスするのでしょうか? その答えの1つがPrivate Google Access(PGA)です。これは、特定のサブネットに対して「Google APIへの内部経路」を有効化する機能です。
Network Control Planeの観点では:
宛先はパブリックIPアドレスのまま: パケットの宛先はあくまでPub/Subの「パブリックIPアドレス」である
経路の変更: 送信元サブネットでPGAが有効であれば、そのパケットをインターネットゲートウェイへは送らず、Googleの内部バックボーンネットワークを経由してサービスへ直接転送する
可観測性: VPC Flow Logsによる検証
適切なルーティングやファイアウォールの許可設定が欠落している場合、パケットは「到達不能」としてNetwork Control Planeに行き手を阻まれ、闇に葬られます。
アプリケーションから見た症状
Network Control Planeでのドロップは、アプリケーション視点では「沈黙」として観測されます。
タイムアウト: パケットが黙って捨てられるため、応答が返ってきません
汎用的なネットワークエラー:
No route to hostやNetwork unreachableなど
ここで重要なシグナルは、「HTTP 401/403などの認証エラーが一切出てこない」ということです。これは、トラブルシューティングのフローチャートにおいて、問題がアイデンティティ層ではなく、「まだネットワーク層にある」ことを示す決定的な証拠となります。
解決策: VPC Flow Logs
この「沈黙したドロップ」を可視化する1つの手段がVPC Flow Logsです。これを有効にすることで、Network Control Plane上の事実を確認できます。
判定結果: そのフローは許可されたか、拒否されたか?
原因の特定: どのファイアウォールルールIDがその判定を下したか?
通信の詳細: 送信元/宛先のIPアドレスとポート番号は正しいか?
トラブルシューティングの際、ログにDENYが記録されていれば、それはNetwork Control Planeが意図通りにパケットを遮断したことを意味します。修正すべきはIAMではなくファイアウォールやルーティング設定であると即座に判断できます。
Identity Control Plane: このリクエストを投げているのは誰か?
ネットワーク到達性が確保されたことで、パケットは無事にPub/Subの「玄関」までたどり着きました。しかし、まだドアは開きません。
ここでバトンを受け取るのが「Identity Control Plane」です。このレイヤーでは、プラットフォームの関心対象が「IPアドレス(どこから来たか)」から「クレデンシャル(誰なのか)」へと変化します。
基本となる構成要素
このフェーズを理解するには、まず「異なる2つのアイデンティティ」と、それを繋ぐ「橋」を理解する必要があります。
2つの世界のアイデンティティ: KSAとGSA
GKE上のPodがPub/Subと連携する際、それぞれ異なるレイヤーに属するアイデンティティが登場します。
Kubernetes Service Account (KSA): これはGKEクラスタの内部でのみ存在し、意味を持つアイデンティティである。PodはこのKSAを持って生まれるが、Pub/SubのAPIはこのGKEクラスタの内部のアイデンティティを知らない
Google Service Account (GSA): これはGKEの外側、すなわちGoogle CloudプロジェクトのIAMレイヤーに存在するアイデンティティである。Pub/SubやGCSなどの権限管理は、すべてこのGSAに対して行われる
つまり、PodがPub/Subにアクセスしようとした時、「言葉(プロトコル)は通じるが、身分証(トークン)が通用しない」という状況が発生します。
Workload Identity: 動的かつ短命なアイデンティティ
この「架け橋」の役割を果たすのがWorkload Identityです。
これは、KSAとGSAを紐付けることで、「KSAの身分証を持つ者には、一時的にGSAとして振る舞うことを許可する」という信頼関係を構築します。
従来の「JSONキーファイル(静的な秘密鍵)」をPodに埋め込む方式とは異なり、Workload Identityは以下の特徴を持ちます。
キーレス: 管理が難しい長期間有効な秘密鍵を一切使用しない
短命なトークン: 発行されるアクセストークンは短時間(通常1時間)で期限切れとなり、自動的にローテーションされる
これにより、アプリケーションは「鍵の管理」という重荷から解放され、安全かつシームレスにGoogle Cloudのリソースへアクセスできるようになります。
Workload Identity の詳細フロー: 信頼の交換プロセス
GKE上のPodが「Googleの認証情報」を求めた時、舞台裏では以下のステップでトークンの交換が行われます。

リクエストの送信: Pod内のクライアントライブラリが、GKEノード上のメタデータサーバーに対してHTTPリクエストを送信し、認証情報を要求する
メタデータサーバーによる識別と準備: メタデータサーバーはこのリクエストをインターセプトし、以下の処理を行う
リクエスト元のPodを識別する
Podに紐付いたKSAと、そのAnnotationから「なり代わるべきGSA」を特定する
Podの身分証明書であるKSA OIDCトークンを取得する
このトークンを持って、Google CloudのSecurity Token Service (STS)APIを呼び出す。
STSによる検証: STSは受け取ったKSAトークンの署名を検証し、IAMバインディング(
roles/iam.workloadIdentityUser)をチェックする- 「このKSAは、本当にこのGSAとして振る舞うことを許可されているか?」検証に成功すると、STSはFederated Access Tokenを返す
GSAトークンへの交換: メタデータサーバーは、受け取ったFederated Tokenを使い、IAM Service Account Credentials APIを呼び出す
- ここで最終的なGSAのOAuth 2.0 Access Tokenへの交換を要求する
Podへの返却: メタデータサーバーは、取得したGSA Access TokenをPod内のクライアントライブラリに返却する
サービスへのアクセス: Pod内のアプリケーションはこのトークンを使ってPub/Sub APIを呼び出す
- Pub/Sub側はトークンを検証し、リクエスト元を「KSAではなくGSA」として認識・認可する
Network Control Planeへの依存:
このIdentity Control Planeのフローが成立するためには、Network Control Planeが以下の通信を許可していることが大前提となります。メタデータサーバーやPodがSTSやIAM API(パブリックエンドポイント)と通信する必要があるためです。
Private Google Access (PGA): 内部IPアドレスしか持たないGKEノードから、Google API(STS, IAM Credentials API)へ到達するために必須である
ファイアウォール(Egress): GoogleのIPアドレス範囲に対するポート443(HTTPS)への送信トラフィックが許可されている必要がある
可観測性: Podが誰として見なされているかを確認する
Identity Control Planeのデバッグにおいて重要なのは、「KSAとGSAの紐付け」が正しく構成され、実際にトークン交換が行われているかを確認することです。
構成の整合性チェック
Kubernetes側(KSA → GSAの参照): Podが正しいKSAを使用しているか、そしてそのKSAに正しいGSAのアノテーションが付与されているかを確認する
# 1. Podが使用しているKSA名を確認 kubectl -n <NAMESPACE> get pod <POD_NAME> \ -o jsonpath='{.spec.serviceAccountName}{"\n"}' # 2. KSAのアノテーションを確認 kubectl -n <NAMESPACE> get sa <KSA_NAME> \ -o jsonpath='{.metadata.annotations.iam\.gke\.io/gcp-service-account}{"\n"}'Google Cloud側(GSA → KSAの許可): GSA側で、「このKSAになりすますこと」を許可しているかを確認する
gcloud iam service-accounts get-iam-policy <GSA_EMAIL> \ --format="table(bindings.role, bindings.members)"出力結果に
roles/iam.workloadIdentityUserがあり、メンバーとしてserviceAccount:PROJECT_ID.svc.id.goog[NAMESPACE/KSA_NAME]が含まれている必要がある。これが欠けていると、STSでの検証(Step 3)で失敗する。
実行時のアイデンティティ確認
設定が正しいように見えても動かない場合は、「Pod内部からどう見えているか」を確認するのが確実です。Podにexecしてメタデータサーバーに問い合わせます。
kubectl exec -it <POD_NAME> -n <NAMESPACE> -- \
curl -H "Metadata-Flavor: Google" \
http://169.254.169.254/computeMetadata/v1/instance/service-accounts/default/email
成功: 指定したGSAのメールアドレスが返ってくる(Workload Identityが機能している)
失敗: GKEノードのデフォルトSAが返ってくる、またはエラーになる
失敗のサイン
Identity Control Planeで問題が起きている場合、アプリケーションログには以下のような兆候が現れます。
DefaultCredentialsError: Could not automatically determine credentials
MetadataServerException: Connection refused (Network Control Planeの問題の可能性も含む)
ログ上にトークン関連のエラーが出るが、IAMの権限不足(403 Forbidden)ではない
これらは、「IAMロールの評価(Authorization)」以前の、「身分証の取得(Authentication)」の段階で躓いていることを示唆しています。
Authorization Control Plane: このアイデンティティは何をしてよいか?
Network Control Planeがパケットの通り道を拓き、Identity Control Planeが「このリクエストは間違いなくあのGSAからのものである」と身元を保証しました。
しかし、まだリクエストは完了していません。Google Cloudは最後にこう問います。
「で、そのGSAには、このデータを触る資格があるのか?」
ここで登場するのが「Authorization Control Plane(IAM)」です。このプレーンは、確立されたアイデンティティに対し、リソースへのアクセス権(Permission)があるかどうかを厳密に評価し、最終的なALLOWまたはDENYを下します。
基本となる構成要素
IAMを理解するには、「権限を直接ユーザーに渡さない」というGoogle Cloudの設計思想を理解する必要があります。
IAMの構成要素: Who, What, Where
IAMは以下の3つの要素を組み合わせることで成立します。
Permissions(権限):アクセスの最小単位である。「サービス・リソース・動詞」の形式で表現される
例:
pubsub.topics.publish(トピックへの送信),cloudsql.instances.connect(DBへの接続)注意: 直接Permissionを扱うことは稀である
Roles(ロール):業務に必要なPermissionを束ねた「名前付きセット」である
プリミティブロール: 権限が広すぎるため、本番環境では原則使用しません
roles/ownerroles/editorroles/viewer
事前定義ロール:Googleがメンテするタスク指向のセット
roles/cloudsql.clientroles/pubsub.publisherroles/secretmanager.secretAccessor
カスタムロール:組織固有のニーズに合わせて作成するセット
BindingsとPolicy(バインディングとポリシー)
- Who: メンバー(GSA, User, Group)
- What: ロール
- Where: リソース
つまり、IAMポリシーは次のような宣言文として読むことができます。
「リソースX (Where) 上で、GSA Y (Who) に対して、ロールZ (What) を与える。」
ポリシーの継承と評価ロジック
Authorization Control Planeの最大の特徴は、ポリシーが階層構造を持つことです。
- Organization(全社)
- Folder(部署・チーム)
- Project(システム境界)
- Resource (個別のCloud SQLインスタンスなど)
リクエストがAPIに到達した瞬間、Authorization Control Planeは以下のアルゴリズムを実行します。
アイデンティティの抽出: アクセストークンを検証し、「誰(GSA)」からのリクエストかを特定する
ポリシーの収集とマージ: 対象リソースから組織ルートまで、親階層を遡りながらすべてのIAMポリシーをかき集める
ルール: 親(例: プロジェクト)で許可された権限は、子(例: Pub/Subトピック)にも継承される
実効権限の展開: 集めたポリシー内のロールを、数千のPermissionに展開し、そのGSAが持っている「実効権限リスト」を作成する
マッチングと判定:「今回のAPIコールに必要なPermission(例:
pubsub.topics.publish)」が、そのリストの中に含まれているかをチェックする
判定: 含まれていればALLOW、そうでなければDENY (403 Forbidden) を返します。
可観測性: 403 Forbiddenの真犯人を探す
Authorization Control Planeでの問題は、ネットワークやアイデンティティとは異なり、「明示的な拒否」として現れます。
症状: 403 Forbidden / Permission Denied
アプリケーションログに403 ForbiddenやPermission Deniedが記録された場合、これはある意味で朗報です。なぜなら、以下のことが確定するからです。
Network Control Planeは通過した(到達性はOK)
Identity Control Planeも通過した(身元は判明している)
問題は「権限」だけにある
ログで見るべきポイント
IAMエラーの詳細は、Cloud Audit Logs (Data Access Logs) に記録されます。Log Explorerで以下のフィルタを使うと、拒否されたリクエストを特定できます。
例:protoPayload.status.code="7"(7はgRPCにおけるPERMISSION_DENIEDを指します), severity="ERROR"
ログのprotoPayload.authenticationInfoとauthorizationInfoを確認することで、決定的な証拠が得られます。
principalEmail: 実際に評価されたアイデンティティは誰か?(意図したGSAになっているか?)resource: どのリソースにアクセスしようとしたか?permission: 具体的にどの権限(permission)が不足していたか?
Policy Troubleshooterによる診断
「なぜ拒否されたのか(どのロールが足りないのか、あるいはどの条件でブロックされたのか)」を論理的に解明するには、Policy Troubleshooterが有効です。ログで特定した「Who, What, Where」を入力することで、Control Planeの評価ロジックをシミュレーションできます。
gcloud policy-troubleshoot iam \
//pubsub.googleapis.com/projects/MY_PROJECT/topics/MY_TOPIC \
--principal-email=my-app-sa@my-project.iam.gserviceaccount.com \
--permission=pubsub.topics.publish
403エラーが出たとき、闇雲にeditorロールを与えるのは避けましょう。ログには「不足しているPermission(例: pubsub.topics.publish)」が明記されています。それをピンポイントで含むカスタムロールや事前定義ロールを付与するのが、最小権限の原則に基づく正しい修正アプローチです。
Resource Control Plane: 妥当な対象リソースは存在するか?
ネットワークが道を拓き、アイデンティティが身元を明かし、Authorization(IAM) が通行を許可しました。これですべての関門を突破したように見えます。
しかし、プラットフォームは最後に「物理的・論理的な現実」と向き合わなければなりません。
「Resource Control Plane」とは、リクエストされた対象が実在するのか、稼働しているのか、そしてサービス固有のルール(DBのユーザ認証など)を満たしているかを判断する、リクエスト処理の最終到達点です。これがResource Control Planeです。
リソース解決:「その宛先」は実在するか?
すべてのAPIリクエストは、最終的に何らかの具体的なリソースをターゲットにします(Cloud SQLインスタンス、Pub/Subトピック、Secret Managerのバージョンなど)。プラットフォームは、リクエストに含まれる識別子(プロジェクトID、リージョン、リソース名)を、実在するオブジェクトに解決しようと試みます。
存在しない: 指定された名前のインスタンスやトピックが無い、または削除されている
場所が違う: リソースは存在するが、指定されたリージョンやプロジェクトが異なる
状態が不正: インスタンスの停止中(STOPPED)やメンテナンス中
症状: ここで発生するエラーは403 Forbiddenではなく、主に404 NOT_FOUNDや400 FAILED_PRECONDITION(インスタンスが起動していない等)となります。
サービス固有のルール: IAMの「奥」にある壁
リソースが無事に特定された後でも、各マネージドサービスはIAMとは独立した独自の防御レイヤーを持っています。IAMはあくまで「Google Cloudリソースへのアクセス」を制御するものであり、その内部のデータ保護までは関与しないことが多いからです。
Cloud SQL(DBエンジンの認証)
Cloud SQLにおいて、IAMロールroles/cloudsql.clientは「インスタンスの玄関を通る権利」にすぎません。
IAMの範囲: Google CloudのAPIとして「Connect」することを許可する
DBエンジンの範囲: PostgreSQLやMySQLプロトコルレベルでのログイン認証
そのため、Resource Control Planeでは以下の事象が起こり得ます。
「インスタンスへの接続(IAM)は成功したが、PostgreSQLのユーザー認証(パスワードやDBユーザー名)で拒否された。」
これは、インフラ(Google Cloud)とアプリケーション(Database)の境界線で発生する典型的なエラーです。
Secret Manager(バージョンの状態)
Secret Managerは、リソースの「存在」と「状態」を厳密に区別します。
権限の分離: メタデータを見る権限(viewer)と、中身(ペイロード)を読む権限(secretAccessor)は別物である
ライフサイクルの壁: IAM権限が正しくても、指定したシークレットのバージョンが「無効(Disabled)」または「破棄(Destroyed)」状態であれば、Resource Control Planeはアクセスを拒否する
可観測性: ターゲットをダブルチェックする
Resource Control Planeのデバッグは、権限の確認から「対象物の現状確認」へとシフトします。IAMがどれほど完璧でも、対象が存在しなければ(あるいは動いていなければ)リクエストは成功しません。
デバッグには、コンソールやgcloudコマンドを使って、以下の3つのレイヤーで事実確認します。
アドレッシングの整合性
コード内の設定値が、デプロイされたリソースと完全に一致しているかを疑います。
プロジェクトとリージョン:「開発環境を見ているつもりが本番環境だった」「us-central1だと思ったらasia-northeast1だった」というミスは頻発する
リソース名: Pub/Subトピック名やバケット名のタイプミスがないか?
ライフサイクルとステータス
リソースが存在していても、リクエストを受け入れられる状態にあるかを確認します。
Cloud SQL: stateはRUNNABLEになっているか?(メンテナンス中やSTOPPEDではないか?)
Secret Manager: シークレット自体が存在するか?
指定したバージョンのstateがENABLEDか?(DISABLEDやDESTROYEDではないか?)
GCS: オブジェクトが既に削除されていないか?(保持ポリシーやライフサイクルルールによる自動削除)
サービス内部のセマンティクス
Google CloudのAPI層を通過した後の、データプレーンレベルのルールです。
DBユーザー権限: Cloud SQLインスタンスへの接続は成功しているが、PostgreSQL/MySQL側でAccess denied for userやpermission denied for tableが出ていないか?
エラーメッセージの解読
Resource Control Planeの問題は、エラーコードによってある程度判別できます。
404 NOT_FOUND/Resource not found: これはIAMの問題(権限不足)ではない。「宛先間違い」または「リソース未作成」である。IAM設定を見直す前に、接続文字列を確認すること
400 FAILED_PRECONDITION:「インスタンスが停止している」「互換性のない操作」など、リソースの状態に問題がある
DBエンジン固有のエラー: IAMの役割は終わっている。DB管理者としてデータベース内部のGRANT設定を確認する必要がある
まとめ: 4つのプレーンを通過して
こうして、GKE上のPodから発せられた1つのリクエストは、長い旅を終えます。
Network: 道はあるか?
Identity: 誰がリクエストしているか?
Authorization: 資格はあるか?
Resource: 対象は実在し、動いているか?
GKEのトラブルシューティングでは、当てずっぽうに設定を見直すのではなく、エラーメッセージやログなどの可観測性データを手掛かりに、どのプレーンで起きている問題かを見極めることが重要です。
本記事で扱ったプレーンごとの役割を、あらためて以下にまとめます。
| コントロールプレーン | 役割 | 代表的なエラー症状 | 何を見るか / 使うツール |
|---|---|---|---|
| 1. Network | 到達性 (道があるか) |
・タイムアウト ・ Connection Refused・ No route to host・IAM関連のエラーが一切出ない |
・VPC Flow Logs (DENYがないか) ・ファイアウォールルール (Egress) ・ルートテーブル ・Connectivity Tests |
| 2. Identity | 認証 (誰か) |
・DefaultCredentialsError・ MetadataServerException・ Could not automatically determine credentials・トークン取得失敗 |
・Pod内からの curl 確認 (メタデータ)・KSAのアノテーション ( kubectl describe sa)・GSAのIAMバインディング ( workloadIdentityUser) |
| 3. Authorization | 認可 (IAM) (権限はあるか) |
・403 Forbidden・ PERMISSION_DENIED・ status code = 7 (gRPC)・「User X does not have permission Y」 |
・Cloud Audit Logs (principalEmail と permission を確認)・IAM Policy Troubleshooter ・ gcloud iam policy |
| 4. Resource | 実在・状態 (宛先は健全か) |
・404 NOT_FOUND・ 400 FAILED_PRECONDITION・「Resource does not exist」 ・DB等の内部認証エラー ( Access denied, Login failed) |
・リソースのステータス (Running か?)・接続文字列 (Project ID, Region, Name) ・サービス固有のログ (PostgreSQLログなど) ・組織ポリシー / Quota |
本記事で紹介した考え方が、トラブルシューティングや日々の設計を考える際の参考になれば幸いです。
enechainでは、日本のエネルギーの未来を一緒に作っていく仲間を募集しています。興味がある方はぜひお声がけください!