Skip to content

CloudFront WAF アーキテクチャ設計書

ドキュメント情報

  • 作成日: 2026-03-06
  • 対象環境: production (fastdoctor.jp)

関連ドキュメント

本ドキュメントは、CloudFront WAFのアーキテクチャ設計を記載しています。以下の関連ドキュメントも合わせて参照してください:

ドキュメントパス状態概要
WAF監視・アラート設計書/docs/datadog/monitoring-guides/waf-monitoring-alert-design.md✅ 作成済みDatadogダッシュボード、アラート設定、Log-based Metrics

目次

  1. アーキテクチャ概要
  2. WAF ルール構成
  3. Terraform 実装設計
  4. ログ・モニタリング設計
  5. WAF Labels によるログ可視化
  6. マネージドルールのバージョン管理
  7. CloudFront Staging Distributionの検討と制約
  8. 事前検証とデプロイフロー
  9. 今後のタスク・実装計画

アーキテクチャ概要

全体構成図

コンポーネント一覧

コンポーネントリージョン/場所役割
CloudFront DistributionGLOBALCDN、HTTPS配信、WAF統合
AWS WAF Web ACLus-east-1WAF ルールエンジン
CloudWatch Logsus-east-1WAF ログ保存
CloudWatch Metricsus-east-1WAF メトリクス
Vercel (fastdoctor-jp-v2)Externalメインアプリケーション
Vercel (headlesscms)ExternalヘッドレスCMS
ロリポップ (production-fastdoctor)Externalレガシーアプリケーション
コーポレートサイトap-northeast-1企業サイト(corporate.fastdoctor.jp)

WAF ルール構成

Cloudflare 設定からの移行方針

基本方針: Cloudflareで有効化されていたルールをAWS WAFで再現し、段階的に運用を開始する

Cloudflare設定との対応:

Cloudflare機能状態AWS WAF相当導入Phase
OWASP コア✅ 有効(ブロック)Core Rule Set (CRS)Phase 1 (Count) → Phase 2 (Block)
Cloudflare Managed Ruleset✅ 有効IP Reputation + Known Bad InputsPhase 1 (Count) → Phase 2 (Block)
IP Access Rules推定有効IP Set (AS9009等)Phase 1 (Block)
Exposed Credentials Check✅ 有効❌ AWS WAF相当機能なし-
スーパー ボット ファイト モード✅ 有効Bot Control($10/月)Phase 3以降で検討
スキーマ検証✅ 有効❌ AWS WAF相当機能なし-
HTTP DDoS保護(自動)デフォルトShield Standard(自動)デフォルト有効

Phase 3以降の検討事項(Cloudflareに無かった追加保護):

  • Geographic Blocking(日本以外ブロック): Cloudflareでは未設定。国外からの正規アクセスがないことを確認後、導入判断
  • Rate Limiting: CloudFront Shield StandardでL7 DDoS保護があるため、基本的に不要。Shield Standardで不足する場合のみ検討
  • Bot Control ($10/月追加): Cloudflareのスーパー ボット ファイト モード相当。Phase 2運用後、ボットトラフィック状況を分析して導入判断
  • その他のマネージドルールグループ(Anonymous IP List等)

AWS Shield Standard について:

  • CloudFrontには無料で自動付属
  • L3/L4 DDoS保護に加え、L7(HTTP Flood等)もある程度自動緩和
  • CloudflareのHTTP DDoS保護と同等の機能が含まれる
  • そのため、明示的なWAF Rate Limitingルールは基本的に不要

ルールタイプの説明

Custom(カスタムルール):

  • 独自に作成するルール(Geographic Blocking、Rate Limiting、IP Set等)
  • AWS WAFには地理的ブロックやRate Limitingのマネージドルールはないため、カスタムルールとして実装が必要

Managed(マネージドルール):

  • AWSが提供・管理するルールグループ
  • 自動的にルールが更新される(バージョン管理については後述)

ルール配置順序

AWS WAF Best Practices に従い、以下の順序でルールを配置します:

配置理由:

  • Force Allow リスト(IP/UA)を最優先で配置し、特定の CATV プロバイダや検索エンジン Bot を後段のルール評価前に強制許可(評価コスト削減)
  • IP/UA Blacklist を次に配置し、既知の悪意ある IP・AS レンジや User-Agent を後段のルール評価前に即座にブロック(評価コスト削減)
  • IP Reputation、Known Bad Inputs で既知の脅威をブロック
  • CRS は最も誤検知の可能性が高いため、最後に配置
  • Geographic Blocking、Rate Limiting は Phase 3以降で検討(Shield Standardで基本的なDDoS保護あり)

: IP Blacklist は個別の悪意ある IP アドレスと AS レンジ(M247/AS9009等)を統合した1つのルールで管理する。IP Set は IPv4/IPv6 で分けるが、個別 IP と AS レンジは同じ IP Set 内で管理する。

Force Allow/Block リストの運用:

  • Force Allow IP List: 一部 CATV プロバイダ等、特定の IP アドレスを強制的に許可する必要がある場合に使用
  • Force Allow UA List: Googlebot 等の検索エンジン Bot を強制的に許可する場合に使用
  • IP Blacklist: 攻撃が確認された IP アドレスや悪意ある AS レンジを即座にブロックする場合に使用
  • UA Blacklist: 悪意ある User-Agent(スクレイピング Bot 等)を即座にブロックする場合に使用
  • これらのリストは初期状態では空で、運用中に必要に応じて追加

IP Blacklist の運用ルール:

  • Terraform の変数定義にコメントで追加理由・追加日・対象の説明を記載すること
  • 例:
    hcl
    waf_shared_ip_blacklist_ipv4 = [
      "203.0.113.5/32",   # 2026-05-01: 攻撃元IP(SQLi試行、インシデント #1234)
      "198.51.100.0/24",  # 2026-04-15: スクレイピング元IP帯
      "5.182.0.0/16",     # M247 (AS9009) - 既知の悪意あるホスティング事業者
      "45.12.0.0/16",     # M247 (AS9009) - 既知の悪意あるホスティング事業者
    ]

フェーズ別ルール構成

Phase 1(Week 1-2: Cloudflareルール再現 - Count モード)

目的: Cloudflareで有効化されていたルールを全てCountモードで適用し、誤検知がないか確認

Priorityルール名タイプアクションWCUCloudflare相当
0force-allow-ip-listCustom (IP Set)Allow1-
1force-allow-ua-listCustom (String Match)Allow1-
2ip-blacklistCustom (IP Set)Block1IP Access Rules
3ua-blacklistCustom (String Match)Block1-
5amazon-ip-reputationManagedCount25Managed Ruleset
6known-bad-inputsManagedCount200Managed Ruleset
10core-rule-setManagedCount700OWASP コア

合計 WCU: 929 / 1,500

:

  • Force Allow/Block リストを最優先で配置: 初期状態では空のリスト。運用中に必要に応じて IP/UA を追加
  • ip-blacklist に個別 IP と AS レンジ(M247/AS9009等)を統合: IP Set は IPv4/IPv6 で分けるが、1つのルールで管理
  • Core Rule Set (CRS) を初期導入から含める: Cloudflareで OWASP コアが有効(ブロック)だったため、AWS WAFでも最初から導入
  • マネージドルールのアクション(Count/Block)はルールごとに個別変数で制御可能
  • Geographic Blocking、Rate Limiting は Phase 3以降で検討: Shield Standardで基本的なDDoS保護があるため、まずは必須ルールのみ適用

確認項目:

  • [ ] CRS の Count 数(特に SQLi、XSS 関連)
  • [ ] IP Reputation の Count 数(悪意あるIPからのアクセス)
  • [ ] Known Bad Inputs の Count 数(Log4j等の攻撃試行)
  • [ ] IP Blacklist のブロック数(個別IP・AS9009等からのアクセス)

