WAFの誤検知は、403を返したルールをログで特定し、必要な経路だけに例外を設けます。EKSの脆弱性対応では、検出されたイメージと稼働中のPodを照合すると、どのサービスから対応すべきかを判断できます。
この記事でわかること
- WAFとアプリのどちらが403を返したかをログで見分ける方法
- 正常な注文を通しながら、既存の遮断が働くことを確認する手順
- PHP2Shellを例に、影響調査から修正版の展開・再スキャンまで進める手順
前提条件として、AWS WAFを関連付けたApplication Load Balancer(ALB)の背後で、Amazon EKS上の購入APIが動く架空の環境を使います。調査には対象のWAF・ALBログへの読み取り権限と、対象クラスタのPodを取得できる kubectl が必要です。ログ、件数、コマンド出力は説明用の例です。
1. 403を返した場所をログで確かめる
アラートを「どのリクエストが失敗したか」に落とす
10時にAWSのマネージドルールを有効化しました。直後の5分間で、購入APIの403が4件から160件に増えたとします。入口のログで同じホスト、パス、HTTPメソッドに絞ると、変更前後ともリクエストは2,000件。403率は0.2%から8%へ悪化しています。アプリに到達した購入リクエストも同じ時間に減っています。
ここまでで分かるのは、変更時刻と症状が重なっていることです。アプリの認可処理やALBの固定応答でも403は返り得ます。ステータスコードだけでWAFを原因と判断せず、Web ACLのログとALBのアクセスログを照らし合わせます。対象リクエストが同一かは、突合に使える識別子があればそれを、使えなければ時刻、ホスト、パス、メソッドなどを組み合わせて確かめます。
CloudWatch Logs Insightsで遮断を集計する
対象Web ACLのログをCloudWatch Logsへ配信している前提です。変更前後の時間範囲を選び、対象ホストと購入APIを絞ります。次の例ではホストを共有しないロググループを使っています。
fields @timestamp, action, terminatingRuleId
| filter httpRequest.uri = "/api/checkout"
and httpRequest.httpMethod = "POST"
and action = "BLOCK"
| stats count(*) as blocked by bin(5m) as window, terminatingRuleId
| sort window asc
window terminatingRuleId blocked
10:00 CommonRuleSet 152
10:00 RateLimit 4
terminatingRuleId は評価を終了させたルールの識別子です。遮断のない時間帯は行が表示されません。この例ではWAFの遮断が156件あり、大半はマネージドルールグループに集中しています。ALB側の160件の403と件数は近いですが、この集計だけでは個々の403の原因は分かりません。WAF側の件数をそのまま全体の403率として扱わず、入口側で同じ条件を集計した分母を使います。 AWS WAFのログ項目
個別ログでルール名を確認し、再現する
グループ内の個別ルールは、該当イベントの ruleGroupList[].terminatingRule.ruleId で確認します。例では SizeRestrictions_BODY で、labels に awswaf:managed:aws:core-rule-set:SizeRestrictions_Body が残っています。これは8,192バイトを超えるリクエスト本文に一致するルールです。検証環境で同じAPIに架空の注文を送り、約6KBでは通過し、約10KBでは同じルールで止まることを確かめます。本文のバイト数を比較し、個人情報を含む実注文は再送しません。 AWSマネージドルールの仕様
一方、403が出た時刻に遮断ログが0件なら、Web ACLとALBの関連付け、ロググループ、タイムゾーン、ログフィルターを先に確認します。ALBログの target_status_code が 403 なら、ターゲットが返した応答なので、認可の変更やアプリログを調べます。elb_status_code=403 かつ target_status_code=- の場合は、actions_executed が waf で終わっているかを見て、WAFによる遮断と固定応答を切り分けます。 ALBアクセスログ
2. AWS WAFの例外を絞り、守るべき通信を再確認する

