概要
多数のIPアドレスから読み取りリクエストが大量に届き、バックエンドのアプリケーションサーバーがスレッドを使い切って応答しなくなる。DDoSと呼ぶほど大規模でなくても、スクレイピングや壊れたクライアントのリトライで簡単に起きる状況です。
このとき、アプリケーション側でスレッド数を増やす、インスタンスをスケールアウトする、といった対処は根本解決になりません。過剰なリクエストがアプリケーションに届く前に落とすのが正しい層での対処です。
Application Load Balancer(ALB)にはAWS WAFを直接関連付けることができ、レートベースルールを使うと「一定時間内に同じ送信元から来たリクエスト数」で自動的にブロックできます。送信元IPが多数に分散していても、集約キーを変えることで対応できます。
この記事では、ALBの前段にWAFのWeb ACLを置き、レートベースルールで過剰なリクエストを遮断するまでを構築して確認します。

クラウドおさる過剰なリクエストは、アプリケーションに届く前に落とすのが正しい層での対処でござる。この記事では、ALB に WAF の Web ACL を関連付け、レートベースルールで 403 が返り始めるところまで、弊猿と一緒に確かめるでござるな。
この記事のメリット
- AWS WAFを関連付けられるリソースと、その中でALBを選ぶ理由を説明できるようになる
- レートベースルールの評価ウィンドウ・集約キー・制限値の意味を正確に理解できる
- Web ACLのルール優先順位とデフォルトアクションの関係を把握できる
- ブロックされたリクエストをサンプルリクエストで確認し、どのルールで落ちたかを追えるようになる
- 新しいWAFコンソールの「保護パック」の選び方と、有効にするルールによる月額の違いを画面で判断できるようになる
- SCS試験で「大量リクエストへの最もシンプルな対策」を問う設問に正確に答えられるようになる
執筆者とキャラクター紹介
執筆者:土肥(とひ)
株式会社ジェニュインの代表であり元エンジニア。これまでオンプレミスと AWS 環境のインフラ業務を担当。AWS 認定資格の学習で得た知識を、ハンズオンとともに解説するのが得意。直近では新人の教育も行っており、これから技術を学ぶ方が納得できる解説を心がけています。基礎編・Cloud Practitioner の記事では、解説役としても登場します。


クラウドおさる



はじめましてでござる。弊猿はクラウドおさる。IT インフラが異常に発達した猿山から、雲に乗って地上の AWS を学びに降りてきたのでござる。



基礎編や Cloud Practitioner の記事では、とひさんに素朴な疑問をぶつける役でござるな。Security - Specialty などの記事では、要所でワンポイントや注意点をひとこと添えるでござる。



猿山にもデータセンターや監視当番があって、地上で起きることはだいたい猿山にも同じ仕組みがあるのでござる。例え話がつい猿山に寄るのは、弊猿の癖でござる。
技術解説
WAFはどこに置けるか
AWS WAFのWeb ACLは、次のリソースに関連付けられます。
| 関連付け先 | スコープ | 用途 |
|---|---|---|
| Application Load Balancer | リージョン | ALB配下のアプリケーション全般 |
| Amazon CloudFront ディストリビューション | グローバル(CloudFront) | エッジで落としたい場合 |
| Amazon API Gateway REST API | リージョン | API単位の保護 |
| AWS AppSync GraphQL API | リージョン | GraphQL APIの保護 |
| Amazon Cognito ユーザープール / App Runner / Verified Access | リージョン | 各サービスの保護 |
Network Load Balancer(NLB)には関連付けられません。NLBはL4のロードバランサーで、HTTPリクエストの中身を見ないためです。設問で「NLBにWAFを付ける」という選択肢が出たら誤りです。
すでにALBがある構成なら、ALBにWeb ACLを関連付けるのが最短で、アプリケーションの変更も要りません。CloudFrontを挟めばエッジで落とせますが、そのためだけにCloudFrontを導入するのは「最もシンプル」からは外れます。



