API Gatewayを通過しないリクエストをAWS WAFにてブロックしてみた

ALBへの直接アクセスを許したくないけど、アクセス元のIPアドレスが多岐に渡るパターンなどで有効です

こんにちは、AWS事業本部の荒平(@0Air)です。

タイトル通り、API Gatewayを通過しないリクエストをAWS WAFでブロックして、ALBへの直接アクセスを防いでみました。

本構成の経緯として、以下のブログにてAPI Gateway+NLB+ALBの構成を実装していたのですが、アプリケーション側から見たアクセス元がNLBのインターナルなIPアドレスとなってしまい、アプリケーション側で不具合が出てしまったため、別の方策を考える必要がありました。

今回紹介する方法を使えば、バックエンド側から見たアクセス元はAPI GatewayのIPとなり、ローカルアクセスの判定をされません。また、最低限のセキュリティを担保するために、ALBへの不特定アクセスを回避します。

img

構成図

今回の実装では、API GatewayのNLB統合を利用せずに、ALB側でもセキュリティグループをオープンにする方法で解決を目指しました。
API Gatewayを通過するリクエストは、x-amzn-apigateway-api-id というヘッダーが付与される仕様を利用します。

やってみた

1. 事前準備(API Gateway・ALB/Lambdaの作成)

ALBを作成し、HTTP:80を0.0.0.0/0に向けて開放します。Target Groupは今回Lambdaを指定して作成しました。

ターゲット先のLambdaサンプルは以下のようにしました。BODYとヘッダーの情報を返すシンプルなものです。

import json

def lambda_handler(event, context):
    body = event.get("body")
    headers = event.get("headers")

    response = {
        "statusCode": 200,
        "body": json.dumps({
            "received_body": body,
            "received_headers": headers
        }),
        "headers": {
            "Content-Type": "application/json"
        }
    }

    return response

API Gatewayをデプロイし、GETメソッドのリクエスト先に作成したALBを設定します。
API GatewayのIDは後ほど利用するため、控えておきます。
(例:ARNがarn:aws:execute-api:ap-northeast-1:{アカウントID}:bjon5wzrpd/* の場合、bjon5wzrpdの部分)

2. AWS WAFルールの設定

AWS WAFのコンソールに移動し、Web ACLを作成します。
ここでは、東京リージョンにALBがあるためAsia Pacific (Tokyo)を選択します。

適当なWeb ACL名を入力し、Add AWS resources をクリックします。

作成したApplication Load Balancerを選択し、Addをクリックします。

Default web ACL actionをBlockに設定の上、「Add my own rules and rule groups」をクリックします。

「Rule builder」を選択し、任意のルール名を入力します。

If a requestは「matches the statement」を選択し、ステートメントは以下のように設定します。

項目
Inspect Single header
Header filed name x-amzn-apigateway-api-id
Match type Exactly matches string
String to match {API GatewayのID}

これ以外の設定は特に変える必要はありません(環境に応じて変更可)。

3. 経由アクセス・直接アクセスの確認

API Gatewayを経由したアクセスができるか確認します。
user-agentがAmazonAPIGateway_{API Gateway-ID}の形式になっていて、レスポンスが返っていれば問題なくアクセスできています。

続いて、ALBに直接アクセスができるか確認します。
AWS WAFに設定したヘッダー情報と不一致のため、正しく設定されていれば403 Forbiddenが返るはずです。

ブラウザでALBへの直接アクセスを確認しても、狙い通り403 Forbiddenとなりました。

おわりに

軽く調べた感じだと、同様の構成がネット上に転がっていなかったので、あまりメジャーに使われていない気がして投稿してみました。
AWS WAFを組み合わせると色々な制御パターンが可能なので、非常に便利なサービスの一つです。

このエントリが誰かの助けになれば幸いです。
それでは、AWS事業本部 コンサルティング部の荒平(@0Air)がお送りしました!