AWS

API GatewayにAWS WAFを関連付ける手順:Web ACLのルール設計・WCU計算とCognito保護

API GatewayにAWS WAFを関連付ける手順:Web ACLのルール設計・WCU計算とCognito保護

Amazon API GatewayにAWS WAFを付けるときは、REST APIのステージごとに、同じリージョンで作ったWeb ACLを関連付けます。ログイン画面やトークン発行を担うCognitoユーザープールは別のリソースなので、関連付けも別に行います。本記事では、Web ACLの作成から関連付けまでをCLIのコードで示し、WCUの計算、ボディ検査の上限、誤検知の切り分け方を整理しました。APIゲートウェイの役割そのものはAPIゲートウェイとは?役割・機能とリバースプロキシ/サービスメッシュとの違い・導入判断を解説で扱っています。仕様は2026年10月時点の公式ドキュメントで確認したものです。

まとめ:WAFはREST APIのステージ単位で付け、Cognitoには別のWeb ACLを関連付ける

API GatewayでAWS WAFを使えるのはREST APIだけです。HTTP APIを守るなら、前段にCloudFrontを置き、そちらにWeb ACLを付けます。REST APIでは、WAFのルールがリソースポリシーやLambdaオーソライザーより先に評価されるため、不正なリクエストは認可処理に届く前に止まります。

ルールはマネージドルールのCore rule set(700WCU)を軸に、既知の不正入力・SQLインジェクション・IPレピュテーションとレートベースルールを足すと、約1,130WCUで基本料金の1,500WCUに収まります。最初は全ルールをCountで入れ、ログで誤検知を確かめてからBlockに切り替える手順です。特にCore rule setのSizeRestrictions_BODYは8KBを超える本文を止めるため、ファイルや大きなJSONを受けるAPIでは真っ先に確認が要ります。

AWS WAFを付けられる範囲|REST APIのステージ単位とHTTP APIの代替

AWS WAFの関連付け先は、APIそのものではなくデプロイ済みのステージです。prodとstgで別のWeb ACLを付けることも、1つのWeb ACLを複数のステージで共用することもできます。

REST APIのステージにリージョンのWeb ACLを関連付けるときの前提条件

API GatewayのWAF連携ページは、WAFv2の場合「Regional application」用のWeb ACLを求め、Web ACLと参照するリソースはAPIと同じリージョンに置くよう定めています。東京のAPIならap-northeast-1で作ったWeb ACLです。

エッジ型(Edge-optimized)のREST APIでも、選ぶのはCloudFront用ではなくリージョン用のWeb ACLです。関連付け先の指定にはステージのARNを使い、形式はarn:aws:apigateway:ap-northeast-1::/restapis/{api-id}/stages/{stage}になります。アカウントIDが入らない点がほかのARNと違うので、手で組み立てるときに間違えやすい箇所です。

WAFはリソースポリシーやオーソライザーより先に評価される評価順の意味

公式ドキュメントは、WAFのルールがリソースポリシー、IAMポリシー、Lambdaオーソライザー、Cognitoオーソライザーより前に評価されると明記しています。リソースポリシーで許可したCIDRでも、WAFが遮断すればそこで止まり、リソースポリシーは評価されません。IPセットとリソースポリシーのどちらで送信元を絞るかはAPI GatewayのIP制限:リソースポリシーとWAFのIPセットで送信元を絞る手順と使い分けで比較しています。

この順序のおかげで、総当たりや大量アクセスがLambdaオーソライザーの起動回数を押し上げません。逆に、WAFで誤って遮断した正規の利用者を後段で救うことはできず、誤検知はAPIの全利用者に効きます。

HTTP APIにWAFは付かないためCloudFront経由でWeb ACLを置く構成

REST APIとHTTP APIの比較ページで、AWS WAFはREST APIだけの機能として並んでいます。HTTP APIで入口を守るなら、CloudFrontのディストリビューションを前段に置き、CloudFront用のWeb ACLを付けます。