WAF を関連付けられるのは ALB や CloudFront、API Gateway などで、L4 の NLB には付けられぬのでござる。「NLB に WAF」という組み合わせは取り違えやすいので気をつけるでござるぞ。
レートベースルールの仕組み
レートベースルールは、指定した評価ウィンドウの中で、集約キーごとにリクエスト数を数え、制限値を超えたらルールのアクション(通常はBlock)を適用します。
| 設定 | 選べる値 | 補足 |
|---|---|---|
| レート制限 | 最小 10 | 評価ウィンドウ内のリクエスト数 |
| 評価ウィンドウ | 60 / 120 / 300 / 600 秒 | 既定は 300 秒(5分) |
| 集約キー | 送信元IP / 転送されたIP(X-Forwarded-For など) / カスタムキー / すべてカウント | カスタムキーではヘッダー・クッキー・クエリ・URIパス・HTTPメソッドなどを組み合わせられる |
重要な性質として、AWS WAFは制限値の「近く」でレート制限を適用しますが、完全に一致することは保証しません。「ちょうど100リクエスト目からブロックされる」と考えず、しきい値付近で効き始めるものと理解します。
ブロックは、そのキーのリクエストレートが制限を下回るまで継続します。恒久的なブロックではありません。


集約キーの選び方
「多数のIPから来る」場合、送信元IP単位では1つあたりのレートが低くなり、ルールに引っかからないことがあります。この場合は集約キーを変えます。
| 状況 | 集約キー |
|---|---|
| 単一または少数のIPから大量 | 送信元IPアドレス |
| CloudFrontやプロキシの背後 | 転送されたIPアドレス(X-Forwarded-For) |
| 特定のAPIパスだけが叩かれる | カスタムキー(URIパス)+スコープダウンステートメント |
| ログイン試行が多い | カスタムキー(HTTPメソッド + URIパス、必要ならヘッダー) |
スコープダウンステートメントを併用すると、「/search へのGETリクエストだけを対象にレートを数える」といった絞り込みができます。



送信元が多数の IP に分散していると、IP 単位では 1 つあたりのレートが低くなり、ルールに引っかからないことがあるのでござる。猿山でも、猿ごとにバナナの持ち出し回数を数えていると、大勢が少しずつ持っていく手口は見逃すでござろう。そういうときは、URI パスなどのカスタムキーに数える単位を変えるのでござる。
Web ACLの評価順序
Web ACLは、ルールを優先順位の小さい順に評価し、いずれかのルールがBlockまたはAllowと判定した時点で評価を終えます。どのルールにも一致しなかったリクエストにはデフォルトアクションが適用されます。
| 設定 | 意味 |
|---|---|
デフォルトアクション: Allow | ルールに一致しないものは通す(ブロックリスト型) |
デフォルトアクション: Block | ルールに一致しないものは落とす(許可リスト型) |
一般的なWebサイトの保護ではデフォルトアクションを Allow にし、レートベースルールやマネージドルールで危険なものだけを落とします。
なお、いきなり Block にすると正規の利用者を巻き込む恐れがあるため、まずアクションを Count にして様子を見る運用が定石です。Countはブロックせずに一致件数だけを記録します。
実践
既存のALB構成に対してWeb ACLを作成し、レートベースルールで過剰なリクエストが遮断されることを確認します。
前提条件
- リージョン:
ap-northeast-1(東京) - 以下のリソースが作成済みであること
| リソース種別 | リソース名 | 用途 |
|---|---|---|
| VPC | waf-lab-vpc | 検証用VPC(CIDR: 10.30.0.0/16) |
| パブリックサブネット | waf-lab-public-ap-northeast-1a / -1c | ALB配置用(2AZ) |
| セキュリティグループ | waf-lab-web-sg | EC2用(VPC内からのHTTPを許可) |
| EC2インスタンス | waf-lab-web-ap-northeast-1a / -1c | HTTPを返すWebサーバー2台 |
[!NOTE] 前提環境のTerraform資材は assets/56_q96_alb-waf-rate-based-rule にあります。ALBとWeb ACLは時間・月額の課金対象です(Web ACLは1つあたり月額 5 USD、ルール1つにつき月額 1 USD、いずれも時間割り。これに処理したリクエスト数に応じた料金が加わります)。検証後は削除してください。
このハンズオンで作成するリソースは以下のとおりです。
| リソース種別 | リソース名 | 用途 |
|---|---|---|
| セキュリティグループ | waf-lab-alb-sg | ALB用(インターネットからのHTTPを許可) |
| ターゲットグループ | waf-lab-tg | EC2 2台を登録 |
| Application Load Balancer | waf-lab-alb | WAFの関連付け先 |
| Web ACL(保護パック) | waf-lab-web-acl | レートベースルールを持つWeb ACL |
手順1: ALB用のセキュリティグループを作成する
AWSマネジメントコンソールにログインし、リージョンが ap-northeast-1(東京)であることを確認します。
上部の検索バーに EC2 と入力し、「EC2」を選択します。左側ナビゲーションの「ネットワーク&セキュリティ」→「セキュリティグループ」を選択し、「セキュリティグループを作成」をクリックします。
以下を設定します。
- セキュリティグループ名:
waf-lab-alb-sg - 説明:
ALB for WAF lab - VPC:
waf-lab-vpc - インバウンドルール: タイプ
HTTP、ソースマイIP