どの経路で大きな本文が必要かを決める
アプリ担当に確認すると、商品点数の多い注文では10KB程度のJSONが正規仕様でした。今回例外を検討する対象は shop.example.com の POST /api/checkout です。同じWeb ACLが別ホストも保護しているなら、同じパスがあっても例外の対象に含めません。正常な注文がすべて8KB以内に収まる設計なら、本文の肥大化をアプリ側で直す判断もあります。
ALBでWAFが検査できる本文は先頭8,192バイトです。ルールのサイズ制限を緩めて10KBを通すと、WAFが本文の末尾まで検査できるわけではありません。アプリ側で本文全体に対するサイズ上限、JSONスキーマ、認証・認可を確認します。本文全体を検証できる見通しが立たない間は、大きな注文の扱いをアプリ担当と決めます。 AWS WAFの本文検査上限
Countとラベルで1ルールの例外を作る
マネージドルールグループの中で SizeRestrictions_BODY だけを RuleActionOverrides で Count にします。Countは一致を記録して評価を続けるアクションです。その後に、対象ラベルが付き、かつ購入APIのホスト・メソッド・パスの組に一致しない場合に遮断するカスタムルールを置きます。
優先順位 100 CommonRuleSet
SizeRestrictions_BODY のみ Count
優先順位 110 対象ラベルあり AND NOT(購入APIのホスト・メソッド・パス)
→ Block
以降 既存のルールを評価
購入APIに対する早い順位の Allow は、そこで評価を終わらせます。上の構成は、その経路でも後続ルールを評価します。既存の終端ルールによりラベル参照まで届かない通信や、別ルールが先に止める通信もあるので、Web ACL全体の評価順を確認します。パスの照合では、末尾スラッシュやURLエンコードをアプリ側がどう扱うかも確認します。 AWS WAFのラベル・AWSの誤検知管理ガイド
正常系と遮断系をセットで試し、切り戻し条件を決める
| 検証環境の入力 | 期待する結果 |
|---|---|
| 購入APIへ正規の10KBの注文 | 購入が成功し、サイズルールへの一致が記録される |
| 別パスへ同じサイズの本文 | ラベルを参照するカスタムルールで遮断される |
| 購入APIへ別の有効な遮断ルールに一致するテスト入力 | 該当する別ルールで遮断される |
| 購入APIへ仕様上の上限を超える本文 | アプリが拒否し、注文が作られない |
Count変更後のログでは、最終アクションと途中で一致したルールを分けて見ます。ラベルが付いていても、最終アクションが ALLOW の場合と、別ルールの BLOCK の場合があります。Countの件数だけでは注文の成否は分かりません。
本番反映前に、購入成功率、購入APIの403率、別経路での遮断件数を変更前と比較できるようにします。別経路で止めるべき通信が通過した場合は、保存したWeb ACL設定に戻します。元に戻せば大きな注文も再び止まるため、その影響と暫定運用をアプリ担当と共有します。例外を恒久化するか、アプリの改修後に撤去するかは、担当者と見直し日を決めて記録します。
3. PHP2Shellを例に、EKSコンテナの影響範囲を判定する
速報から自分たちが確認すべき条件を抜き出す
IPAが2026年10月22日に公表したPHP2Shellの注意喚起では、PHPの2つの脆弱性(CVE-2026-109618、CVE-2026-109619)による遠隔からのコード実行の可能性を説明しています。10月26日には、米国CISAの悪用が確認された脆弱性のカタログに掲載されました。IPAの情報は11月2日に更新されています。ここまでが公表情報です。自分たちの環境に影響があるかは、実際のPHPの配布元・バージョンと、外から到達する処理を照合して判断します。 IPAのPHP2Shell注意喚起・AWSのセキュリティ速報
たとえば上流PHPの8.4系では、IPAが8.4.27を修正版として挙げています。ディストリビューションが修正をバックポートする場合は、上流のバージョン文字列だけで決めず、配布元のパッケージ版とアドバイザリを確認します。アプリの依存関係だけを棚卸しすると、ベースイメージのPHPランタイムを見落とすことがあります。
Inspectorの検出を実行中のPodと照合する
ECRの拡張スキャンでは、InspectorがOSや言語パッケージの脆弱性を検出します。対象リポジトリ、イメージのダイジェスト、パッケージ名、検出バージョン、修正情報を控えます。ダイジェストはイメージの内容を識別する値です。Inspectorの実行環境との関連付けを手がかりに、対象クラスタでも稼働中の値を確認します。 InspectorによるECRイメージスキャン
kubectl -n shop get pods -l app=checkout \
-o custom-columns='POD:.metadata.name,IMAGE:.spec.containers[*].image,IMAGE_ID:.status.containerStatuses[*].imageID'
POD IMAGE IMAGE_ID(抜粋)
checkout-a checkout:prod …@sha256:aaaa…
checkout-b checkout:prod …@sha256:aaaa…
checkout-c checkout:prod …@sha256:bbbb…
IMAGE はPod仕様の参照、IMAGE_ID はランタイムが報告する識別子です。この例で検出対象が aaaa… なら、同じタグを使っていても2台で対象イメージが稼働しています。複数CPUアーキテクチャ向けのイメージでは、イメージインデックスとプラットフォーム別マニフェストを区別し、実際の参照を照合します。このコマンドの範囲は一つの名前空間とラベルに限られるため、別クラスタ、サイドカー、JobやCronJobのテンプレートも確認します。 Kubernetesのコンテナイメージ
稼働、到達性、悪用の証拠を別々に判断する
| 観測したこと | 次の判断 |
|---|---|
| 対象ダイジェストのPodが公開サービスの配下にある | 公開経路とPHPの構成を確認し、修正を優先する。修正版が間に合わなければ該当経路の一時停止を検討する |
| 対象は外部入口のない定期ジョブで使われている | ジョブの入力や内部からの到達性も確認し、影響と修正期限を決める |
| 対象はレジストリにあるが稼働先が見つからない | 休止中の処理や過去の展開を確認し、再利用されないようにする |
| 悪用を疑うリクエストや異常な実行の痕跡がある | ログを保全し、修正と並行してインシデント対応を進める |
PHP2Shellのような速報が出たときに、WAFルールの一致だけで悪用の成否を判定することはできません。入口のログ、アプリのログ、利用できる実行時の証跡を時系列で確認します。調べた期間、保存期間の制約、取得できなかった証跡も記録します。
4. 修正版を展開し、完了を証明する

