App Engine 間通信のアクセス制御
こんにちは、Cloud Support の Rnrn です。よくサポートに寄せられる質問の一つに、「異なるプロジェクトに存在する App Engine (以下 GAE) 間で通信する際、通信先の GAE に IP 制限を設定するために通信元の GAE の外向き IP を固定するにはどうしたらいいか」というものがあります。GAE では外向きの IP を固定することができますが、GAE 間の通信においてはその静的 IP は使用されず、通信元 GAE の IP を固定することはできません。今日はその詳しい理由と対処法をご紹介します。
デフォルトの GAE の外向き IP
デフォルト状態では、GAE の外向き IP は固定されていません。公式ドキュメント に詳しく説明されているように、一定の範囲のアドレスの中からランダムのアドレスが利用されます。そのため、例えば Google Cloud 外にある IP 制限のかかっているエンドポイントに対して GAE からのアクセスを許可したい場合、この範囲内のアドレスをすべてリストアップしなければいけないことになります。
でもそれはなかなかに大変そうですよね。そういうときは、次章で述べる外向き IP の固定を実施することが多いかと思います。
一般的な外向き IP の固定
公式ドキュメント で紹介しているように、Serverless VPC Access ・Cloud NAT を利用することで GAE が外向き通信時に使う IP アドレスを固定することができます。これにより、一般的なIP 制限においてはこの静的アドレスだけを許可すれば良いことになるので手間が省けます。
ただし、この方法で固定された外向き IP は、異なるプロジェクトに存在する GAE に対して通信した場合は使われないのです。
GAE 間通信で固定した外向き IPは使われない
GAE には IP ベースでファイアーウォール を適用する機能があります。この機能を通信先の GAE で利用している場合、よくある問題が「外向き IP を固定してファイアーウォールで許可したにも関わらずアクセスができない」です。
これはなぜかというと、Cluod NAT を設定すると同時に Private Google Access が有効化されるためです。Private Google Access により、Cluod NAT 背後にある GAE から別のGAE へ通信するリクエストは Google Cloud の内部ネットワークを通じてルーティングされるようになります。 このようなトラフィックに対して Cloud NAT は NAT を行わないため、このシナリオでは Cloud NAT による外向き IP は使われないことになります。実際にこの状態でリクエストを送信した場合、GAE のリクエストヘッダーから確認できるクライアント IP は 0.0.0.0/32
となります。
それでもGAE 間の通信にアクセス制御をかけたい時の対処法
上記の制約を踏まえ、この状況では以下のような対処が考えられます。もちろん 0.0.0.0/32
をファイアーウォールの許可リストに追加することでも問題は回避可能ですが、セキュリティ的に望ましいとは言えないので今回は省きます。
1. 内部通信を利用せずに通信させる
意図的に外部 HTTP(S) ロードバランサ を経由させることにより、内部ネットワークを通らずに通信を行うようにする方法です。これによりリクエストは通常の外部リクエストと同等に扱われるため、期待通り Cloud NAT が機能するようになります。通信先の AppEngine にロードバランサを設定する方法については 公式ドキュメント をご確認ください。
注意点として、ロードバランサの料金が追加で発生すること、またロードバランサを経由させる場合にはアクセス先のエンドポイントが変わることが挙げられます。一方で、GAE の内向き制御 を設定しない限りはロードバランサを配置したからといって GAE のデフォルトの URL でサービスにアクセスができなくなるわけではありません。そのため、特定のパターンでのみロードバランサを経由させ、それ以外では従来どおりの URL でアクセスするということも可能です。
2. IP ではなくアカウントでの制限を行う
IP 制限にこだわる必要がなく、特定の許可された GAE サービスからのみアクセスを許可することが目的であればアクセス制限の方法自体を見直す手もあります。ここでご紹介するのはファイアーウォールではなく Identity Aware proxy を利用して通信元のアカウントをベースにアクセス制限を行う 方法です。この方法であれば特定のサービスアカウントからのアクセスだけを許可する制御ができるため、そのサービスアカウントを許可したい GAE サービスのみに付与すれば目的を達成することができます。リンク先の公式ドキュメント以外に、以前コミュニティブログでもこの方法を用いた GAE 間のアクセス制限について紹介しています のでこちらもぜひご参照ください。
上記ブログ記事でも紹介していますが、IAP を使う場合、通信時のレイテンシが増加する可能性があることに注意が必要です。また、IAP は各プロジェクトのリソース単位で有効/無効の切り替えをすることになります。もし複数の GAE サービスがプロジェクト内に存在している場合、IAP を GAE に対して有効化したタイミングですべての GAE サービスに対して認証が求められるようになる点にご留意ください。なお、一度有効化した後は各 GAE サービスごとに個別のアクセス権の設定が可能です。
おわりに
GAE 同士での通信でアクセス制御をかけたいなと思っている方の手助けになれば幸いです。質問などあればぜひコメントくださいね 💬
Discussion