Phase 2(Week 3-4: Block モード化)

目的: Phase 1 で誤検知がないことを確認後、全マネージドルールを Block モードに変更

Priorityルール名タイプアクションWCU変更点
0force-allow-ip-listCustom (IP Set)Allow1変更なし
1force-allow-ua-listCustom (String Match)Allow1変更なし
2ip-blacklistCustom (IP Set)Block1変更なし
3ua-blacklistCustom (String Match)Block1変更なし
5amazon-ip-reputationManagedBlock25Count → Block
6known-bad-inputsManagedBlock200Count → Block
10core-rule-setManagedBlock700Count → Block

合計 WCU: 929 / 1,500

:

  • マネージドルールを Block モードに変更(ルールごとに個別に変更可能)
  • 誤検知が確認された場合は、誤検知への対応方法を参照して除外設定を実施
  • Force Allow/Block リストは初期導入から同じアクション(Allow/Block)のため変更なし

監視強化期間: Block 化後 1週間は重点的にモニタリング

  • エラーレート変化(WAF適用前後で ±1% 以内を目標)
  • ユーザーからの問い合わせ(403 Forbidden等のエラー報告)
  • Datadog アラート(ブロック数急増、特定URIへのブロック集中等)
  • 正規トラフィックの誤ブロックがないか

誤検知への対応方法

Phase 1(Count モード)または Phase 2(Block モード)で誤検知が確認された場合、以下の3つの方法から適切な除外設定を選択します。

1. 誤検知の特定

Datadog Logsでの確認:

# COUNT として記録された誤検知
source:waf @system.action:ALLOW @nonTerminatingMatchingRules.action:COUNT

# BLOCK された誤検知(Phase 2)
source:waf @system.action:BLOCK

確認すべき情報:

  • @terminatingRuleId または @nonTerminatingMatchingRules.ruleId: 誤検知したルールID
  • @http.url: 誤検知が発生したURL/パス
  • @http.method: HTTPメソッド
  • @network.client.ip: クライアントIP
  • リクエストの内容が正規のものであることを確認

2. 除外方法の選択

シナリオ推奨方法WCU影響設定複雑度
特定パス全体で誤検知Scope-down statementなし
特定ルール1つだけが誤検知Rule Action Overrideなし
複雑な条件(IP+パス等)カスタム除外ルール+1〜5
一時的な回避が必要Rule Action Overrideなし

3. 除外設定の実装方法

方法1: Scope-down statement(推奨)

用途: 特定パターン(URI、クエリパラメータ等)に対してルールグループの評価自体をスキップ

Terraform実装例
hcl
rule {
  name     = "core-rule-set"
  priority = 10

  override_action {
    none {} # Block モード
  }

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

      # 特定パスをCRSの評価対象外にする
      scope_down_statement {
        or_statement {
          statement {
            # パターン1: /api/search パスを除外
            byte_match_statement {
              search_string = "/api/search"
              field_to_match {
                uri_path {}
              }
              text_transformation {
                priority = 0
                type     = "LOWERCASE"
              }
              positional_constraint = "STARTS_WITH"
            }
          }

          statement {
            # パターン2: /admin/* パスを除外
            byte_match_statement {
              search_string = "/admin/"
              field_to_match {
                uri_path {}
              }
              text_transformation {
                priority = 0
                type     = "LOWERCASE"
              }
              positional_constraint = "STARTS_WITH"
            }
          }
        }
      }
    }
  }

  visibility_config {
    cloudwatch_metrics_enabled = true
    metric_name                = "core-rule-set"
    sampled_requests_enabled   = true
  }
}

メリット:

  • ✅ 指定パターンに対してルールグループ全体をスキップ(パフォーマンス向上)
  • ✅ 複数の除外パターンを or_statement で組み合わせ可能
  • ✅ WCU消費なし

デメリット:

  • ⚠️ ルールグループ全体が評価されなくなる(部分的な除外は不可)

コンソール設定:

  1. Web ACL → Rules → 対象ルールを Edit
  2. 「スコープダウンステートメント - オプション」チェックボックスをON
  3. 検査対象(URI path等)と条件を設定
方法2: Rule Action Override

用途: 特定ルールのみアクションを変更(Block → Count)

Terraform実装例
hcl
rule {
  name     = "core-rule-set"
  priority = 10

  override_action {
    none {} # Block モード
  }

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

      # 特定ルールのみCountに変更
      rule_action_override {
        name = "SQLi_QUERYARGUMENTS"  # ルールID
        action_to_use {
          count {}  # Block → Count に変更
        }
      }

      rule_action_override {
        name = "GenericRFI_QUERYARGUMENTS"
        action_to_use {
          count {}
        }
      }
    }
  }

  visibility_config {
    cloudwatch_metrics_enabled = true
    metric_name                = "core-rule-set"
    sampled_requests_enabled   = true
  }
}

メリット:

  • ✅ 個別ルールのみアクション変更
  • ✅ 他のルールは正常にBlock動作
  • ✅ WCU消費なし

デメリット:

  • ⚠️ ルール評価自体は実行される
  • ⚠️ ルール名(ID)を正確に把握する必要がある

ルールIDの確認方法:

bash
# AWS CLIでマネージドルールグループの詳細を取得
aws wafv2 describe-managed-rule-group \
  --vendor-name AWS \
  --name AWSManagedRulesCommonRuleSet \
  --scope CLOUDFRONT \
  --region us-east-1
方法3: カスタム除外ルール

用途: 複雑な条件(IP + パス、メソッド + クエリ等)での除外

Terraform実装例
hcl
# カスタム除外ルール(Priority 5: CRSより前)
rule {
  name     = "allow-api-search-legacy"
  priority = 5

  action {
    allow {}  # このルールにマッチしたら即座に許可
  }

  statement {
    and_statement {
      statement {
        # /api/search パス
        byte_match_statement {
          search_string = "/api/search"
          field_to_match {
            uri_path {}
          }
          text_transformation {
            priority = 0
            type     = "LOWERCASE"
          }
          positional_constraint = "STARTS_WITH"
        }
      }

      statement {
        # クエリパラメータに "query" が含まれる
        byte_match_statement {
          search_string = "query="
          field_to_match {
            query_string {}
          }
          text_transformation {
            priority = 0
            type     = "URL_DECODE"
          }
          positional_constraint = "CONTAINS"
        }
      }
    }
  }

  visibility_config {
    cloudwatch_metrics_enabled = true
    metric_name                = "allow-api-search-legacy"
    sampled_requests_enabled   = true
  }
}

# マネージドルールグループ(Priority 10)
rule {
  name     = "core-rule-set"
  priority = 10
  # ... 省略 ...
}

メリット:

  • ✅ 最も柔軟(複雑な条件を組み合わせ可能)
  • ✅ AND/OR条件で詳細な除外設定が可能
  • ✅ 複数のマネージドルールグループに影響

デメリット:

  • ⚠️ Priority管理が必要(除外ルールを先に配置)
  • ⚠️ WCU消費が増える(1〜5 WCU程度)

4. 除外設定後の検証

動作確認:

bash
# 誤検知していたリクエストを再送信
curl -v "https://fastdoctor.jp/api/search?query=test"

# 期待結果: 200 OK(ブロックされない)

Datadogログで確認:

# 除外されたリクエストがブロックされていないことを確認
source:waf @http.url:"/api/search" @system.action:BLOCK
→ 結果: 0件

5. 除外設定の判断フロー

6. ベストプラクティス

  1. 段階的な除外:

    • まず Rule Action Override で Count に変更
    • 1週間様子を見て、Count扱いとなったアクセスがBlockしても問題ないものであること(正規のアクセスでないこと)を確認する
    • 誤検知(正規アクセス)であることが確認された場合のみ、恒久的な除外設定を実施
  2. 最小権限の原則:

    • 除外範囲は必要最小限に
    • パス全体ではなく、特定のパラメータのみ除外できないか検討
  3. ドキュメント化:

    • 除外理由をコメントに記載
    • GitHub Issue番号を参照