CloudFront用のWeb ACLはcreate-web-aclで--scope CLOUDFRONT --region us-east-1を指定して作り、ほかのリソース種別とは共用できません。この構成では、HTTP APIのURLへ直接アクセスされるとWAFを迂回されます。CloudFrontだけが付けるヘッダで直アクセスを拒否する方法はCloudFront×API Gateway×Lambdaの連携構成|設定手順と403の原因・直アクセスの遮断方法にまとめました。

CLIでWeb ACLを作りAPIステージとCognitoユーザープールへ関連付ける手順

東京リージョンのREST APIとCognitoユーザープールを守るWeb ACLを、AWS CLIで組み立てます。ルールをJSONで残すと、別アカウントへ同じ構成を再現できます。

マネージドルール4つとレートベースルールをJSONファイルに定義する書き方

次のrules.jsonは、IPあたりのレート制限、Amazon IPレピュテーション、Core rule set、既知の不正入力、SQLインジェクションの5本です。Core rule setのSizeRestrictions_BODYだけは、後述する誤検知を避けるためRuleActionOverridesでCountに上書きしています。

[
  {
    "Name": "rate-per-ip",
    "Priority": 0,
    "Statement": {
      "RateBasedStatement": {
        "Limit": 1000,
        "EvaluationWindowSec": 300,
        "AggregateKeyType": "IP"
      }
    },
    "Action": { "Block": {} },
    "VisibilityConfig": { "SampledRequestsEnabled": true, "CloudWatchMetricsEnabled": true, "MetricName": "rate-per-ip" }
  },
  {
    "Name": "aws-ip-reputation",
    "Priority": 1,
    "Statement": { "ManagedRuleGroupStatement": { "VendorName": "AWS", "Name": "AWSManagedRulesAmazonIpReputationList" } },
    "OverrideAction": { "None": {} },
    "VisibilityConfig": { "SampledRequestsEnabled": true, "CloudWatchMetricsEnabled": true, "MetricName": "aws-ip-reputation" }
  },
  {
    "Name": "aws-common",
    "Priority": 2,
    "Statement": {
      "ManagedRuleGroupStatement": {
        "VendorName": "AWS",
        "Name": "AWSManagedRulesCommonRuleSet",
        "RuleActionOverrides": [
          { "Name": "SizeRestrictions_BODY", "ActionToUse": { "Count": {} } }
        ]
      }
    },
    "OverrideAction": { "None": {} },
    "VisibilityConfig": { "SampledRequestsEnabled": true, "CloudWatchMetricsEnabled": true, "MetricName": "aws-common" }
  },
  {
    "Name": "aws-known-bad-inputs",
    "Priority": 3,
    "Statement": { "ManagedRuleGroupStatement": { "VendorName": "AWS", "Name": "AWSManagedRulesKnownBadInputsRuleSet" } },
    "OverrideAction": { "None": {} },
    "VisibilityConfig": { "SampledRequestsEnabled": true, "CloudWatchMetricsEnabled": true, "MetricName": "aws-known-bad-inputs" }
  },
  {
    "Name": "aws-sqli",
    "Priority": 4,
    "Statement": { "ManagedRuleGroupStatement": { "VendorName": "AWS", "Name": "AWSManagedRulesSQLiRuleSet" } },
    "OverrideAction": { "None": {} },
    "VisibilityConfig": { "SampledRequestsEnabled": true, "CloudWatchMetricsEnabled": true, "MetricName": "aws-sqli" }
  }
]

レートベースルールを先頭に置くのは、大量アクセスをマネージドルールの検査より前に落とすためです。レートベースルールの設定項目では、評価ウィンドウは60・120・300・600秒から選び、既定は300秒、上限値の最小は10です。上の例は「1つのIPから5分間に1,000件まで」を意味します。

create-web-aclでリージョン用のWeb ACLを作成しARNを控える手順