「セキュリティグループを作成」をクリックします。
手順2: ターゲットグループとALBを作成する
左側ナビゲーションの「ロードバランシング」→「ターゲットグループ」を選択し、「ターゲットグループの作成」をクリックします。
- ターゲットタイプ:
インスタンス - ターゲットグループ名:
waf-lab-tg - プロトコル・ポート:
HTTP/80 - VPC:
waf-lab-vpc
「次へ」をクリックし、waf-lab-web-ap-northeast-1a と -1c の2台を選択して「保留中として以下を含める」をクリックし、「ターゲットグループの作成」で作成します。


左側ナビゲーションの「ロードバランサー」を選択し、「ロードバランサーの作成」をクリックします。ロードバランサータイプを比較する画面が表示されるので、「Application Load Balancer」の「作成」をクリックします。
以下を設定します。
- ロードバランサー名:
waf-lab-alb - スキーム:
インターネット向け - VPC:
waf-lab-vpc - マッピング:
ap-northeast-1aとap-northeast-1cのパブリックサブネットを選択 - セキュリティグループ:
waf-lab-alb-sg(デフォルトのSGは外す) - リスナー:
HTTP:80→ 転送先waf-lab-tg


「ロードバランサーの作成」をクリックし、状態が「アクティブ」になるまで待ちます。
DNS名をブラウザで開き、Webサーバーの応答が返ることを確認します。