hcl
# GitHub Issue #123: /api/search でSQLi誤検知のため除外
# 調査結果: product_idパラメータが "product_id=123" の形式でSQLiと誤判定
# 対応: Scope-down statementで /api/search パスを除外
scope_down_statement {
  # ...
}
  1. 定期レビュー:
    • 除外設定を四半期ごとに見直し
    • 不要になった除外設定は削除

Phase 3以降(運用安定後: 追加ルール検討)

目的: Phase 2 運用が安定後、追加の保護ルールを検討

検討項目:

追加ルールPriorityWCU月額コスト優先度判断基準
Geographic Blocking31含む🟡 中国外からの正規アクセスがないことを確認後、導入判断
Rate Limiting42含む🟢 低Shield Standardで不足する場合のみ(基本的に不要)
Bot Control1550+$10〜🔴 高Phase 2運用後、ボットトラフィック分析結果に基づき判断
Anonymous IP List550含む🟢 低VPN/Proxy経由の攻撃が多い場合
その他Managed Rules各種各種含む🟢 低必要に応じて

WCU上限: 1,033 / 1,500(全て追加時)

: Priority 3, 4 は Phase 1/2 で使用している Priority 0-10 の後に配置

各ルールの導入判断基準:

Geographic Blocking(日本以外ブロック):

  • 判断材料: Phase 2 運用中のアクセスログ分析
    • 国外からのアクセス数・割合
    • 国外アクセスの正当性(海外出張中のユーザー、海外提携先等)
    • 国外からの攻撃・スクレイピングの有無
  • 確認方法: Datadog Logs で @network.client.geoip.country.iso_code を分析
  • 事業側確認の必要性:
    • コーポレートサイト: 広報室に確認が必要
    • 各LP(ランディングページ): 所管の事業部に確認が必要
    • fastdoctor.jp配下には複数のサイト・LPが存在し、各サイトの管轄先を整理した上で広範囲にわたる確認が必要
    • 国外からのアクセスが正当なビジネス要件(海外提携先、海外出張者等)に影響を与える可能性があるため、慎重な判断が必要
  • 結論: 技術的には導入可能だが、事業側との広範囲な調整が必要であり、今後の検討課題とする

Rate Limiting:

  • 判断材料: Shield Standardで防ぎきれないHTTP Flood攻撃の有無
  • 確認方法: CloudWatch MetricsでDDoS攻撃の検知状況を確認
  • 推奨: Shield Standardで基本的に対応可能なため、優先度低

Bot Control ($10/月追加):

  • 判断材料: Phase 2 運用後、ボットトラフィック分析
    • ボットによるアクセス数(User-Agent分析)
    • スクレイピング被害の有無
    • 正規ボット(Googlebot等)の誤検知リスク
  • Cloudflareでスーパー ボット ファイト モードが有効だったため、ボットトラフィックがある前提
  • 推奨: ボット被害が確認された場合は導入を検討

Terraform 実装設計

配置先

WAF の Terraform 実装は fastdoctor-template/common/ に配置します。

