Serverless NEGを使用して、GAEにIPv4の固定IPアドレスでIP制限をする

Programming

はじめに

この記事は ミライトデザイン Advent Calendar 2021 の 23日目の記事となっています。

前回は「docker-laravel の Docker 構成をちゃんと理解する【Dockerfile 編 – PHP】」という記事を書いてくれた takuma でした。

docker-compose 編もあるので、そっちも見てみてください。

さて、今回の記事は、IP制限をGAE(Google App Engine)で実現したいユースケースがあったのですが、GAEは自動的にIPv6に対応するそうで、半固定のIPv6に対しては固定IPで制限ができないという事象がありました。

色々方法はあると思いますが、今回はServerless NEGを使用しロードバランサ経由でGAEにアクセスすることで、IP制限の実現ができたのでそちらの紹介をします。

NEGとは?

そもそもNEGというのは「Network Endpoint Group」の略です。

名前の通り複数のネットワークエンドポイントをまとめたものとなっていて、ロードバランサのエンドポイントとして指定が可能となっています。

NEGにはいくつか種類があり、今回のケースではServerless NEGというものを使用します。

以下の画像はGKE(Google Kubernetes Engine)での画像ですが、イメージしやすいと思ったので持ってきました。

network_endpoint_group
Container-native load balancing on GKE now generally available | Google Cloud Blog より引用

従来のGKEのロードバランサは iptables で再度負荷分散をするという2段階ロードバランシングだったのを、NEGを使用することで直説負荷分散できるといった内容を紹介してくれています。

NEGとは何かという方にはイメージしやすいのではないでしょうか。

NEGの種類

  • Zonal NEG
  • Internet NEG
  • Serverless NEG
  • Hybrid connectivity NEG
  • Private Service Connect NEG

公式:Network endpoint groups overview  |  Load Balancing  |  Google Cloud

Serverless NEGとは?

Serverless NEGというのはサーバーレスサービスに対して使用できるNEGです

NEGは今までGCE(Google Compute Engine)GKEにしか使用できなかったようですが、Serverless NEGの登場により「App Engine」「Cloud Functions」「Cloud Run」のサーバーレスサービスでも使用ができるようになりました。

そのため、ロードバランサのエンドポイントにサーバーレスサービスを指定し、ロードバランサでIPv4を指定することでGAEにはIPv4でのアクセスとなり、本来やりたかった固定IPの制限が可能になるということです。

環境構築手順

では実際に環境を作ってみましょう。

大きく手順としては以下の通りです。

  1. GAEをデプロイする
  2. 静的IPアドレスを取得する
  3. Serverless NEGを作成する
  4. バックエンドサービスを作成する
  5. ロードバランサを設定する

GAEをデプロイする

GAEのアプリケーションがデプロイされている上でIP制限をかけたいというユースケースのため、ここではGAEのデプロイ詳細は省略します。

Laravelの例ですが、IPの確認をするためにエンドポイントに以下のアクションを追加しておくとGAEへのリクエストIPの確認ができます。

public function ip(Request $request): array
{
    return [
        'ip' => $request->ip(),
        'ips' => $request->ips(),
        'client_ip' => $request->getClientIp(),
        'client_ips' => $request->getClientIps(),
        'X-Appengine-User-Ip' => $request->header('X-Appengine-User-Ip'),
    ];
}

GAEでIPを確認する場合は X-Appengine-User-Ip ヘッダーから取得して確認します。

公式:Request Headers and Responses  |  App Engine standard environment for PHP 7 docs  |  Google Cloud

静的IPアドレスの作成

ロードバランサのエンドポイントに使用するため静的IPアドレスを作成しておきます。

gcloud compute addresses create [IPアドレス論理名] \
    --ip-version=IPV4 \
    --global

以下のコマンドで予約されている IPv4 アドレスを控えときましょう。

gcloud compute addresses describe [IPアドレス論理名] \
    --format="get(address)" \
    --global

GUI上でも作成されていることが確認できます

Serverless NEGの作成

GAE用のServerless NEGを作成します。

なお、リージョンについてはGAEと同じリージョンにする必要があります。

