0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

AWS WAFは動いてるフリをします

0
Last updated at Posted at 2026-02-23

最初に結論

AWS WAF のマネージドルールを COUNT にすると、リクエストにラベル(ARN 形式の文字列)が付与されます。このラベルを後段のカスタムルールで拾ってリクエスト制御するパターンはよく使われますが、ラベルの文字列を1文字でも間違えると、エラーは一切出ないのにルールが機能しないという状態に陥ります。

前提:マネージドルール + カスタムルールの構成

AWS WAF でマネージドルールを柔軟に運用するとき、以下のような構成がよく使われます。

Step 1: マネージドルールの特定ルールを COUNT に切り替える

マネージドルールの中で、特定パスだけ除外したいルールがあるとします。マネージドルール単体では「このパスだけ除外」のような細かい制御ができないため、一旦 COUNT モードにしてリクエストをブロックせずにラベルだけ付与させます。

managed_rule_group_statement {
  name        = "AWSManagedRulesCommonRuleSet"
  vendor_name = "AWS"

  rule_action_override {
    name = "SizeRestrictions_BODY"  # ← これはルール名
    action_to_use {
      count {}
    }
  }
}

このとき AWS は、マッチしたリクエストに対して以下のようなラベルを付与します。

awswaf:managed:aws:core-rule-set:SizeRestrictions_Body

### Step 2: カスタムルールでラベルを拾ってリクエスト制御

後段のカスタムルールで `LabelMatchStatement` を使い、Step 1 で付与されたラベルを拾います。これにより「特定パスだけ許可、それ以外はブロック」という細かい制御が可能になります。

```hcl
rule {
  name   = "Check_SizeRestrictions_BODY"
  action = "block"

  statement {
    and_statement {
      statements {
        label_match_statement {
          scope = "LABEL"
          key   = "awswaf:managed:aws:core-rule-set:SizeRestrictions_Body"
          #                                                          ^^^^
          #                                              ここが正しければ機能する
        }
      }
      statements {
        not_statement {
          byte_match_statement {
            # 除外したいパスの条件
            search_string         = "/api/image/upload"
            positional_constraint = "STARTS_WITH"
            field_to_match { type = "uri_path" }
          }
        }
      }
    }
  }
}

マネージドルール(COUNT)→ ラベル付与 → カスタムルールで拾ってブロック、この流れ自体は AWS が推奨するパターンです。

落とし穴:ラベルの ARN はキャメルケース

ここからが本題です。

マネージドルールが付与するラベルはこういう形式です。

awswaf:managed:aws:core-rule-set:SizeRestrictions_Body
                                                  ^^^^
                                                  PascalCase

一方、ルール名はこうです。

SizeRestrictions_BODY
                 ^^^^
                 全大文字

ルール名とラベルで大文字小文字が違います。

ルール名 付与されるラベル
SizeRestrictions_BODY ...SizeRestrictions_Body
CrossSiteScripting_BODY ...CrossSiteScripting_Body

ルール名は _BODY(全大文字)ですが、ラベルは _Body(PascalCase)です。

ルール名を見て key を書くと、こうなります。

label_match_statement {
  scope = "LABEL"
  key   = "awswaf:managed:aws:core-rule-set:SizeRestrictions_BODY"
  #                                                          ^^^^
  #                              ルール名からコピーして _BODY と書いてしまう
}

LabelMatchStatement は case-sensitive です。_BODY_Body は別の文字列なので、このルールは一生マッチしません。

最大の罠:間違えてもエラーにならない

ここが一番厄介なところです。

間違ったラベルで terraform planterraform apply しても、すべて成功します。 AWS API もエラーを返しません。

なぜか。

AWS WAF のラベルはもともと任意の文字列を付けられる仕組みです。マネージドルールが付与するラベルだけでなく、カスタムルールでも自分で定義したラベルを自由に付けることができます。LabelMatchStatement はリクエストに付いたラベル文字列をただ比較しているだけです。

つまり AWS から見れば、SizeRestrictions_BODY というラベルを参照しようとしているのが「マネージドルールのラベルのタイポ」なのか「カスタムラベルの正しい参照」なのか区別がつきません。どちらも有効な文字列なので、エラーにしようがないのです。

IAM ポリシーで存在しないリソースの ARN を書けばエラーになりますが、WAF のラベルマッチはそうはいきません。

どうなるか:一見動いているように見える

間違ったラベルを設定しても、WAF 全体としてはエラーなく動き続けます。

リクエスト着信
  ↓
マネージドルール発火 → ラベル付与: SizeRestrictions_Body  (正しいラベル)
  ↓
カスタムルールで LabelMatchStatement 評価
  key = "SizeRestrictions_BODY"  ← 設定した値
  ≠     "SizeRestrictions_Body"  ← 実際のラベル
  ↓
マッチしない → and_statement = false → ルール不発火
  ↓
リクエスト通過(ブロックされない)
  • WAF のコンソールにルール自体は表示されている
  • terraform plan でも差分なし
  • エラーログも出ない
  • ただし、ブロックすべきリクエストがすべて素通りしている

「セキュリティルールを設定したはずなのに、実は何も守っていなかった」という状態が、気づかれないまま続きます。

気づくには

WAF ログを確認します。

  • マネージドルールが COUNT で付与したラベルがログに記録されている
  • しかし後段のカスタムルールが BLOCK していない
  • リクエストの最終アクションが ALLOW になっている

この組み合わせが見えたら、ラベルの不一致を疑ってください。

対策

1. 公式ドキュメントの Labels 列からコピーする

ルール名ではなく、必ず 公式ドキュメントの Labels 列 からラベル文字列をコピーしてください。

2. locals で一元管理する

locals {
  waf_labels = {
    size_restrictions_body    = "awswaf:managed:aws:core-rule-set:SizeRestrictions_Body"
    cross_site_scripting_body = "awswaf:managed:aws:core-rule-set:CrossSiteScripting_Body"
  }
}

ラベルを変数化して参照すれば、複数箇所で同じ文字列を書くリスクがなくなります。

3. 設定直後にテストリクエストで確認する

意図的にルール発火条件を満たすリクエスト(8KB超のボディなど)を投げて、ブロックされることを確認しましょう。dev/stg で「なぜか通る」場合はラベルを疑ってください。

まとめ

マネージドルールの「ルール名」 ≠ 「付与されるラベル」
  • マネージドルールを COUNT にするとラベル(ARN 形式)が付与される
  • そのラベルを LabelMatchStatement で拾ってリクエスト制御するのはよくあるパターン
  • ラベルの ARN はキャメルケースで書かれているが、ルール名は全大文字の箇所がある
  • 間違った文字列を書いても AWS はエラーを返さない(ラベルは任意の文字列なのでバリデーションできない)
  • 結果、一見ルールが動いているように見えて、実は何もブロックしていない状態になる

ルール名をそのままコピーしてラベルの key に使うのは自然な行動ですが、それが罠です。

参考

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?