CloudFront は fastdoctor-template 側の Terraform 管理にしない:

  • CloudFront Distribution(fastdoctor.jp、test.fastdoctor.jp)は fd-sys アカウントに存在し、現状 fastdoctor-manager 側で管理されている
  • fastdoctor.jp の CloudFront はビヘイビアが128個あり、Terraform化にはビヘイビアの整理が先に必要で、かなりの労力と時間がかかる
  • 本チケットのスコープでは WAF Web ACL の構築と CloudFront への手動アタッチまでをゴールとする
  • CloudFront のリアルタイムログ設定やビヘイビア整理は別チケット(#10381)で対応

WAF の配置理由:

  • WAF Web ACL は fastdoctor-template/common/ で Terraform 管理し、再利用可能なモジュールとして提供
  • WAF Web ACL の CloudFront へのアタッチは手動で実施(アカウントが異なるため)

ディレクトリ構成

terraform_for_aws/
└── fastdoctor-template/
    ├── common/
    │   ├── infra-dev/
    │   │   └── waf.tf                # WAF Web ACL(検証用)
    │   ├── amazon-connect/
    │   │   └── waf.tf                # WAF Web ACL(本番: fastdoctor-jp-waf + test-fastdoctor-jp-waf)
    │   └── ...
    └── template_modules/
        └── options/
            ├── cloudfront-waf/       # WAF モジュール
            └── waf-shared-sets/      # 共有 IP/UA セット

WAF Web ACL の構成:

WAF Web ACL対象 CloudFrontDistribution ID
fastdoctor-jp-waffastdoctor.jpECFZLJO6MPEU
test-fastdoctor-jp-waftest.fastdoctor.jpE2ZMX7K5O2809

: CloudFront Distribution は fastdoctor-template 側では管理しない。WAF Web ACL を作成後、対象の CloudFront Distribution に手動でアタッチする。共有リソース(IP Blacklist、UA Blacklist)は waf-shared-sets モジュールで1つだけ作成し、両方の WAF から参照する。


ログ・モニタリング設計

基本方針

WAFログの主な利用目的:

  • 誤検知(False Positive)の調査: 正規ユーザーがブロックされていないか確認
  • ブロック漏れの検出: 攻撃パターンがすり抜けていないか検証
  • 緊急時の攻撃元特定: DDoS攻撃等のインシデント対応時にIPアドレス・パターンを即座に特定

分析期間:

  • 主に直近(数時間〜数日)のログ分析で運用
  • 過去に大きく遡っての分析は基本的に不要

監視プラットフォーム:

  • Datadog で一元管理(メトリクス + ログの統合監視)
  • アラート発火 → 同一画面でログ確認 → 原因特定のワークフローを実現
  • 疎通検証期間(約1週間)はインフラDatadogアカウントを使用: プロダクト系のログ量変動に釣られないように、WAFログ量の見積もりを正確に行う。インフラは現状ログは無し。
  • 疎通検証完了後、本番Datadogアカウントに切り替え
  • 検証期間中もインフラDatadogアカウントでダッシュボードでモニタリングをし、本番Datadogアカウントに切り替える際にダッシュボードもexport/importする。

WAFログの出力先アーキテクチャ

基本方針:

  • ALLOW: CloudFront Standard Loggingで記録(WAFログには不要、既に有効)
  • BLOCK/COUNT: WAF Logging Filter → Firehose → Datadog + S3バックアップ
  • 4xx/5xx エラー監視: CloudFrontデフォルトメトリクス(4xxErrorRate, 5xxErrorRate)で監視
    • : CloudFront Real-time Logsによる詳細なエラーログ分析は別チケット(#10381)で対応。fastdoctor.jpのCloudFrontはビヘイビアが128個あり、リアルタイムログはビヘイビア単位で設定が必要なため、ビヘイビアの整理が先に必要
  • 監査要件: S3バックアップで1年間保存

アーキテクチャ図:

ログ保存先:

ログタイプ保存先保存期間用途
WAF BLOCK/COUNTKinesis Firehose → Datadog15日リアルタイム監視、誤検知分析
WAF BLOCK/COUNTKinesis Firehose → S3 Backup1年(365日)監査要件、過去データ分析
CloudFront 全アクセスCloudFront Standard Logging → S3無期限(ライフサイクルなし)正常アクセスの監査、トラブルシューティング
CloudFront 4xx/5xxCloudWatch デフォルトメトリクス → Datadog-エラー率監視(4xxErrorRate, 5xxErrorRate

保存期間の根拠:

  • 監査要件ガイドラインに基づき、セキュリティログは最低1年間保存が必要
  • WAFログは公式サイト・LPへのアクセス制御ログとして、監査証跡の一部を構成
  • S3バックアップで365日保持することで、監査要件を満たしつつ、Datadogコストを削減
  • CloudFront Standard Loggingは既に有効で、ライフサイクル設定がないため無期限保持(将来的にライフサイクル設定の追加を検討)

CloudFront エラー監視:

  • 4xx/5xxエラー監視: CloudWatch デフォルトメトリクス(4xxErrorRate, 5xxErrorRate)を Datadog AWS 統合で収集
  • 無料・自動有効: 設定不要で利用可能
  • : CloudFront Real-time Logs による詳細な設計やエラーログ分析は別PR・別ドキュメントで検討

ログ内容(主要フィールド):

カテゴリフィールド説明
基本情報timestampリクエスト時刻(ISO 8601形式)
formatVersionログフォーマットバージョン
webaclIdWeb ACL の ARN
WAF判定actionALLOW / BLOCK / COUNT
terminatingRuleIdマッチしたルール ID
terminatingRuleTypeルールタイプ(REGULAR / RATE_BASED / MANAGED)
labelsWAF Labels の配列
HTTPリクエストhttpRequest.clientIpクライアント IP アドレス
httpRequest.country送信元の国コード(JP / US 等)
httpRequest.uriリクエストURI
httpRequest.httpMethodGET / POST 等
httpRequest.headersリクエストヘッダー
httpRequest.argsクエリパラメータ
その他ruleGroupList評価されたルールグループのリスト
httpSourceIdCloudFront Distribution ID

: ログフィールドのRedaction(秘匿化)については、運用設計書にて詳細を記載します

Datadog 監視統合

WAFの監視はDatadogで一元管理します。

WAFログの段階的コスト削減アプローチ

WAF Logging Filterで BLOCK/COUNT のみ に絞った後も、Datadogのログ取り込みコストが高騰する場合は、以下の追加施策を段階的に検討します。

コスト削減の2段階:

Stage 1: WAF Logging Filter(基本構成)

設定: WAF Logging ConfigurationのLogging Filterでアクションをフィルタ

hcl
logging_filter {
  default_behavior = "DROP"
  filter {
    behavior    = "KEEP"
    requirement = "MEETS_ANY"
    condition {
      action_condition { action = "BLOCK" }
    }
    condition {
      action_condition { action = "COUNT" }
    }
    condition {
      action_condition { action = "EXCLUDED_AS_COUNT" }
    }
  }
}

削減効果:

  • ALLOW(大部分を占める)を除外 → 大幅なログ量削減

コスト: 追加コストなし(AWS WAFの標準機能)


Stage 2: Lambda Data Transformation(フィールド抽出)

状況: Stage 1でもDatadogのログ取り込み量が多くコストが予算を超える場合にのみ検討する

設定: Firehose Data Transformationで必要フィールドのみ抽出

削減効果:

  • ヘッダー、クエリパラメータ、ruleGroupList等を削除 → ログサイズを大幅削減
  • Datadogのingestionコストとstorageコストの両方を削減

コスト:

  • Lambda実行コストが発生(リクエスト数に応じて変動)
  • Datadog削減額がLambdaコストを上回る場合に効果的

注意点:

  • S3バックアップは変換前のフルログが保存される(監査要件を満たす)
  • 詳細調査が必要な場合はS3のフルログをAthenaで分析可能

Datadog Pipelineについて:

  • Datadog側でログフィールドを削除する機能もあるが、ingestionコスト(最もコストが高い)は削減されない
  • ストレージコストのみ削減(効果が限定的)
  • そのため、コスト削減が目的の場合はLambda Transformationを推奨

推奨アプローチ

初期構成:

  • まずは Stage 1(Logging Filter) で開始
  • 運用開始後、以下を確認:
    • 実際のBLOCK/COUNT発生率
    • Datadogのログ取り込み量(ingestion volume)
    • Datadogの月間コスト

Stage 2導入判断基準:

  • Datadogのログコストが予算を超える場合
  • Lambda実行コストよりもDatadog削減額が大きい場合
  • ログ量が多く、フィールド削減効果が見込める場合

判断フロー:

運用開始(Stage 1)

1-2ヶ月運用してコスト確認

Datadogコストが予算内?
  ↓ YES → Stage 1で継続
  ↓ NO  → Stage 2(Lambda Transformation)を検討

メトリクス監視(AWS統合経由)

前提条件:メトリクス監視の設定

WAFおよびCloudFrontのメトリクスをDatadogで監視するには、以下の設定が必要です:

1. WAF Web ACL: CloudWatchメトリクスの有効化(必須)

重要: WAFの各ルールで terraformでcloudwatch_metrics_enabled = true を設定しないと、メトリクスがCloudWatchに送信されず、Datadog AWS統合でメトリクスを取得できません。

設定内容:

  • cloudwatch_metrics_enabled: true に設定(オプションだが強く推奨)
  • metric_name: 各ルールの識別名(必須、英数字とハイフン・アンダースコアのみ、1-128文字)
  • sampled_requests_enabled: サンプルリクエストをAWSコンソールで表示するか(オプション)

コスト: 無料(WAFの基本料金に含まれる)

2. CloudFront: デフォルトメトリクスと拡張メトリクス(Phase 1/2で有効化)

CloudFrontには**デフォルトメトリクス(無料、自動有効)拡張メトリクス(有料、手動有効化)**があります。

重要: Phase 1/2では拡張メトリクスを有効化します。エラー状況の詳細把握のため、ステータスコード別エラー率が必須です。

デフォルトメトリクス(無料、自動有効、設定不要):

  • Requests(リクエスト数)
  • BytesDownloaded / BytesUploaded
  • 4xxErrorRate / 5xxErrorRate(全体のエラー率)
  • TotalErrorRate(総エラー率)

拡張メトリクス(Phase 1/2で有効化、$1.80/月):

Phase 1/2で有効化するメトリクス - ステータスコード別エラー率(401, 403, 404, 502, 503, 504): 6メトリクス

  • 401ErrorRate: 認証エラー率
  • 403ErrorRate: 権限エラー率(WAF/CloudFront関連)
  • 404ErrorRate: Not Foundエラー率
  • 502ErrorRate: Bad Gatewayエラー率(オリジン接続問題)
  • 503ErrorRate: Service Unavailableエラー率(オリジン過負荷)
  • 504ErrorRate: Gateway Timeoutエラー率(オリジンタイムアウト)

コスト: 6メトリクス × $0.30 = $1.80/Distribution/月

拡張メトリクスの有効化方法(Terraform):

hcl
resource "aws_cloudfront_distribution" "fastdoctor_jp" {
  # ...

  # 拡張メトリクスを有効化(Phase 1/2)
  monitoring_subscription {
    realtime_metrics_subscription_config {
      realtime_metrics_subscription_status = "Enabled"
    }
  }
}

: 拡張メトリクスは有効化すると最大8メトリクス(CacheHitRate, OriginLatency含む)が収集されますが、本構成ではステータスコード別エラー率(6メトリクス)のみをDatadog Monitorsで使用します


Datadog AWS統合の設定:

Datadog の AWS インテグレーションでWAFv2メトリクスを自動収集:

Datadog メトリクス説明監視目的優先度
aws.wafv2.allowed_requests許可されたリクエスト数正常トラフィックの推移⭐⭐⭐
aws.wafv2.blocked_requestsブロックされたリクエスト数攻撃トレンドの検知⭐⭐⭐
aws.wafv2.counted_requestsCountされたリクエスト数Phase 1/2 での評価⭐⭐⭐
aws.wafv2.passed_requestsルールマッチしなかったリクエスト数デフォルトActionでの通過数⭐⭐

タグ付け(ルール別メトリクス):

  • rule:geo-blocking-non-japan
  • rule:rate-limiting-ddos-protection
  • rule:core-rule-set
  • rule:ip-blacklist
  • rule:amazon-ip-reputation
  • rule:known-bad-inputs
  • webacl:fastdoctor-jp-cloudfront

注記:

  • PassedRequests: マネージドルールグループ内でどのルールにもマッチしなかったリクエスト数。CRSやKnown Bad Inputsの有効性評価に有用
  • CAPTCHA/Challenge メトリクス: 現在のWAF構成では未使用(CAPTCHA/Challenge actionを使用していないため)
  • Bot Control メトリクス: Bot Control managed rule groupを使用していないため不要
  • CloudFrontメトリクス: デフォルトメトリクス(無料)で基本的なエラー率は取得可能。拡張メトリクス(ステータスコード別エラー率、$1.80/月)はPhase 1/2で有効化

ログ監視(Firehose経由)

WAF → Firehose → Datadog転送:

Kinesis Data Firehoseを使用してWAFログをDatadogに転送:

Firehose選択理由(Lambda Forwarderを使わない理由):

  • WAFネイティブサポート: WAFログはFirehoseへのネイティブ配信に対応しており、設定が簡潔
  • 構成のシンプル化: Lambda Forwarder使用時は CloudWatch Logs 経由での転送が必要で構成が複雑化
  • 再試行・バッファリング標準装備: Firehoseは再試行・バッファリングが標準機能で、大量アクセス時の取りこぼしリスクが低い
  • 運用コスト削減: Lambda実行コスト、CloudWatch Logs保存コストが不要

転送の目的:

  • リアルタイムインシデント対応: Datadogアラート発火時に、同一画面で即座にログ確認
  • メトリクスとの統合分析: ブロック数急増(メトリクス)→ 攻撃元IP特定(ログ)を1画面で実施
  • 運用ワークフロー統合: 既存のDatadog運用フローにWAF監視を統合

転送遅延:

  • Firehoseバッファ: 60秒 または 4MB(先に到達した方)
  • 最大遅延: 約60秒
  • CloudWatch Logs経由(Lambda Forwarder使用時)より高速

Firehose設定:

hcl
http_endpoint_configuration {
  url                = "https://aws-kinesis-http-intake.logs.datadoghq.com/v1/input"
  buffering_size     = 4   # MB
  buffering_interval = 60  # seconds
  s3_backup_mode     = "AllData"  # 全ログをS3にバックアップ
}

Datadog で利用可能なフィールド:

  • @action: BLOCK / COUNT / EXCLUDED_AS_COUNT(ALLOW は除外)
  • @http.url_details.path: リクエストURI
  • @http.method: HTTPメソッド
  • @network.client.ip: クライアントIP
  • @network.client.geoip.country.iso_code: 国コード
  • @terminating_rule_id: マッチしたルールID
  • @labels.name: WAF Labels(配列)
  • @ja3Fingerprint: TLS Client Hello fingerprint(32文字)
  • @ja4Fingerprint: TLS Client Hello fingerprint(36文字)

ログ保持期間:

  • Datadog: 15日間(リアルタイム監視用)
  • S3 Backup: 1年間(監査要件、過去データ分析用)
    • S3バケット: fastdoctor-waf-logs-archive-production
    • Athenaで過去データ分析可能

詳細: WAF監視・アラート設計書(/datadog/monitoring-guides/waf-monitoring-alert-design.md)で詳細を記載予定

ダッシュボード構成(例)

Datadog Dashboard: WAF Security Overview

モニタリング検証しながら変更を加えていく
統合ダッシュボードで以下を1画面に表示:

ウィジェットタイプ内容
Allowed vs Blocked RequestsTimeseriesメトリクス: aws.wafv2.allowed_requests / aws.wafv2.blocked_requests
Top Blocked IPsTableログクエリ: source:waf @system.action:BLOCK grouped by @network.client.ip
BLOCK Rule PerformanceTimeseriesログクエリ: source:waf @system.action:BLOCK grouped by @terminatingRuleId
COUNT Rule PerformanceTimeseriesログクエリ: source:waf @nonTerminatingMatchingRules.action:COUNT grouped by @nonTerminatingMatchingRules.ruleId
Geographic DistributionMapログクエリ: source:waf @system.action:BLOCK grouped by @httpRequest.country
Recent Blocked RequestsLog Streamログクエリ: source:waf @system.action:BLOCK

メリット:

  • ✅ メトリクス(傾向)とログ(詳細)を同時に確認
  • ✅ アラート発火時に該当時刻のログへ1クリックで遷移
  • ✅ 非エンジニアでもUI操作で分析可能

アラート例:

  • ブロック数急増: source:waf @system.action:BLOCK count > 1000 in 5min
  • Rate Limiting発動: source:waf @terminatingRuleId:rate-limiting-ddos-protection @system.action:BLOCK
  • Count数異常: source:waf @nonTerminatingMatchingRules.action:COUNT count > 500 in 10min(Phase 1/2での評価)

インシデント対応ワークフロー(Datadog統合)

Datadogでのインシデント対応フロー:

1. Datadogアラート発火(Slack通知)
2. アラート画面で「View in Logs」クリック
3. 該当時刻のログが自動フィルタ表示
4. 攻撃元IP・パターンを即座に確認
5. 必要に応じてWAFルール調整・IP Set追加等の対応実施

メリット:

  • メトリクス(ブロック数急増)とログ(攻撃元詳細)を同一画面で確認
  • AWSコンソールへの移動、クエリ作成が不要
  • 非エンジニアでもUI操作で分析可能

Datadog Logs Pipeline によるタグ付け

目的:

Firehose経由でDatadogに送信されたWAFログに、ルール別集計を容易にするタグを付与します。COUNT/BLOCKのアクションとルールIDを動的にタグ化することで、ログクエリとメトリクス集計がシンプルになります。

課題と解決策:

課題解決策
Firehose Parameters では固定タグしか付与できないDatadog Logs Pipeline で動的タグを付与
COUNT/BLOCK でログ構造が異なるネストされたパイプラインで分離処理
COUNT側の nonTerminatingMatchingRules が配列Array Processor でスカラー属性に変換
標準 Pipeline だけではタグが反映されないAWS WAF標準パイプライン配下にネストを作成

設計判断の背景:

本構成は「WAF導入初期の安全な立ち上げ(COUNT→BLOCK移行)」を前提に、ルール別にCOUNT/BLOCKを可観測化し、運用判断を最小の工数とコストで回すことを狙っています。

1) WAFログをFirehose経由でDatadog(AP1)に送る理由
  • WAFログの必要性: CloudFrontアクセスログだけでは「403」がオリジン由来かWAF由来か等の判別が難しく、COUNTも含めたWAF判断を確実に追跡するにはWAFログが一次情報になる
  • Firehoseの選択理由:
    • WAFログはマネージドにFirehoseへ配信でき、HTTP endpoint(Datadog)へ低運用で転送できるため、追加コンポーネント(常駐VM、Lambda Forwarder等)を増やさずに済む
    • Firehoseは再試行・バッファリングが標準であり、大量アクセス時でも「取りこぼしを避けたい」という要件に合致する
    • CloudWatch Logs経由と比較して、WAF → Firehose → Datadogの経路が最もシンプルで、転送遅延も最小(最大60秒)
2) Firehose Parametersではなく、Datadog側Processorでタグ付けする理由
  • Firehose Parametersの制約: Firehose Parametersで付与できるのは固定タグであり、WAFのruleIdCOUNT/BLOCKといったイベント内容に依存する動的タグは付与できない
  • 要件との不一致: ルール別の集計(ruleIdタグ化)が本要件の中心であるため、Datadog側のログパイプラインで動的タグ付けを行う方針とした
  • : waf_rule:core-rule-setwaf_rule:ip-reputation のようなルールIDベースのタグは、ログ内容を解析しないと付与できない
3) Datadogの"Attach Extra Tags"を使わず、Processorにした理由
  • 実装上の問題: Firehose経由のログ取り込みでは、Attach Extra Tags が期待通り反映されない事象が発生した
  • 安定性の確保: 一方でProcessor(Category/Remapper/Array Processor)による属性追加・タグ化は確実に反映され、運用上も再現性が高かったため、タグ付与はProcessorに統一した
  • メンテナンス性: Processorベースの設計により、タグ付与ロジックが明示的になり、トラブルシューティングが容易になる