修正する層に合わせてイメージを作り直す
アプリ依存の脆弱性ならロックファイルを更新し、OSパッケージなら配布元の修正版を含むベースイメージを選びます。今回のPHPの例では、実際にランタイムを供給するベースイメージやパッケージを更新します。EKS on Fargateでも、AWSが管理する基盤OSと自チームが配るコンテナイメージは管理範囲が別です。ベースのダイジェストを更新した変更をレビューし、再ビルドしたイメージのパッケージ版とスキャン対象を確認します。 EKS FargateのOSパッチ・Dockerのビルド指針
少数に展開し、サービスが正常かを確かめる
修正版のダイジェストを指定し、既存の段階展開の仕組みで少数のPodから切り替えます。まず正常な注文と、修正したランタイムを実際に通る機能をテストします。本番では変更前と同じ経路の成功率、5xx率、処理時間を比較します。段階展開に必要なリクエスト数が集まっていなければ、数分間エラーが出なかったことだけで全体へ進めません。
異常があれば展開を止め、原因を切り分けます。旧イメージに戻す必要がある場合は、脆弱性が戻ることを前提に、該当経路の停止などの暫定策を継続します。先に安定版の修正済みイメージが用意できていれば、切り戻し候補として使えます。
修正完了と侵害調査の進捗を分けて報告する
最後に、対象の全Podやジョブ定義で修正版を参照し、稼働中の識別子も一致することを確認します。新しいダイジェストのスキャンが完了し、対象CVEの指摘が解消したことを確認します。結果が空なら、スキャン対象外や未完了でも空になり得るため、スキャン状態を見ます。旧ダイジェストがレジストリに残っていれば、旧イメージへの指摘は引き続き表示されることがあります。 ECR拡張スキャンの対象条件
公開の購入APIで対象イメージが2 Pod稼働していました。全Podで修正版のダイジェストを確認し、新イメージのスキャンと購入テストが完了しました。過去ログの調査は継続中です。確認済みの時間範囲と次回報告時刻は対応記録に記載しました。
手元のランブックにも、WAFなら「どのルールが遮断したか」、コンテナなら「どのダイジェストが稼働していたか」を記録する欄を作っておくと、次の当番が判断の根拠を引き継げます。役に立ったら、いいねで知らせてもらえるとうれしいです。

コメント