gcloud compute network-endpoint-groups create [ServerlessNEG論理名] \
    --region=[リージョン名] \
    --network-endpoint-type=serverless  \
    --app-engine-app \
		--app-engine-service=default

作成されたことを以下のコマンドで確認します。

gcloud beta compute network-endpoint-groups list
NAME                           LOCATION         ENDPOINT_TYPE  SIZE
[ServerlessNEG論理名]           [リージョン名]       SERVERLESS     0

GUI上でも作成されていることが確認できます。

バックエンドサービスの作成

バックエンドサービスを作成し、バックエンドとして先ほど作成した Serverless NEG を追加します。

gcloud compute backend-services create [バックエンドサービス論理名] \
    --global

NAME                            BACKENDS  PROTOCOL
[バックエンドサービス論理名]                     HTTP

バックエンドサービスにServerless NEGを追加

gcloud compute backend-services add-backend [バックエンドサービス論理名] \
    --global \
    --network-endpoint-group=[ServerlessNEG論理名] \
    --network-endpoint-group-region=[リージョン名]

バックエンドサービスが作成され、Serverless NEGが追加されているかを以下のコマンドで確認しましょう。

gcloud beta compute backend-services list
NAME                      BACKENDS                                                PROTOCOL  LOAD_BALANCING_SCHEME  HEALTH_CHECKS
[バックエンドサービス論理名]     [リージョン名]/networkEndpointGroups/[ServerlessNEG論理名]   HTTP      EXTERNAL

GUI上でも確認ができます。

ロードバランサーの設定

まずは受信リクエストをバックエンドサービスにルーティングするためのURLマップを作成します。

gcloud compute url-maps create [ロードバランサ論理名] \
    --default-service [バックエンドサービス論理名]

NAME                 DEFAULT_SERVICE
[ロードバランサ論理名]    backendServices/[バックエンドサービス論理名]

ターゲットhttpプロキシを作成しロードバランサに追加

URL マップにリクエストをルーティングするターゲット HTTPS プロキシを作成します。

HTTP ロードバランサの場合、HTTP ターゲット プロキシを作成します

gcloud compute target-http-proxies create [ターゲットhttpプロキシ論理名] \
    --url-map=[ロードバランサ論理名]

NAME                        URL_MAP
[ターゲットhttpプロキシ論理名]    [ロードバランサ論理名]

フロントエンド(forwarding rule)をロードバランサに追加

gcloud compute forwarding-rules create [フロントエンド論理名] \
    --address=[控えていたIPアドレスを指定] \
    --target-http-proxy=[ターゲットhttpプロキシ論理名] \
    --global \
    --ports=80

ロードバランサ・フロントエンドの確認

以下のコマンドで作成したものを確認しましょう。

$ gcloud compute forwarding-rules list
NAME                REGION     IP_ADDRESS   IP_PROTOCOL  TARGET
[フロントエンド論理名]   [IPアドレス]               TCP          [ターゲットhttpプロキシ論理名]

GUIでも確認

ロードバランサにリクエストしてみる

作成したロードバランサにリクエストをしてみましょう。

取得したIPアドレスをURLに入力してアクセスするとデプロイしたアプリケーションの画面が表示されます。

自分の場合はLaravelのアプリケーションをデプロイしたので、Webcomeページが表示されます。

固定IPでアクセスできるかを確認してみる

もともとデプロイしていたアプリケーションのIPを確認するとIPv6でアクセスされていることが確認できます。

次に作成したロードバランサにアクセスしてIPv4でアクセスされていることを確認します。

GAEへアクセスされているIPを調べるために追加したエンドポイントを叩いて X-Appengine-User-Ip の値を確認すると、固定IPとなっているかと思います。

おわりに

クライアントがIPv6でアクセスしてきたとしても、GAEにはIPv4でアクセスできていることが確認できたと思います。

GAEでは自動でIPv6に対応するため、IPv4の固定IPでIP制限が必要な場合は今回紹介した方法で試してみてください。

この後DNSの設定やSSLの設定をすることで実用化できると思いますが、今回は省略します。

できれば余裕があるときに追記していけたらと思います。

参考