ルールファイルができたら、リージョン用のWeb ACLを作ります。既定の動作はAllowにして、ルールに当たったものだけを止める形にします。

# 東京リージョンにREST API・Cognito用のWeb ACLを作る
aws wafv2 create-web-acl --region ap-northeast-1 \
  --name api-prod-acl --scope REGIONAL \
  --default-action Allow={} \
  --visibility-config SampledRequestsEnabled=true,CloudWatchMetricsEnabled=true,MetricName=api-prod-acl \
  --rules file://rules.json \
  --query "Summary.ARN" --output text

出力されるARNはarn:aws:wafv2:ap-northeast-1:{account-id}:regional/webacl/api-prod-acl/{id}の形です。作成直後は反映に数秒から数分かかり、その間に関連付けるとWAFUnavailableEntityExceptionが返ることがCognitoのWAF連携ページに書かれています。スクリプトで続けて実行するなら、関連付けに再試行を入れておきます。

associate-web-aclでAPIステージとユーザープールへ順に関連付ける

関連付けはAPI Gateway側でもCognito側でもなく、WAFのassociate-web-aclで行います。Cognitoには関連付け専用のAPI操作がありません。

WEB_ACL_ARN="arn:aws:wafv2:ap-northeast-1:111122223333:regional/webacl/api-prod-acl/a1b2c3d4-5678-90ab-cdef-EXAMPLE11111"

# REST APIのprodステージへ関連付ける(ARNにアカウントIDは入らない)
aws wafv2 associate-web-acl --region ap-northeast-1 \
  --web-acl-arn "$WEB_ACL_ARN" \
  --resource-arn "arn:aws:apigateway:ap-northeast-1::/restapis/4wk1k4onj3/stages/prod"

# Cognitoユーザープールへ関連付ける
aws wafv2 associate-web-acl --region ap-northeast-1 \
  --web-acl-arn "$WEB_ACL_ARN" \
  --resource-arn "arn:aws:cognito-idp:ap-northeast-1:111122223333:userpool/ap-northeast-1_EXAMPLE"

# 関連付けを確認する
aws wafv2 list-resources-for-web-acl --region ap-northeast-1 \
  --web-acl-arn "$WEB_ACL_ARN" --resource-type API_GATEWAY

関連付けの制約として、1つのWeb ACLは複数のリソースに付けられますが、1つのリソースに付くWeb ACLは1つだけです。ステージごとに別の設定にしたいなら、Web ACLを分けて作ります。

WCUの計算とボディ検査16KBの上限|1,500WCUを超えると課金が増える仕組み

Web ACLに積めるルールの量は、ルールの本数ではなくWCU(Web ACL Capacity Units)で決まります。ボディをどこまで検査するかも、ルールの効き方と料金の両方に関わります。

マネージドルールのWCU一覧とcheck-capacityで上限を事前に確かめる方法

WCUの説明ページによると、Web ACLの基本料金に含まれるのは1,500WCUまでで、上限は5,000WCUです。前の手順のルール構成は次のように積み上がります。

ルール WCU 主に止めるもの
Core rule set 700 XSS・LFI・サイズ超過
Known bad inputs 200 Log4j等の既知の攻撃
SQL database 200 SQLインジェクション
Anonymous IP list 50 VPN・Tor等のIP
Amazon IP reputation 25 脅威情報にあるIP
レートベース(IP) 2 単一IPの大量アクセス

WCUの値はベースラインのルールグループ、IPレピュテーションのルールグループ、用途別のルールグループの各ページの記載です。前述のrules.jsonは1,127WCUで、匿名IPリストを足しても1,177WCUです。LinuxとPOSIXのルールグループ(計300WCU)まで積むと1,477WCUになり、独自ルールを足す余地はほとんど残りません。足す前にcheck-capacityで合計を確かめます。

aws wafv2 check-capacity --region ap-northeast-1 \
  --scope REGIONAL --rules file://rules.json

