AWS WAFを使ってリクエストサイズの制約を設定する

はじめに

イタンジ株式会社の李です。SREとしてイタンジサービスの信頼性を向上するための施策やコスト最適化などをしています。

本記事ではAWSのWAFを使ってリクエストサイズの制約をかける方法を紹介しようと思います。

背景

RailsアプリケーションをECSサービスでデプロイしている一部のプロダクトで、静的コンテンツの配信や制約条件を入れる目的でRailsの前段にnginxサーバーを配置する場合がありますが、

  • 静的コンテンツの配信が不要
  • 現状のリクエスト数だとreverse proxyが必要なほど負荷が高くない、ALBの負荷分散だけでも十分

の経緯で果たしてnginxをRailsの前端に置いておく必要があるかの疑問が湧いてきました。上記のことで開発陣で相談してみた結果、nginxを剥がしてみようとの結論になったので早速作業に着手しました。

課題

ただ、nginxに設定している client_max_body_size をどうするかの問題がありました。ファイルを添付するなどの機能があるサービスは、容量があまりにも大きいリクエストは受け付けないようにnginxで設定していましたので、nginxを剥がす前にリクエスト容量の制約をどこかに移行する必要がありました。

解決方法

WAFのサイズ制約ルールステートメントを使用しリクエストボディのバイト数で制約をかけることで問題の解決ができました。取り組みする当時はWAFの知識がそこまでなかったので、この解決方法にたどり着くまで割と時間がかかってしまいました。

実装してみよう

以下のTerraformコードを実行することでALBにWAFを設定しボディーサイズ制約のルールを掛けることができました。

# ALB
resource "aws_lb" "load_balancer" {
  ...
}

# WAFを作成して制約条件を掛ける
resource "aws_wafv2_web_acl" "web_acl" {
  name  = "web-acl"
  scope = "REGIONAL"

  default_action {
    allow {}
  }

  # ボディーサイズが12MBを超過するリクエストはブロックするルール
  rule {
    name     = "request-max-body-size-rule"
    priority = 1

    action {
      block {}
    }

    statement {
      size_constraint_statement {
        comparison_operator = "GT"
        size                = 1024 * 1024 * 12 # 12MB

        field_to_match {
          body {}
        }

        text_transformation {
          priority = 0
          type     = "NONE"
        }
      }
    }

    visibility_config {
      cloudwatch_metrics_enabled = true
      metric_name                = "request-max-body-size-rule"
      sampled_requests_enabled   = true
    }
  }

  visibility_config {
    cloudwatch_metrics_enabled = true
    metric_name                = "web-acl"
    sampled_requests_enabled   = true
  }
}

# ALBにWAFを設定する
resource "aws_wafv2_web_acl_association" "load_balancer_web_acl" {
  web_acl_arn  = aws_wafv2_web_acl.web_acl.arn
  resource_arn = aws_lb.load_balancer.arn
}

実装は簡単でしたが、実装に必要な知識を得るまでが結構時間がかかりました。

実装の検証

ルールにカウントされたサンプルリクエスト

12MB以上のファイルを添付したリクエストがWAFのルールでカウントされたことが確認できました。 (動作確認のため一時的にアクションをカウントにしたもので、検証できたのでブロックに変更しました。)

終わりに

今回はALBにWAFを設定してリクエストサイズの制約を入れてみました。

方法がわかっていれば割とすぐに解決できる問題でしたが、WAFの知識が浅い状態で取り組みを始めたら課題解決までの時間が思ったよりかかってしまいました。しかし、この案件を通してWAFについて深掘りして知識を貯めることができたので、今後にWAFの力が必要そうな案件が出てきたら積極的に駆使していこうと思います。