
こんにちは、エブリーでデリッシュキッチンの開発を主に担当している塚田です。
WebやAPIを運用する中で、セキュリティ強化は継続的な課題の一つです。
今回は、AWS WAF (Web Application Firewall) を導入する場合のアーキテクチャ選定と、そこで直面した技術的な検討事項について紹介します。
特に、「CloudFront -> ALB -> ECS」という標準的な構成において、「WAFをどこに適用するか(Edge vs Regional)」という議論にフォーカスします。
はじめに
今回は、静的コンテンツの配信効率化と負荷分散のために、以下のような構成をとっている前提で検討します。
また、セキュリティグループやネットワークACLによる防御や、アプリケーション側で行える基本的な攻撃への対処(SQLインジェクションやXSSなど)は実現できているものとします。
User -> CloudFront -> ALB (Application Load Balancer) -> ECS (Amazon ECS)
そこで最初の岐路となったのが、「CloudFront(Edge)にWAFを適用するか、ALB(Regional)に適用するか」という問題です。
CloudFront vs ALB どちらにWAFを置くか?
AWS WAFは、CloudFrontとALBのどちらにもアタッチ可能です。それぞれのメリット・デメリットを整理し、検討を行いました。
| 比較項目 | CloudFront (Edge) に適用 | ALB (Regional) に適用 |
|---|---|---|
| 防御範囲 | 全リクエストをエッジでブロック | キャッシュミスし、オリジンに到達したリクエストのみブロック |
| コスト | 高い (全リクエストが課金対象) | 安い (オリジン到達分のみ課金対象) |
| オリジン負荷 | 攻撃リクエストがオリジンに届かないため負荷減 | 攻撃リクエストもALBまでは到達する |
| 直接アクセス対策 | ALBへ直接アクセスされるとWAFを回避される | ALB自体を守るため、直接アクセスでもWAFが機能する |
| IP制限 | クライアントIPで直接制限可能 | X-Forwarded-For ヘッダーの参照が必要 |
単純に以下の観点で検討した場合ALBの方が有利であると感じました。
圧倒的なコストメリット
メディアサービスの特性上、画像や動画などの静的リクエスト数が膨大です。
CloudFront側でWAFを有効にすると、静的リソースへの正常なアクセスも含めた「全リクエスト」に対してWAFの料金(Web ACL使用料 + リクエスト数課金)が発生してしまいます。 ALB側であれば、CloudFrontでキャッシュアウトした「動的処理が必要なリクエスト」のみが検査対象となるため、コストを大幅に最適化できます。
防御対象の絞り込み
本当に守りたいのは、データベース接続やビジネスロジックを持つECS上のアプリケーションです。静的ファイルへのリクエストを除外した、純粋なアプリケーションリクエストのみを検査対象とすることで、運用時のログ分析ノイズも減らせると判断しました。
技術的検討事項と実装のポイント
有利であると感じたALB側にWAFを適用する場合ですが、いくつか特有の技術的課題が発生します。
1.クライアントIPの識別(IP制限)
ALBにWAFを適用する場合、WAFが見る「送信元IPアドレス」はCloudFrontのIPレンジになってしまいます。攻撃者のIPや、社内からのアクセス許可(ホワイトリスト)をIPベースで行う場合、そのままでは機能しません。
対策: AWS WAFのルール設定において、IP判定に X-Forwarded-For ヘッダーを使用するように構成することで、IP制限を実現。
方法: AWS WAFの設定(コンソールやTerraform等)で、IPセットの一致条件を「IP address in header」とし、ヘッダー名に X-Forwarded-For を指定します。 ※ X-Forwarded-For は改ざん可能なヘッダーであることに注意が必要です。
2.AWSマネージドルール(IPレピュテーション等)の制約
ここが大きな注意点ですが、AWSが提供する AWSManagedRulesAmazonIpReputationList などのIPアドレスベースのマネージドルールは、基本的に「送信元IPアドレス」を検査対象とします。
ALB上のWAFから見ると送信元はすべてCloudFrontのIPとなるため、これらのルールはクライアントのIP(攻撃者)に対して正しく機能しません(CloudFrontのIPを評価してしまいます)。
SQLインジェクションやXSSなど「アプリケーション脆弱性への攻撃(リクエストの中身)」への防御やレートリミットでの制限を最優先とする場合は、この制約を許容できるかもしれません。 しかし、AWS提供のIPレピュテーションリストによる防御が必須要件である場合は、コスト増を許容してでもCloudFront側にWAFを適用する必要があります。
3.CloudFront以外からのアクセス遮断(WAF回避の防止)
ALBにWAFがあるため、攻撃者がCloudFrontを経由せずにALBのDNS名に直接アクセスしてきた場合でも、WAF自体は機能します。しかし、キャッシュを介さない不必要な負荷を避けるため、ALBへのアクセスはCloudFront経由のみに限定すべきです。
対策: ALBのセキュリティグループ(SG)で、インバウンドルールを「CloudFrontのManaged Prefix ListからのHTTPSのみ許可」に設定しました。
これにより、攻撃者がALBのIPやDNSを特定して直接攻撃を仕掛けてきても、ネットワーク層で遮断されます。WAF以前の段階で不正アクセスを防ぐ重要な設定となります。
4.静的・動的コンテンツの分離によるコスト最適化
ALBレイヤーでの適用と同様の効果(コスト削減)を得るための別のアプローチとして、CloudFrontディストリビューションを静的コンテンツ用と動的コンテンツ用に分割する構成も有効です。
静的コンテンツ用CloudFront: WAFを適用しない(または安価なルールのみ)。常にキャッシュさせる
動的コンテンツ用CloudFront: WAFを適用する
このように構成することで、エッジ(CloudFront)での防御メリットを享受しつつ、検査対象を動的リクエスト(ALBと同等のアクセス量)に絞り込んでコストを最適化できます。ただし、ドメイン設計やフロントエンドの実装変更が必要になるため、対応に必要なコストと防御したい内容を天秤にかけて検討すると良いでしょう。
実際に導入する際の運用考慮事項
実際にWAFを本番環境へ導入する場合には、技術的な設定だけでなく、誤検知(False Positive)への運用フローなどの考慮も必要です。
この点については、過去の記事でも詳しく紹介していますので、ぜひ参考にしてください。
まとめ
今回のWAF導入では、「どこで守るか」と「コスト最適化」という観点で検討を行いました。
CloudFront (Edge): 全リクエスト防御、DDoS対策重視、設定がGlobal
ALB (Regional): コスト最適化(キャッシュ済みリクエスト除外)、アプリ保護重視
構成図だけ見れば「前段(Edge)で止めるのがベストプラクティス」とされることが多いですが、実際のリクエスト量や守るべき対象のリスク許容度を計算すると、他の方法も検討の余地があります。
今後も、サービスの成長に合わせて、セキュリティとパフォーマンス、そしてコストの最適なバランスを追求していきたいと思います。