外部の自動運用サービスに任せる場合のWCUの考え方はWafCharmとは?AWS WAF自動運用の導入手順・WCU消費・料金の実額を実装視点で解説で扱っています。

ボディ検査は既定16KBで、最大64KBへ広げると追加課金になる条件

ボディ検査の上限は、API GatewayとCognitoで既定16KB(16,384バイト)です。16KB刻みで64KBまで広げられ、設定値は16・32・48・64KBの4つに限られます。16KBを超えた部分はWAFに渡らず、SQLインジェクションやXSSのボディ検査ルールは先頭16KBしか見ません。

上限はcreate-web-aclやupdate-web-aclの--association-configで、リソース種別ごとに指定します。値の形式はRequestBodyAssociatedResourceTypeConfigの定義どおりです。

--association-config '{"RequestBody":{"API_GATEWAY":{"DefaultSizeInspectionLimit":"KB_32"}}}'

追加料金は、16KBを超える本文を実際に検査したリクエストにだけかかります。

東京リージョンでWeb ACL1つにかかる月額を試算する計算式

AWS WAFの料金は、Web ACLが月5ドル、ルールが1本月1ドル、検査したリクエストが100万件あたり0.60ドルです。マネージドルールグループは1つで1ルールと数えます。東京リージョンの単価も同額です(Price List APIの2026年9月版で確認)。

前述の5ルールで月500万リクエストなら、5ドル+5ドル+3.00ドルで月13ドルです。1,500WCUを超えると、500WCUごとに100万件あたり0.20ドルが上乗せされます。ボディ検査を32KBに広げた場合、16KBを超えた分の検査料金は100万件あたり0.30ドルです。API Gateway本体を含めた請求の全体像はAPI Gatewayの料金を東京リージョンの実額で計算する:REST・HTTP・WebSocketの単価と付帯課金で計算しています。

Cognitoユーザープールを守るWeb ACLの制約|PII非対応と403の返り方

Cognitoユーザープールへの関連付けは、API Gatewayと同じassociate-web-aclで済みます。ただし、Cognitoがリクエストの一部しかWAFに渡さないため、API向けのWeb ACLをそのまま使うと期待どおりに動かない箇所があります。

ユーザー名やメールアドレスでは照合できずIPやヘッダで判定する制約

CognitoのWAF連携ページは、ユーザー名・パスワード・電話番号・メールアドレスといった個人情報をルールの照合対象にできないと明記しています。WAFに見えるのは、IPアドレス、User-Agent、呼び出されたAPI操作などのセッション情報です。マネージドログインと従来のホストされたUIでは本文も渡らず、ヘッダなど本文以外だけが検査されます。

そのため「同じユーザー名への連続ログイン」はWAFでは数えられません。総当たり対策は、IP単位のレートベースルールと、Cognito側の脅威保護を組み合わせて考えます。WAFで遮断したリクエストはCognitoのAPIレートクォータに数えられないので、大量のログイン試行で正規利用者がスロットリングされる事態を防げます。ユーザープールの構築とJWTの検証はCognitoで認証基盤を実装する手順:ユーザープール構築からJWT検証までにまとめました。

ATPとACFPのルールグループは関連付け不可・CAPTCHAはTOTP登録を壊す注意点

アカウント乗っ取り防止のAWSManagedRulesATPRuleSetと、不正なアカウント作成を防ぐAWSManagedRulesACFPRuleSetを含むWeb ACLは、ユーザープールに関連付けられません。Cognitoと共用するWeb ACLからは外します。

CAPTCHAを返すルールにも落とし穴があります。マネージドログインでTOTPの多要素認証を登録する途中にCAPTCHAが出ると、回復できないエラーになる場合があるため注意が必要です。また、独自のブロック応答で500番台を返しても、マネージドログインやホストされたUIでは403に置き換わります。ユーザープールAPIで独自のステータスコードが通るのは400〜499の範囲だけです。

