CloudFront WAF アーキテクチャ設計書
ドキュメント情報
- 作成日: 2026-03-06
- 対象環境: production (fastdoctor.jp)
関連ドキュメント
本ドキュメントは、CloudFront WAFのアーキテクチャ設計を記載しています。以下の関連ドキュメントも合わせて参照してください:
| ドキュメント | パス | 状態 | 概要 |
|---|---|---|---|
| WAF監視・アラート設計書 | /docs/datadog/monitoring-guides/waf-monitoring-alert-design.md | ✅ 作成済み | Datadogダッシュボード、アラート設定、Log-based Metrics |
目次
- アーキテクチャ概要
- WAF ルール構成
- Terraform 実装設計
- ログ・モニタリング設計
- WAF Labels によるログ可視化
- マネージドルールのバージョン管理
- CloudFront Staging Distributionの検討と制約
- 事前検証とデプロイフロー
- 今後のタスク・実装計画
アーキテクチャ概要
全体構成図
コンポーネント一覧
| コンポーネント | リージョン/場所 | 役割 |
|---|---|---|
| CloudFront Distribution | GLOBAL | CDN、HTTPS配信、WAF統合 |
| AWS WAF Web ACL | us-east-1 | WAF ルールエンジン |
| CloudWatch Logs | us-east-1 | WAF ログ保存 |
| CloudWatch Metrics | us-east-1 | WAF メトリクス |
| 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 Inputs | Phase 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 | ルール名 | タイプ | アクション | WCU | Cloudflare相当 |
|---|---|---|---|---|---|
| 0 | force-allow-ip-list | Custom (IP Set) | Allow | 1 | - |
| 1 | force-allow-ua-list | Custom (String Match) | Allow | 1 | - |
| 2 | ip-blacklist | Custom (IP Set) | Block | 1 | IP Access Rules |
| 3 | ua-blacklist | Custom (String Match) | Block | 1 | - |
| 5 | amazon-ip-reputation | Managed | Count | 25 | Managed Ruleset |
| 6 | known-bad-inputs | Managed | Count | 200 | Managed Ruleset |
| 10 | core-rule-set | Managed | Count | 700 | OWASP コア |
合計 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 | 変更点 |
|---|---|---|---|---|---|
| 0 | force-allow-ip-list | Custom (IP Set) | Allow | 1 | 変更なし |
| 1 | force-allow-ua-list | Custom (String Match) | Allow | 1 | 変更なし |
| 2 | ip-blacklist | Custom (IP Set) | Block | 1 | 変更なし |
| 3 | ua-blacklist | Custom (String Match) | Block | 1 | 変更なし |
| 5 | amazon-ip-reputation | Managed | Block | 25 | Count → Block |
| 6 | known-bad-inputs | Managed | Block | 200 | Count → Block |
| 10 | core-rule-set | Managed | Block | 700 | Count → 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実装例
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消費なし
デメリット:
- ⚠️ ルールグループ全体が評価されなくなる(部分的な除外は不可)
コンソール設定:
- Web ACL → Rules → 対象ルールを Edit
- 「スコープダウンステートメント - オプション」チェックボックスをON
- 検査対象(URI path等)と条件を設定
方法2: Rule Action Override
用途: 特定ルールのみアクションを変更(Block → Count)
Terraform実装例
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の確認方法:
# AWS CLIでマネージドルールグループの詳細を取得
aws wafv2 describe-managed-rule-group \
--vendor-name AWS \
--name AWSManagedRulesCommonRuleSet \
--scope CLOUDFRONT \
--region us-east-1方法3: カスタム除外ルール
用途: 複雑な条件(IP + パス、メソッド + クエリ等)での除外
Terraform実装例
# カスタム除外ルール(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. 除外設定後の検証
動作確認:
# 誤検知していたリクエストを再送信
curl -v "https://fastdoctor.jp/api/search?query=test"
# 期待結果: 200 OK(ブロックされない)Datadogログで確認:
# 除外されたリクエストがブロックされていないことを確認
source:waf @http.url:"/api/search" @system.action:BLOCK
→ 結果: 0件5. 除外設定の判断フロー
6. ベストプラクティス
段階的な除外:
- まず Rule Action Override で Count に変更
- 1週間様子を見て、Count扱いとなったアクセスがBlockしても問題ないものであること(正規のアクセスでないこと)を確認する
- 誤検知(正規アクセス)であることが確認された場合のみ、恒久的な除外設定を実施
最小権限の原則:
- 除外範囲は必要最小限に
- パス全体ではなく、特定のパラメータのみ除外できないか検討
ドキュメント化:
- 除外理由をコメントに記載
- GitHub Issue番号を参照
# GitHub Issue #123: /api/search でSQLi誤検知のため除外
# 調査結果: product_idパラメータが "product_id=123" の形式でSQLiと誤判定
# 対応: Scope-down statementで /api/search パスを除外
scope_down_statement {
# ...
}- 定期レビュー:
- 除外設定を四半期ごとに見直し
- 不要になった除外設定は削除
Phase 3以降(運用安定後: 追加ルール検討)
目的: Phase 2 運用が安定後、追加の保護ルールを検討
検討項目:
| 追加ルール | Priority | WCU | 月額コスト | 優先度 | 判断基準 |
|---|---|---|---|---|---|
| Geographic Blocking | 3 | 1 | 含む | 🟡 中 | 国外からの正規アクセスがないことを確認後、導入判断 |
| Rate Limiting | 4 | 2 | 含む | 🟢 低 | Shield Standardで不足する場合のみ(基本的に不要) |
| Bot Control | 15 | 50 | +$10〜 | 🔴 高 | Phase 2運用後、ボットトラフィック分析結果に基づき判断 |
| Anonymous IP List | 5 | 50 | 含む | 🟢 低 | 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 | 対象 CloudFront | Distribution ID |
|---|---|---|
fastdoctor-jp-waf | fastdoctor.jp | ECFZLJO6MPEU |
test-fastdoctor-jp-waf | test.fastdoctor.jp | E2ZMX7K5O2809 |
注: 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/COUNT | Kinesis Firehose → Datadog | 15日 | リアルタイム監視、誤検知分析 |
| WAF BLOCK/COUNT | Kinesis Firehose → S3 Backup | 1年(365日) | 監査要件、過去データ分析 |
| CloudFront 全アクセス | CloudFront Standard Logging → S3 | 無期限(ライフサイクルなし) | 正常アクセスの監査、トラブルシューティング |
| CloudFront 4xx/5xx | CloudWatch デフォルトメトリクス → 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 | ログフォーマットバージョン | |
| webaclId | Web ACL の ARN | |
| WAF判定 | action | ALLOW / BLOCK / COUNT |
| terminatingRuleId | マッチしたルール ID | |
| terminatingRuleType | ルールタイプ(REGULAR / RATE_BASED / MANAGED) | |
| labels | WAF Labels の配列 | |
| HTTPリクエスト | httpRequest.clientIp | クライアント IP アドレス |
| httpRequest.country | 送信元の国コード(JP / US 等) | |
| httpRequest.uri | リクエストURI | |
| httpRequest.httpMethod | GET / POST 等 | |
| httpRequest.headers | リクエストヘッダー | |
| httpRequest.args | クエリパラメータ | |
| その他 | ruleGroupList | 評価されたルールグループのリスト |
| httpSourceId | CloudFront Distribution ID |
注: ログフィールドのRedaction(秘匿化)については、運用設計書にて詳細を記載します
Datadog 監視統合
WAFの監視はDatadogで一元管理します。
WAFログの段階的コスト削減アプローチ
WAF Logging Filterで BLOCK/COUNT のみ に絞った後も、Datadogのログ取り込みコストが高騰する場合は、以下の追加施策を段階的に検討します。
コスト削減の2段階:
Stage 1: WAF Logging Filter(基本構成)
設定: WAF Logging ConfigurationのLogging Filterでアクションをフィルタ
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/BytesUploaded4xxErrorRate/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):
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_requests | Countされたリクエスト数 | Phase 1/2 での評価 | ⭐⭐⭐ |
aws.wafv2.passed_requests | ルールマッチしなかったリクエスト数 | デフォルトActionでの通過数 | ⭐⭐ |
タグ付け(ルール別メトリクス):
rule:geo-blocking-non-japanrule:rate-limiting-ddos-protectionrule:core-rule-setrule:ip-blacklistrule:amazon-ip-reputationrule:known-bad-inputswebacl: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設定:
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で過去データ分析可能
- S3バケット:
詳細: WAF監視・アラート設計書(/datadog/monitoring-guides/waf-monitoring-alert-design.md)で詳細を記載予定
ダッシュボード構成(例)
Datadog Dashboard: WAF Security Overview
モニタリング検証しながら変更を加えていく
統合ダッシュボードで以下を1画面に表示:
| ウィジェット | タイプ | 内容 |
|---|---|---|
| Allowed vs Blocked Requests | Timeseries | メトリクス: aws.wafv2.allowed_requests / aws.wafv2.blocked_requests |
| Top Blocked IPs | Table | ログクエリ: source:waf @system.action:BLOCK grouped by @network.client.ip |
| BLOCK Rule Performance | Timeseries | ログクエリ: source:waf @system.action:BLOCK grouped by @terminatingRuleId |
| COUNT Rule Performance | Timeseries | ログクエリ: source:waf @nonTerminatingMatchingRules.action:COUNT grouped by @nonTerminatingMatchingRules.ruleId |
| Geographic Distribution | Map | ログクエリ: source:waf @system.action:BLOCK grouped by @httpRequest.country |
| Recent Blocked Requests | Log Stream | ログクエリ: source:waf @system.action:BLOCK |
メリット:
- ✅ メトリクス(傾向)とログ(詳細)を同時に確認
- ✅ アラート発火時に該当時刻のログへ1クリックで遷移
- ✅ 非エンジニアでもUI操作で分析可能
アラート例:
- ブロック数急増:
source:waf @system.action:BLOCKcount > 1000 in 5min - Rate Limiting発動:
source:waf @terminatingRuleId:rate-limiting-ddos-protection @system.action:BLOCK - Count数異常:
source:waf @nonTerminatingMatchingRules.action:COUNTcount > 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の
ruleIdやCOUNT/BLOCKといったイベント内容に依存する動的タグは付与できない - 要件との不一致: ルール別の集計(ruleIdタグ化)が本要件の中心であるため、Datadog側のログパイプラインで動的タグ付けを行う方針とした
- 例:
waf_rule:core-rule-set、waf_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.action、clientIp→@network.client.ip)へ正規化しており、後続のフィルタ・プロセッサの条件が安定する - 独立パイプラインの問題: "独立パイプラインのみ"では正規化が不足し、期待した条件判定やタグ付与が安定しなかった
- 拡張性: 標準の正規化処理を前提に拡張する設計とすることで、AWS WAF公式のフィールド変更にも追従しやすい
5) COUNT/BLOCKをネストパイプラインで分離した理由
- ログ構造の違い:
- COUNTイベント: 最終アクションがALLOWのままでも
nonTerminatingMatchingRulesにCOUNTとruleIdが記録される(non-terminating) - BLOCKイベント:
@system.action=BLOCKかつterminatingRuleIdにより終端判定される
- COUNTイベント: 最終アクションがALLOWのままでも
- 誤タグ付与の防止: 両者を同一フィルタで処理すると
terminatingRuleId=Default_Action等が混在し、waf_ruleの意味が曖昧になるリスクがある - 分離の効果: COUNT/BLOCKを分離し、それぞれの条件に一致するログだけに処理を適用することで誤付与を防止し、タグの意味を明確にする
6) COUNTのruleId抽出にArray Processorを採用した理由
- 配列フィールドの制約: COUNT側の
ruleIdはnonTerminatingMatchingRules配列内に存在するため、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.clientIp→network.client.iphttpRequest.uri→http.url_details.pathhttpRequest.httpMethod→http.methodaction→system.action(重要)
この親パイプラインは Datadog 提供の標準パイプラインをそのまま利用します。
ネスト1: Add waf count tag (COUNT用)
Filter: source:waf @nonTerminatingMatchingRules.action:COUNT
Processors (実行順):
Category Processor: Attribute count
- COUNTログに
waf.action_value = countを付与(分類用)
- COUNTログに
Remapper: Add action tag
waf.action_value→ tagwaf_action- 結果:
waf_action:count
Array Processor: Add count rule id attribute
- Array path:
nonTerminatingMatchingRules - When:
action:COUNT - Extract value of:
ruleId - Target attribute:
waf.count_rule_id
- Array path:
Remapper: Add count rule id tag
waf.count_rule_id→ tagwaf_rule- 結果:
waf_rule:block-ip-test(例)
ネスト2: Add waf block tag (BLOCK用)
Filter: source:waf @system.action:block
Processors (実行順):
Remapper: Add action tag
system.action→ tagwaf_action- 結果:
waf_action:block
Remapper: Add block rule id tag
terminatingRuleId→ tagwaf_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-set、waf_rule:ip-reputation等)で十分な粒度の分析が可能
マネージドルールのバージョン管理
注: 本セクションの方針、手順、検証期間は、構築検証およびモニタリング検証の結果に基づいて見直す場合があります。実運用での知見を踏まえて、最適な運用フローを確立します。
バージョン管理方針
基本方針: 静的バージョンを選択し、通知を受けて手動更新
理由:
- 自動更新による予期しないブロックを防止
- 新バージョンをリリース候補版で検証してから適用
- 変更管理プロセスに組み込む
静的バージョンの指定方法
# 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 の作成と購読:
- AWS Console → WAF → Settings → Notifications
- SNS Topic を作成:
waf-managed-rule-updates - Email サブスクリプション追加
- 通知を受信したら、以下の手順で検証
バージョン更新フロー
注: 以下のフローは初期案であり、実運用での検証を通じて最適化します。特にモニタリング期間やロールバック判断基準は、検証結果に基づいて調整します。
リリース候補ルールの活用
本構成では、リリース候補ルール(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(検証用)
- Primary distribution:
- この操作により、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.jp → fastdoctor.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_action、waf_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 | 🟢 低(別チケット #10381) | CloudFront Distribution のReal-time Logsを有効化し、詳細なエラーログ分析を実現。ビヘイビアが128個あるため、ビヘイビアの整理が前提タスク |
| Kinesis Data Streams | 🟢 低(別チケット #10381) | CloudFront Real-time Logsの受信用Data Streams(4xx/5xxエラーログ詳細分析用) |
| Kinesis Data Firehose (CloudFront) | 🟢 低(別チケット #10381) | Kinesis 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_action、waf_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-12 | 1.0 | 初版作成 | SRE | 大賀 |