4) 標準のAWS Web Application Firewallパイプラインを複製して使う理由
  • 正規化の必要性: 標準パイプラインはWAFログをDatadogの共通スキーマ(例:action@system.actionclientIp@network.client.ip)へ正規化しており、後続のフィルタ・プロセッサの条件が安定する
  • 独立パイプラインの問題: "独立パイプラインのみ"では正規化が不足し、期待した条件判定やタグ付与が安定しなかった
  • 拡張性: 標準の正規化処理を前提に拡張する設計とすることで、AWS WAF公式のフィールド変更にも追従しやすい
5) COUNT/BLOCKをネストパイプラインで分離した理由
  • ログ構造の違い:
    • COUNTイベント: 最終アクションがALLOWのままでもnonTerminatingMatchingRulesにCOUNTとruleIdが記録される(non-terminating)
    • BLOCKイベント: @system.action=BLOCKかつterminatingRuleIdにより終端判定される
  • 誤タグ付与の防止: 両者を同一フィルタで処理するとterminatingRuleId=Default_Action等が混在し、waf_ruleの意味が曖昧になるリスクがある
  • 分離の効果: COUNT/BLOCKを分離し、それぞれの条件に一致するログだけに処理を適用することで誤付与を防止し、タグの意味を明確にする
6) COUNTのruleId抽出にArray Processorを採用した理由
  • 配列フィールドの制約: COUNT側のruleIdnonTerminatingMatchingRules配列内に存在するため、Remapperだけでは抽出できない(添字アクセス等がUI/仕様上制約)
  • Array Processorの採用: Datadog公式の**Array Processor(matching elementから値抽出)**を用い、配列からruleIdをスカラー属性(例:waf.count_rule_id)へ抽出後、Remapperでタグ化することで、ruleIdが動的に変わっても安定してタグ付与できるようにした
  • 柔軟性: 複数ルールがCOUNTマッチした場合でも、Array Processorで最初の要素を抽出する等、ルールを明確に定義できる