ログイン用とAPI用でWeb ACLを分けるかどうかの判断基準

判断の軸はレート制限の値です。APIは画面1枚で数十回呼ばれることがあり、IPあたり5分間に1,000件でも正規の利用で届く場合があります。一方ログインは、同じIPから5分間に数十回も試すこと自体が不自然です。この2つを1本のレートベースルールで扱うと、どちらかに合わせた値が他方では緩すぎるか厳しすぎます。

レート制限の値が違うなら、Web ACLを分けます。ログイン用はIPレピュテーション、匿名IPリスト、低い値のレートベースルールの3本で十分で、月額は5ドル+3ドル+リクエスト料金です。レート制限を同じ値で運用できる小規模な社内システムなら、1つのWeb ACLを共用して月額を抑えて構いません。

誤検知を出さずに本番へ入れる運用|Countで様子見しログで切り分ける手順

関連付けのページも、本番では先にCountモードで調整してから遮断を有効にするよう求めています。API GatewayのWAFで多い誤検知は、マネージドルールが想定する一般的なWebサイトとAPIの通信の違いから生まれます。

SizeRestrictions_BODYが8KB超のJSONを止める誤検知と上書き

Core rule setのSizeRestrictions_BODYは、8KB(8,192バイト)を超える本文をBlockします。ボディ検査の上限が16KBなのに、このルールは8KBで止めるわけです。画像をBase64で送るAPIや、明細行の多い注文データを送るAPIは、攻撃ではなくても403になります。

対処は、このルールだけをRuleActionOverridesでCountに変えることです。ManagedRuleGroupStatementの定義には、マネージドルールではルール名が1文字でも違う上書きは黙って無視されると書かれています。大文字小文字まで一致させ、Count後のログでラベルawswaf:managed:aws:core-rule-set:SizeRestrictions_Bodyが付いても通過していることを確かめます。古いExcludedRulesではなくRuleActionOverridesを使うのが現行の書き方です。

aws-waf-logs-で始まるロググループへ出力し遮断したルールを特定する

WAFのログ出力先にCloudWatch Logsを選ぶ場合、ロググループ名はaws-waf-logs-で始め、Web ACLと同じリージョン・アカウントに作ります。

aws logs create-log-group --region ap-northeast-1 --log-group-name aws-waf-logs-api-prod

aws wafv2 put-logging-configuration --region ap-northeast-1 \
  --logging-configuration ResourceArn="$WEB_ACL_ARN",LogDestinationConfigs="arn:aws:logs:ap-northeast-1:111122223333:log-group:aws-waf-logs-api-prod"

# 直近1時間でBlockされたリクエストをルール別に数える(Logs Insights)
aws logs start-query --region ap-northeast-1 \
  --log-group-name aws-waf-logs-api-prod \
  --start-time $(date -d '-1 hour' +%s) --end-time $(date +%s) \
  --query-string 'filter action = "BLOCK" | stats count(*) by terminatingRuleId, httpRequest.uri | sort count(*) desc'

terminatingRuleIdが遮断したルール、httpRequest.uriがどのエンドポイントで起きたかを示します。特定のパスに集中している場合の対応は、そのルールをCountに変えるか、スコープダウン文でパスを除外する方法です。Cognitoのユーザープール宛てのリクエストは、ヘッダx-amzn-cognito-operation-nameでどのAPI操作かを見分けられます。ログの保存にはCloudWatch Logsの料金が別にかかります。

WAFを付けるべき公開APIと付けなくてよい閉じたAPIの採用判断

インターネットに公開し、不特定の利用者から呼ばれるREST APIには付けます。Web ACLとルールで月10ドル程度からなので、Lambdaオーソライザーの無駄な起動や、総当たりによるCognitoのスロットリングを防げるだけで元が取れます。