手順3: Web ACL(保護パック)を作成してレートベースルールを追加する
[!NOTE] AWS WAFのコンソールは刷新され、Web ACLは「保護パック (ウェブ ACL)」という名前で、保護したいリソースを起点に作成する流れになりました。名前と画面構成が変わっただけで、作られるものは従来どおりのWeb ACLです。API・CLI(
wafv2)の呼び出し方も変わりません。画面上部の案内から「以前のコンソールに切り替えてください」を選ぶと、従来の画面も使えます。
上部の検索バーに WAF と入力し、「WAF & Shield」を選択します。
「リソースと保護パック (ウェブ ACL)」の画面が開きます。「リージョンのスコープ」が CloudFront (グローバル) とリージョンレベル になっていることを確認し、「保護パック (ウェブ ACL) を作成」をクリックします。
アプリについて教えてください のセクションで、以下を選択します。ここで選んだ内容は、次のステップで推奨されるルールの内容に反映されます。
- アプリカテゴリ:
コンテンツおよび公開システム - アプリケーションフォーカス:
ウェブ
保護するリソースを選択 のセクションで「リソースを追加」→「リージョンリソースを追加」を選びます。ダイアログに保護できるリージョンリソースの一覧が表示されるので、waf-lab-alb(Application Load Balancer)にチェックを入れて「追加」をクリックします。
初期の保護を選択 のセクションでは、ルールの組み合わせを3つから選びます。
| 選択肢 | 内容 |
|---|---|
| お客様のために推奨されるルール | 「重要」のすべて + レート制限やIPレピュテーション、Bot Controlなどを含む |
| 重要ルール | レイヤー7 DDoS対策、コアルールセット、SQLインジェクション保護などの基本セット |
| AWS WAF が提供するすべての保護から独自のパックを構築 | 適用するルールを自分で選ぶ |
それぞれに「1,000万リクエストあたりの推定コスト」が表示されます。マネージドルールグループを含むパックほど高くなるため、何を有効にすると課金がどう増えるかを、作る前に画面上で確認できます。
この記事ではレートベースルールだけを試すので、「AWS WAF が提供するすべての保護から独自のパックを構築」 を選択します。
名前を付けて、説明を入力 のセクションで、名前に waf-lab-web-acl を入力します。名前は後から変更できません。


独自のパックを選ぶと「ルールを追加」のパネルが開きます。以下の順に選択します。
- ルールの種類:
カスタムルールを選んで「次へ」 - 作成するルール:
レートベースのルールを選んで「次へ」
レートベースルールの設定画面で、以下を入力します。
- アクション:
Block - ルール名:
rate-limit-per-ip - レート制限:
100 - 評価ウィンドウ:
1 分
「ルール設定」を展開し、「リクエスト集約」が 送信元 IP アドレス になっていることを確認します。


「ルールを追加」をクリックします。ルールを1つ追加すると、「独自のパックを構築」の推定コストが増えることが確認できます。
画面下部の「保護パック (ウェブ ACL) を作成」をクリックします。作成が完了すると、ALBとの関連付けまで自動で行われ、「以下のリソースが関連付けられています: waf-lab-alb」というメッセージが表示されます。
一覧に戻り、waf-lab-web-acl の「ルール」列の「1 個のルール」をクリックすると、追加した rate-limit-per-ip が表示されます。


デフォルトアクションは新しいコンソールのウィザードには表示されませんが、既定で Allow(どのルールにも一致しないリクエストは許可)が設定されます。CLIで確認できます。
aws wafv2 get-web-acl \
--name waf-lab-web-acl --scope REGIONAL \
--id <Web ACL の ID> --region ap-northeast-1 \
--query 'WebACL.{Default:DefaultAction,Rules:Rules[].{Name:Name,Action:Action,Rate:Statement.RateBasedStatement}}'{
"Default": { "Allow": {} },
"Rules": [
{
"Name": "rate-limit-per-ip",
"Action": { "Block": {} },
"Rate": { "Limit": 100, "AggregateKeyType": "IP", "EvaluationWindowSec": 60 }
}
]
}手順4: 制限を超えるリクエストを送ってブロックを確認する
手元の端末から、ALBのDNS名に対して短時間に大量のリクエストを送ります。
ALB=<ALBのDNS名>
for i in $(seq 1 300); do
curl -s -o /dev/null -w "%{http_code}\n" "http://$ALB/"
done | sort | uniq -c1回目の実行では、すべて 200 が返ることがあります。
300 200これは設定が効いていないのではなく、レート制限が効き始めるまでに時間差があるためです。AWS WAFは評価ウィンドウの設定とは別のタイミングでリクエストレートを繰り返しチェックしており、しきい値を超えた瞬間にブロックが始まるわけではありません。
リクエストを送り続けると、やがてブロックが始まります。
for round in 1 2 3; do
seq 1 200 | xargs -P 10 -I{} curl -s -o /dev/null -w "%{http_code}\n" "http://$ALB/" \
| sort | uniq -c | tr '\n' ' '
echo
done 200 403
200 403
200 403送信元IPあたりのレートが制限を超えた状態が続く間、そのIPからのリクエストは 403 で遮断され続けます。
[!NOTE] AWS WAFは設定した制限の近くでレート制限を適用しますが、制限との完全一致は保証しません。「ちょうど100件目から403になる」とは考えず、しきい値付近で効き始め、少し遅れて反映されるものと理解します。