まとめ:

標準パイプラインの正規化と、COUNT/BLOCK分離 + Array Processorによる動的タグ化により、アクセス量が多い環境でも誤付与を抑えつつ、ルール別集計を安定させる設計としています。

パイプライン構成:

親パイプライン: AWS Web Application Firewall

Filter: source:waf

役割: AWS WAFログの正規化(標準フィールドへのマッピング)

主要な Remapper:

  • httpRequest.clientIpnetwork.client.ip
  • httpRequest.urihttp.url_details.path
  • httpRequest.httpMethodhttp.method
  • actionsystem.action (重要)

この親パイプラインは Datadog 提供の標準パイプラインをそのまま利用します。

ネスト1: Add waf count tag (COUNT用)

Filter: source:waf @nonTerminatingMatchingRules.action:COUNT

Processors (実行順):

  1. Category Processor: Attribute count

    • COUNTログに waf.action_value = count を付与(分類用)
  2. Remapper: Add action tag

    • waf.action_value → tag waf_action
    • 結果: waf_action:count
  3. Array Processor: Add count rule id attribute

    • Array path: nonTerminatingMatchingRules
    • When: action:COUNT
    • Extract value of: ruleId
    • Target attribute: waf.count_rule_id
  4. Remapper: Add count rule id tag

    • waf.count_rule_id → tag waf_rule
    • 結果: waf_rule:block-ip-test (例)
ネスト2: Add waf block tag (BLOCK用)

Filter: source:waf @system.action:block

Processors (実行順):

  1. Remapper: Add action tag

    • system.action → tag waf_action
    • 結果: waf_action:block
  2. Remapper: Add block rule id tag

    • terminatingRuleId → tag waf_rule
    • 結果: waf_rule:block-ip-test (例)

期待されるタグ付与結果:

ログタイプタグ例
COUNTログwaf_action:count, waf_rule:block-ip-test
BLOCKログwaf_action:block, waf_rule:geo-blocking-non-japan

運用上の利点:

  • ✅ タグベースのシンプルなクエリ: waf_action:BLOCK waf_rule:rate-limiting-ddos-protection
  • ✅ Log-based Metricsの集計が容易: Group by: waf_rule
  • ✅ ダッシュボードでのドリルダウン分析が可能
  • ✅ COUNT/BLOCKの混在を防ぎ、正確な集計を実現

注意点:

  • COUNTログには terminatingRuleId = Default_Action が存在するため、ネストで分離しないとタグが混在する
  • WAFログに Cookie などが含まれる場合は、監査要件と相談しつつマスキング/Redactionを検討

Log-based Metrics の活用

Datadogでは、ログから独自メトリクスを生成可能です。タグベース実際のログ構造に基づいた設定例:

BLOCK数のルール別集計

方法1: タグベース(推奨)

Datadog Logs Pipeline でタグ付け後、シンプルなクエリで集計可能:

メトリクス名: waf.blocked_requests.by_rule
クエリ: waf_action:BLOCK
Group by: waf_rule

ダッシュボードクエリ:

sum:waf.blocked_requests.by_rule{*} by {waf_rule}
COUNT数のルール別集計

方法1: タグベース(推奨)

メトリクス名: waf.counted_requests.by_rule
クエリ: waf_action:count
Group by: waf_rule

ダッシュボードクエリ:

sum:waf.counted_requests.by_rule{*} by {waf_rule}