逆に、VPC内からだけ呼ぶプライベートAPIや、取引先数社にIPを固定してもらっているAPIでは過剰です。前者はネットワークで、後者はリソースポリシーで入口が絞れています。WAFはSQLインジェクションのような既知の型を入口で落とす仕組みで、認可の抜けや業務ロジックの欠陥は防げません。APIの代表的なリスクはAPIセキュリティとは?OWASP API Top 10の主要リスクと実装対策を解説で整理しています。WAFで塞げない箇所を含めたAPIの点検は、脆弱性診断・セキュリティ診断でご相談いただけます。

よくある質問

API GatewayとCognitoにAWS WAFを付けるときに出やすい疑問に、公式ドキュメントの記載をもとに答えます。WAFという仕組みの全体像はWAFとは?仕組み・ファイアウォール/IPS・IDSとの違いと企業の選び方を解説をご覧ください。

WAF Classicで作ったWeb ACLはAPI Gatewayにそのまま使えますか?

API GatewayのWAF連携ページは、WAFv2のリージョン用Web ACLとWAF Classicのリージョン用Web ACLの両方を関連付け先として挙げています。ただし、WCUやRuleActionOverrides、ボディ検査上限の変更はWAFv2の仕組みです。これから構成を作るなら、CLIはaws wafv2、Web ACLもWAFv2で作ります。

1つのWeb ACLを複数のステージやAPIで共用できますか?

できます。1つのWeb ACLは同じリージョンの複数のリソースに関連付けられ、REST APIのステージとCognitoユーザープールを混ぜても構いません。反対に、1つのステージやユーザープールに付けられるWeb ACLは1つだけです。共用すれば月額は下がる一方、ルールの変更はすべての関連付け先に同時に効きます。

エッジ型のREST APIにはCloudFront用のWeb ACLを付けるのですか?

付けません。エッジ型のREST APIでも、関連付けるのはAPIと同じリージョンで作ったリージョン用のWeb ACLです。API GatewayのWAF連携ページが求めるのは、エンドポイントの種類にかかわらずリージョン用のWeb ACLです。自前のCloudFrontを前段に置くなら、APIはリージョン型にして、CloudFront側にus-east-1のWeb ACLを付けます。

Cognitoの脅威保護とAWS WAFはどちらか一方でよいですか?

両方を同時に有効にできます。CognitoのWAF連携ページは、AWS WAFがすべての機能プランで使え、Cognitoの脅威保護を補う位置づけだと説明しています。WAFはIPやヘッダで入口のリクエストを落とし、ユーザー名単位の判断はできません。ユーザーごとの不審なサインインの検知は脅威保護の役割なので、要件に応じて重ねます。

レートベースルールの上限値はいくつに設定すればよいですか?

最小は10件で、評価ウィンドウは60・120・300・600秒から選びます。RateBasedStatementの定義によると、WAFは約10秒ごとに件数を確かめるため、上限ちょうどで止まるとは限りません。設定を変えるとカウントがリセットされます。まずCountで入れ、正規の利用者がピーク時に何件送るかをログで測ってから、その数倍を上限にします。

関連記事

お気に入りに入れた記事の一覧

この記事は以下の記事からリンクされています

資料請求

今日のトレンド記事 直近 24 時間で、いつもより多く読まれている記事

  1. 2026.10.15 テックブログ リゾートトラスト不正アクセス:会員2.6万件・カハラ横浜3.6万件の対象確認と窓口
  2. 2026.10.16 テックブログ ソースネクスト不正アクセスで最大2,252万件流出|ログインできない理由・パスワード再設定と会員APIの点検
  3. 2026.10.16 テックブログ バーガーキング不正アクセスで約1,118万件の情報漏洩|対象確認・案内メールの真偽と運営側のログ点検
  4. 2026.10.15 テックブログ 銀のさら不正アクセス:最大650万件の対象確認と窓口、パスワード変更の手順
  5. 2026.10.16 テックブログ ワラウ不正アクセスで連携トークン流出|Yahoo! JAPAN ID再連携と対象確認

RELATED POSTS 関連記事

目次