1 回目はすべて 200 が返ることがあり、送り続けるとやがて 403 が混じり始めたでござるな。レートベースルールはしきい値ちょうどで効くのではなく、しきい値付近で少し遅れて効き始めるものでござる。
手順5: ブロックされたリクエストをWAF側で確認する
保護パックの一覧に戻り、waf-lab-web-acl の「サンプルリクエスト」列の「表示」をクリックします。「ダッシュボード」と「設定」の選択が表示されるので、「ダッシュボード」を選びます。
ダッシュボードの「概要」に、指定した時間範囲のリクエスト数が「合計 / 許可済み / ブロック済み」で表示されます。その下の「保護パック (ウェブ ACL) のアクティビティ」では、すべてのトラフィックが rate-limit-per-ip に入り、ブロック済みとデフォルトアクション(許可済み)に分かれていく流れが図で確認できます。


画面下部の「サンプルリクエスト」パネルに、直近のリクエストのサンプルが表示されます。「リクエストをフィルタ」に BLOCK と入力すると、遮断されたリクエストだけに絞り込めます。
メトリクス名の列が、許可されたリクエストでは waf-lab-web-acl(デフォルトアクション)、遮断されたリクエストでは rate-limit-per-ip(一致したルール名)になっている点に注目します。どのルールで落とされたかがここで分かります。


リクエストを止めてしばらく待つと、レートが制限を下回りブロックが解除されます。再度アクセスして 200 が返ることを確認します。
手順6: Countモードで影響を測る(任意)
保護パックの一覧で「ルール」列の「1 個のルール」をクリックし、「ルールを管理」のパネルから rate-limit-per-ip を開きます。
「アクション」を Count に変更し、「ルールを保存」をクリックします。


Countはブロックせず一致件数だけを記録します。本番環境に新しいルールを入れる前に、まずCountで「どれだけ正規のリクエストが引っかかるか」を測るのが定石です。手順3の「初期の保護を選択」で用意されているパックでも、レート制限系のルールが既定で Count になっているのは同じ考え方によるものです。



大量リクエストへの対策で、既にある ALB に Web ACL を付けてレートベースルールで落とすのが最もシンプル、と見抜けるかが問われる観点でござる。WAF を付けられないリソースや、評価ウィンドウ・集約キーの意味も、取り違えやすいところでござるな。
まとめ
| 論点 | 結論 |
|---|---|
| 大量リクエストへの最短の対策 | ALBにWeb ACLを関連付け、レートベースルールで落とす |
| WAFを付けられないもの | NLB(L4のため)。ALB・CloudFront・API Gateway などが対象 |
| レートベースルールの単位 | 評価ウィンドウ(60/120/300/600秒、既定300秒)内の、集約キーごとのリクエスト数 |
| 制限値の下限 | 10 |
| 効き方 | 制限値の近くで効き始め、レートが下がると自動的に解除される |
- 送信元IPが分散している場合は、集約キーをカスタムキー(URIパスやヘッダー)に変える
- 新しいルールはまず
Countで影響を測り、問題なければBlockに切り替える - デフォルトアクションは、一般的なWeb公開なら
Allow、許可リスト型にするならBlock - 検証後はWeb ACL・ALB・ターゲットグループを削除する(課金が続くため)
参照先
- レートベースのルールステートメント – AWS WAF
- レートベースのルールの高レベル設定 – AWS WAF
- レートベースのルールの集計オプション – AWS WAF
- ウェブ ACL を AWS リソースに関連付ける – AWS WAF
- ウェブ ACL のルールとルールグループの評価順序 – AWS WAF
- AWS WAF の料金