タグベースの利点:

  • ✅ クエリがシンプル(waf_action:BLOCK waf_rule:rate-limiting-ddos-protection
  • ✅ COUNT/BLOCKの混在を防ぐ(フィールドベースでは terminatingRuleId:Default_Action が混入)
  • ✅ ダッシュボード・アラートでの可読性向上

詳細設計:

具体的なアラートクエリ、閾値設定、通知先、エスカレーションフローについては、WAF監視・アラート設計書(/datadog/monitoring-guides/waf-monitoring-alert-design.md)にて以下を記載予定です:

  • Datadogアラート設定の詳細(クエリ、評価期間、閾値)
  • ダッシュボード構成とウィジェット設計(JSON定義含む)
  • Log-based Metricsの設定方法
  • 通知チャンネル設定(Slack等)
  • Phase別の監視戦略
  • ログフィールドのRedaction(秘匿化)設定

WAF Labels によるログ可視化

Labels の利用方針

本構成では基本的にWAF Labelsを使用しません。

理由:

  • Datadog Logs PipelineでルールIDベースのタグ(waf_rule:<ruleId>)を自動付与しており、これによってフィルタリング・分析が可能
  • Labelsはカスタムルールにのみ付与可能で、マネージドルールグループ(Core Rule Set、Known Bad Inputs等)には付与できない制約がある
  • ルールIDタグ(waf_rule:core-rule-setwaf_rule:ip-reputation等)で十分な粒度の分析が可能

マネージドルールのバージョン管理

: 本セクションの方針、手順、検証期間は、構築検証およびモニタリング検証の結果に基づいて見直す場合があります。実運用での知見を踏まえて、最適な運用フローを確立します。

バージョン管理方針

基本方針: 静的バージョンを選択し、通知を受けて手動更新

理由:

  • 自動更新による予期しないブロックを防止
  • 新バージョンをリリース候補版で検証してから適用
  • 変更管理プロセスに組み込む

静的バージョンの指定方法

hcl
# Terraform での静的バージョン指定
managed_rule_group_statement {
  vendor_name = "AWS"
  name        = "AWSManagedRulesCommonRuleSet"

  # バージョンを固定(指定しない場合は自動更新)
  managed_rule_group_configs {
    aws_managed_rules_common_rule_set {
      version_name = "Version_1.5"  # 静的バージョン
    }
  }
}

: バージョンを指定しない場合、AWS が自動的に最新バージョンに更新します(リスク大)。

AWS からの更新通知設定

AWS SNS Topic の作成と購読:

  1. AWS Console → WAF → Settings → Notifications
  2. SNS Topic を作成: waf-managed-rule-updates
  3. Email サブスクリプション追加
  4. 通知を受信したら、以下の手順で検証

バージョン更新フロー

: 以下のフローは初期案であり、実運用での検証を通じて最適化します。特にモニタリング期間やロールバック判断基準は、検証結果に基づいて調整します。

リリース候補ルールの活用

本構成では、リリース候補ルール(Release Candidate)の活用は特に想定していません。

理由:

  • マネージドルールのバージョン管理は静的バージョン指定により行う
  • バージョン更新時は test.fastdoctor.jp で事前検証してから fastdoctor.jp に適用する運用フローで十分
  • リリース候補ルール(_RC サフィックス)は通常の運用では不要

CloudFront Staging Distributionの検討と制約

検討の背景

本番環境への影響を避けるため、CloudFront Staging Distribution(継続的デプロイ機能)を使った検証を検討した。

期待した動作:

  • Primary DistributionのクローンとしてStaging Distributionを作成
  • Weight-based(例: 15%)でStaging Distributionにトラフィックを振り分け
  • Staging DistributionにのみWAF Web ACLを適用して検証
  • 検証完了後、Promote to Productionで本番に反映

判明した制約

1. WAF Web ACLの付け替えが不可

事象:

  • Staging Distribution作成後、WAF Web ACLを別のものに付け替えた
    • Primary distribution: webacl-prod
    • Staging distribution: webacl-stg(検証用)
  • この操作により、Weight-basedルーティングが機能しなくなった
  • 通常アクセス(ヘッダなし)では常にPrimary distributionにルーティングされる
  • Header-based(例: aws-cf-cd-test: 1)でのみStaging distributionにアクセス可能

AWS サポートからの回答:

  • 継続的デプロイポリシーがアタッチされている場合、WAF Web ACLの関連付け・関連付け解除は実施できない [1]
  • ステージングディストリビューションに対してWAF Web ACLを付け替えたことにより、Weight-basedルーティングが機能しなくなった

2. トラフィックのピーク時の動作

AWS公式ドキュメントの記載 [2]:

リソース使用率が高い期間など、状況に応じて、CloudFront は継続的デプロイポリシーで指定されている内容に関係なく、すべてのリクエストをプライマリディストリビューションに送信する場合があります。

影響:

  • Weight-basedで15%を指定しても、トラフィックのピーク時には全てPrimary distributionに送信される
  • ピーク時の具体的な閾値は非公開のため、いつStaging distributionへのルーティングが停止するか予測できない
  • PR発表・決算発表時など、意図的にトラフィックが増加するタイミングでの検証が困難

結論

Staging Distributionは本構成では利用できない:

  • WAF Web ACLを別のものに付け替えた時点で、Weight-basedルーティングが機能しなくなる
  • Header-basedでのアクセスは可能だが、実際のユーザートラフィックでの検証ができない
  • トラフィックのピーク時には全てPrimary distributionに送信されるため、安定した検証環境として機能しない

採用する検証フロー:

  • infra-dev環境test.fastdoctor.jpfastdoctor.jp の3段階検証フローを採用
  • WAF Web ACL は fastdoctor-template 側で Terraform 管理
  • CloudFront Distribution は fastdoctor-template 側の Terraform 管理にしない(fd-sys アカウント側で既存管理)
  • WAF Web ACL の CloudFront へのアタッチは手動で実施
  • test.fastdoctor.jp と fastdoctor.jp はそれぞれ専用の WAF Web ACL を持つtest-fastdoctor-jp-waf / fastdoctor-jp-waf

参考資料

[1] 継続的デプロイに関するクォータとその他の考慮事項 - AWS WAF ウェブ ACL

[2] CloudFront の継続的デプロイを使用して CDN 設定の変更を安全にテストする


事前検証とデプロイフロー

検証環境の方針

検証の流れ: infra-dev環境 → test.fastdoctor.jp → fastdoctor.jp

理由:

  • fastdoctor.jp の staging環境には、CloudFront Distribution相当のドメインが存在しない
  • infra-dev環境で構築・疎通検証を実施
  • 本番環境のテスト用ドメイン test.fastdoctor.jp導入検証とモニタリング検証を実施
  • 検証完了後、fastdoctor.jp に導入・モニタリングを実施
  • CloudFront Staging Distributionは、WAF Web ACLの付け替えにより機能しないため採用しない(詳細は CloudFront Staging Distributionの検討と制約 を参照)

検証フロー

検証手順の詳細

Phase 1: infra-dev環境での構築・疎通検証

目的: Terraform設定の妥当性確認とWAFルールの基本動作確認

Step 1: infra-dev環境用 WAF Web ACL 作成

ディレクトリ: fastdoctor-template/common/infra-dev/waf-cloudfront-fastdoctor-jp/

Step 2: 設定検証

確認項目:

  • [ ] WAF Web ACL が正常に作成される
  • [ ] CloudFront Distribution に WAF が正常にアタッチされる
  • [ ] Kinesis Firehose が正常に作成される
  • [ ] Firehose → Datadog ログ転送が正常動作する(60秒以内)

Step 3: 疎通検証

確認項目:

  • [ ] 正常リクエストが通過する(Action: ALLOW)
  • [ ] Count モードで各ルールが正常にマッチする
  • [ ] S3バックアップにログが保存される(AllDataモード)
  • [ ] Datadog Logs にログが転送される(60秒以内)
  • [ ] Datadog Logs Pipeline でタグ付けが正常動作する(waf_actionwaf_rule タグ確認)

Phase 2: test.fastdoctor.jp での導入検証とモニタリング検証

目的: 本番環境でのWAF動作確認と誤検知の検出

Step 4: test.fastdoctor.jp へのWAF適用

対象: production環境のテスト用ドメイン test.fastdoctor.jp(Distribution ID: E2ZMX7K5O2809、fd-sys アカウント)

使用するWAF: test-fastdoctor-jp-waf(test.fastdoctor.jp 専用)

確認項目:

  • [ ] WAF Web ACL test-fastdoctor-jp-waf をtest.fastdoctor.jp用CloudFront Distributionに手動で関連付け(AWSコンソールから実施)
  • [ ] test.fastdoctor.jpへのアクセスが正常に動作する
  • [ ] Datadog Logs にtest.fastdoctor.jpのWAFログが表示される
  • [ ] ルール別COUNT数が正常に集計される

Step 5: モニタリング検証

確認項目:

  • [ ] Datadog メトリクス(aws.wafv2.*)が収集される
  • [ ] Datadog Logs Pipeline でタグ付けが正常動作する
  • [ ] Datadog ダッシュボードが正常に表示される
  • [ ] アラート設定が正常に動作する(テストアラート)
  • [ ] ルール別COUNT数の推移が安定している(誤検知がない)

検証期間: 最低1週間、Count モードでマッチ数を確認

Phase 3: fastdoctor.jp への本番適用

Step 6: fastdoctor.jp へのWAF適用

対象: 本番ドメイン fastdoctor.jp(Distribution ID: ECFZLJO6MPEU、fd-sys アカウント)

使用するWAF: fastdoctor-jp-waf(fastdoctor.jp 専用)

確認項目:

  • [ ] test.fastdoctor.jpで誤検知が確認されなかった
  • [ ] WAF Web ACLをfastdoctor.jp用CloudFront Distributionに手動で関連付け(AWSコンソールから実施)
  • [ ] fastdoctor.jpへのアクセスが正常に動作する
  • [ ] Datadog Logs にfastdoctor.jpのWAFログが表示される

Step 7: 本番運用開始・継続モニタリング

確認項目:

  • [ ] 1週間のCOUNTモード運用で誤検知なし
  • [ ] Phase 2移行(BLOCKモード化)の準備完了
  • [ ] Datadog Monitorでブロック数急増アラートが設定されている
  • [ ] ロールバック手順が文書化されている(検証を通じて確立)

検証期間: 最低1週間、Count モードでマッチ数を確認

: ロールバック手順は、構築検証・モニタリング検証を通じて具体化し、運用設計書に反映します。

Step 5: 問題なければ production 適用

infra-dev で検証が完了したら、同じ設定で production 環境に適用し、継続的にモニタリングを実施。


AWS Shield Standard による DDoS 保護

自動的に有効化される保護:

  • L3/L4 DDoS 攻撃(SYN フラッド、UDP リフレクション等)
  • SSL/TLS ハンドシェイク攻撃
  • HTTP フラッド攻撃の一部

追加料金: なし(CloudFront に標準装備)


WCU 使用率

現在の WCU 使用率:

  • 929 / 1,500 (62%)
  • 十分な余裕あり

WCU 内訳:

  • Force Allow IP List: 1 WCU
  • Force Allow UA List: 1 WCU
  • IP Blacklist(個別IP + ASレンジ統合): 1 WCU
  • UA Blacklist: 1 WCU
  • IP Reputation List: 25 WCU
  • Known Bad Inputs: 200 WCU
  • Core Rule Set: 700 WCU

Phase 3以降の追加ルール(検討中):

  • Geographic Blocking: 1 WCU
  • Rate Limiting: 2 WCU

スケーラビリティ

リクエスト処理能力

AWS WAF の制約:

  • リクエスト処理能力: 無制限(CloudFront の処理能力に依存)
  • WCU 上限: 1,500(デフォルト)、最大 5,000(申請により拡大可能)
  • Rate Limiting: IP ごとに 5分間で最大 10,000 リクエストまで

ルール追加の余地

現在の WCU 使用率: 929 / 1,500 残り WCU: 571

追加可能なルール例:

  • Geographic Blocking (1 WCU)
  • Rate Limiting (2 WCU)
  • Anonymous IP List (50 WCU)
  • Bot Control (50 WCU) - 別料金 $10/月
  • 追加のカスタムルール

セキュリティ考慮事項

ログの機密情報保護

Redaction 対象:

  • Authorization ヘッダー
  • Cookie ヘッダー
  • X-Pre-Shared-Key ヘッダー

今後のタスク・実装計画

Phase 1/2 実装予定のリソース

リソース優先度説明
WAF Web ACL🔴 高CloudFront用WAF Web ACL(Phase 1: Count モード)、マネージドルールグループ設定
CloudFront拡張メトリクス🔴 高ステータスコード別エラー率(401/403/404/502/503/504)の有効化($1.80/月)
Kinesis Data Firehose (WAF)🔴 高WAFログをDatadog HTTP Endpointに転送するFirehose配信ストリーム
S3ログバックアップバケット🔴 高WAFログ1年保存用S3バケット + ライフサイクルポリシー(Firehose Backup用)
Secrets Manager🔴 高Datadog API Key格納用Secret(Firehose認証用)
Datadog Logs Pipeline🔴 高AWS Web Application Firewall親パイプライン + COUNT/BLOCKネストパイプライン2本の手動作成
Datadog Dashboard🔴 高WAF Security Overviewダッシュボード + CloudFront Performance & Errors(ステータスコード別エラー率含む)
Datadog Log-based Metrics🔴 高ルール別BLOCK/COUNT数のメトリクス生成設定
Datadog Monitors🟡 中ブロック数急増、誤検知検知、特定ルールCOUNT数監視、ステータスコード別エラー率監視のアラート設定
SNS Topic🟡 中WAFアラート通知用SNS Topic(Datadog Monitorからの通知先、オプション)

: CloudFront エラー監視はデフォルトメトリクス(4xxErrorRate, 5xxErrorRate)+ 拡張メトリクス(ステータスコード別エラー率)で実施

Phase 3 以降の検討事項

リソース優先度説明
CloudFront Real-time Logs🟢 低(別チケット #10381CloudFront Distribution のReal-time Logsを有効化し、詳細なエラーログ分析を実現。ビヘイビアが128個あるため、ビヘイビアの整理が前提タスク
Kinesis Data Streams🟢 低(別チケット #10381CloudFront Real-time Logsの受信用Data Streams(4xx/5xxエラーログ詳細分析用)
Kinesis Data Firehose (CloudFront)🟢 低(別チケット #10381Kinesis Data Streams → Datadog への転送用Firehose配信ストリーム
Rate Limiting ルール🟡 中DoS攻撃対策用のRate Limitingルール(Phase 2安定後に検討)
Bot Control🟡 中AWS Managed Rule: Bot Control($10/月、Bot検証が必要な場合)
Geographic Blocking🟢 低日本以外からのアクセスをブロック(事業側確認が必要、広範囲な調整が必要)

実装タスクの流れ

Phase 1 デプロイ前のチェックリスト

実装完了後、production環境デプロイ前に以下を確認:

  • [ ] Terraform plan で想定通りのリソースが作成される
  • [ ] CloudFront Standard Logging が既に有効であることを確認
  • [ ] CloudFront Access LogがS3バケットに出力されていることを確認
  • [ ] CloudFront デフォルトメトリクス(4xxErrorRate, 5xxErrorRate)がDatadogに収集されていることを確認
  • [ ] CloudFront 拡張メトリクス(ステータスコード別エラー率:401/403/404/502/503/504)が有効化され、Datadogに収集されていることを確認
  • [ ] infra-dev環境でWAFルールが正常動作する(テストリクエストでCOUNT/BLOCK確認)
  • [ ] Firehose (WAF) → Datadog ログ転送が正常動作する(60秒以内に表示)
  • [ ] Datadog Logs Pipeline でタグ付けが正常動作する(waf_actionwaf_rule タグ確認)
  • [ ] S3バックアップにログが保存される(AllDataモード確認)
  • [ ] Datadog Dashboard でメトリクスとログが統合表示される
  • [ ] 全ルールがCOUNTモードになっている(Phase 1要件)
  • [ ] Geographic Blocking、Rate Limitingの設定値が適切
  • [ ] AS9009 IP Setが正しく設定されている
  • [ ] CloudFront DistributionにWeb ACLが関連付けられる

Phase 1 → Phase 2 移行前のチェックリスト

Phase 1運用後、BLOCKモード移行前に以下を確認:

  • [ ] 1週間以上の運用実績があり、COUNTログが蓄積されている
  • [ ] 誤検知が確認されず、または除外設定で対応済み
  • [ ] ルール別COUNT数の傾向が安定している(急増・急減がない)
  • [ ] SRE Teamで移行判断会議を実施し、承認を得ている
  • [ ] ロールバック手順が文書化されている(検証を通じて確立)
  • [ ] 移行作業を平日日中に実施できるスケジュールを確保している
  • [ ] Datadog Monitorでブロック数急増アラートが設定されている

: ロールバック手順や判断基準は、Phase 1・2の運用で得られた知見に基づいて具体化し、運用設計書に反映します。


参考資料

AWS アーキテクチャ図

Terraform リソース


更新履歴

日付バージョン変更内容担当チーム担当者
2026-03-121.0初版作成SRE大賀