AWS WAFのWeb ACL(保護パック)でCloudWatch Logsにログを出力している場合はコスト削減のためにも、運用負荷軽減のためにも新しいコンソールを使用する方が良いと感じた件

AWS WAFのWeb ACL(保護パック)でCloudWatch Logsにログを出力している場合はコスト削減のためにも、運用負荷軽減のためにも新しいコンソールを使用する方が良いと感じた件

新しいコンソールに慣れていこう
2025.09.07

AWSマネジメントコンソールでWeb ACLを開くたびに実行されるTop Insightsセクションの表示にかかるコストが気になる

こんにちは、のんピ(@non____97)です。

皆さんはAWSマネジメントコンソールでWeb ACLを開くたびに実行されるTop Insightsセクションの表示にかかるコストが気になったことはありますか? 私はあります。

Traffic Overview ダッシュボードに表示されるTop Insights セクションを用いることで、URIパスやクライアントIPなどトラフィックのより詳細な情報を確認することが可能です。こちらはWeb ACLのログをCloudWatch Logsに出力している場合に使用可能です。

https://dev.classmethod.jp/articles/waf-console-top-insights-visualizations/

こちらのTop Insightsセクションの情報は裏側でCloudWatch Logs Insightsが実行されることによって表示されます。

Top InsightsセクションにはThe top insights section includes richer visualizations based on your CloudWatch logs. Loading this section incurs additional CloudWatch query costs. For more information on these costs, see CloudWatch pricing . For more information on security insights visualizations, see the AWS WAF Developer Guideという注意書きがあることからCloudWatch Logs Insightsの課金が発生することが分かります。

Top InsightsセクションはTraffice overflowダッシュボードに記載されています。

Traffice overflowダッシュボードはAWSマネジメントコンソールからWeb ACLを開く場合に最初に遷移するページです。つまりはWeb ACLのルールやログの設定を確認したいだけであっても、Top Insightsセクションが読み込まれ、裏側でCloudWatch Logs Insightsが実行されてしまいます。

CloudWatch Logs Insightsはスキャンしたデータ量によって課金が発生します。全てのログを出力する設定 かつ 大量のトラフィックを捌いているWebACLにおいては課金が気になってくるところです。

では、AWS re:Inforce 2025にて発表されたコンソールの場合はどうでしょう。

https://dev.classmethod.jp/articles/aws-waf-new-console-2025/

構成がガラッと変わったのであれば、嬉しいです。

実際に確認してみます。

いきなりまとめ

  • AWS re:Inforce 2025にて発表されたコンソールではTop Insightsセクション表示時にコストがかかることがより分かりやすくなった
    • 表示する際には確認のポップアップが出るように
      • そもそも、ルールやログなど他設定を確認/変更する際に、ダッシュボードを経由しなくともよくなったため、無用にTop Insightsのコストがかかってしまう事態を減らしやすくなった
    • 3時間よりも広い期間やルール、終了アクションを変更した場合は明示的にリロードが要求されるように
  • AWS re:Inforce 2025にて発表されたコンソールではログエクスプローラーが使用できる
    • GUIで簡単にログの絞り込みができる
    • CloudWatch Logsのフィールドインデックスを有効活用しよう

従来のコンソールの場合

初回アクセス

まずは従来のコンソールの場合です。

Web ACLにアクセスするとTraffic overviewタブを開いています。こちらにTop Insightsセクションがあります。

2.従来のコンソールでアクセス.png

既に過去にオープンしていたため、URIパスなどの情報が表示されていますね。

この時のCloudWatch Logs Insightsの実行履歴を確認すると、AWSマネジメントコンソールからWeb ACLにアクセスしたタイミングでCloud Watch Logs Insightsが実行されています。

1.従来のコンソールでアクセスした場合のLogs Insightsの実行履歴.png

これは気になりますね。

期間と終了アクションを変更した上で再度アクセス

期間と終了アクションを変更した上で再度アクセスをします。

デフォルトの期間は3時間で、終了アクションは以下全てのものが選択されています。

  • Allowed
  • Blocked
  • Captcha
  • Challenge

Top InsightsセクションのCloudWatch Logs Insightsのクエリは以下記事で紹介しているとおり、終了アクションでフィルタリングをしています。

https://dev.classmethod.jp/articles/aws-waf-top-insights-cloudwatch-logs-insights-query/

そのため、CloudWatch Logsロググループのフィールドインデックスで終了アクションactionに対していインデックスを張ることでスキャン量を減らし、コスト削減をすることです。

つまりは、Blockedのみなど、一部の終了アクションを選択しておけば裏側で実行されるCloudWatch Logs Insightsのコスト影響を抑えることができそうです。

今回は期間を1日で終了アクションをAllowedBlockedのみにしました。

3.従来のコンソールでアクセス_期間と対象アクションを変更.png

この状態で別ページに遷移してから再度アクセスをします。

5.従来のコンソールでアクセス_期間と対象アクションを変更して別ページに遷移した場合.png

期間と終了アクションが維持できていますね。

裏側ではCloudWatch Logs Insightsの実行が行われていました。

4.従来のコンソールでアクセス_期間と対象アクションを変更して別ページに遷移した場合のLogs Insightsの実行履歴.png

それでは、一度このセッションからサインアウトした後に再度アクセスをします。

すると、デフォルトの期間は3時間で、全ての終了アクションを選択した状態になっていました。

6.従来のコンソールでアクセス_期間と対象アクションを変更して再度サインインした場合.png

どうやら、こちらのフィルタリングはセッション単位でリセットされてしまうようです。

そのため、期間や終了アクションを絞っておいて、再度アクセスした際のCloudWatch Logs Insightsにかかることを削減する方法は取れなさそうです。

Top Insightsセクションを畳んでから再度アクセス

Top Insightsセクションを畳んでから再度アクセスした場合はどうでしょうか。

Top Insightsセクションを畳んでから再度アクセスします。

7.従来のコンソールでTop Insightsセクションを畳んでから再度アクセス.png

この時、CloudWatch Logs Insightsの実行履歴を確認しましたが、何も実行されていないようです。

8.従来のコンソールでTop Insightsセクションを畳んでから再度アクセスした場合のLogs Insightsの実行履歴.png

そのため、CloudWatch Logs Insightsのコストが気になる場合は、Top Insightsセクションを畳んでおけば良さそうです。

一度このセッションからサインアウトしてから再度アクセスをします。

10.従来のコンソールでTop Insightsセクションを畳んでから再度ログインしてアクセス.png

閉じたままですね。

CloudWatch Logs Insightsの実行履歴からも実行されていないことを確認できました。

11.従来のコンソールでTop Insightsセクションを畳んでから再度ログインしてアクセスした場合のLogs Insightsの実行履歴.png

他、以下アクセスをしましたたがTop Insightsセクションは閉じたままでした

  1. 一度サインアウトして、ブラウザのキャッシュを削除した上で再度アクセス
  2. 別のIAMロールにスイッチロールした状態でアクセス
  3. シークレットブラウザからアクセス

これらのパターンからデフォルトではTop Insightsセクションは閉じた状態のようですね。

CloudWatch Logsにログを出力する = Top Insightsセクションの表示で毎回コストがかかるという訳ではなさそうです。

AWS re:Inforce 2025にて発表されたコンソールの場合

初回アクセス

続いて、AWS re:Inforce 2025にて発表されたコンソールの場合です。

以前はWeb ACL(保護パック)があるリージョンごとにセレクトメニューから選択していましたが、横断して確認できるようになりました。私は好きです。

12.新しいコンソール.png

Top Insightsセクションは各保護パック横のダッシュボードを表示をクリックした先で確認できます。

13.新しいコンソールのTop Insights.png

Load Top Insightsと、より分かりやすくTop Insightsセクションを表示するのかをユーザーに求めるようになりました。追加料金が適用されますという文言も黄色でアピールしてくれていますね。

13.新しいコンソールのTop Insightsを開いた場合のLogs Insights実行履歴.png

Load Top Insightsをクリックすると、追加コストがかかりますと表示されました。親切設計ですね。

17.追加コストがかかります.png

確認をクリックすると、Top Insightsの各種情報が表示されました。

18.新しいコンソールのTop Insights.png

他パターンでのアクセス

毎回スクリーンショットを貼るのもアレなので、各パターンごとの結果を以下にまとめます。

アクセスパターン Top Insightsセクションの状態
リロード 表示
別画面に遷移してから再度アクセス 表示
一度サインアウトしてから再度アクセス 表示
別のIAMロールにスイッチロールしてアクセス 未表示
シークレットブラウザからアクセス 未表示

あるユーザーが調査のために期間を長めに設定した上でTop Insightsセクションを眺めている最中に、別のユーザーがダッシュボードにアクセスしてもLoad Top Insightsをクリックしない限り裏側でCloudWatch Logs Insightsは実行されなさそうですね。

また、期間や終了アクションについては従来のコンソールと同じく、サインアウトをするとリセットされました。そもそも現状ではサインアウトすると毎回従来のコンソールが表示されています。

フィルタリング条件を変更した際に明示的なリロードが要求されるようになった

他、新しいコンソールでは、終了アクション、ルールなどのフィルタリング条件を変更した場合に明示的なリロードを行わなければTop Insightsセクションの情報が更新されないという点も良いと感じました。

従来は終了アクションを変更すると、すぐさまTop Insightsセクションが更新されていました。特に終了アクションは複数同時に選択をしたり、外すことができないため、地味にコストがかかるところです。

具体的には終了アクションに対するフィルタリングを

  • Allowed
  • Blocked
  • Captcha
  • Challenge

という状態から

  • Captcha
  • Challenge

に変更する場合は以下のように2回Top Insightsセクションの読み込みが走ってしまいます。

  • Allowed を外すタイミング
  • Blocked を外すタイミング

ルールや終了アクションを変更した場合、新しいコンソールでは、Hide Top Insights横のリロードボタンを押さなければTop Insightsセクションの情報は更新されません。そもそも従来のコンソールではルールでフィルタリングすることができなかったので、非常にありがたいです。

期間については3時間よりも広い期間を選択する場合は明示的なリロードが要求されるようです。

実際に試します。

19.新しいコンソール3時間全アクション.png

この状態から期間を12時間、ルールをGeoBlockRuleで設定します。

20.新しいコンソール3時間全アクション2.png

すると、この状態ではまだTop Insightsセクションの情報は更新されていません。

Hide Top Insights横のリロードボタンを押すと、追加コストがかかりますとポップアップが表示されます。

処理を続行すると、初めてTop Insightsのロードが始まり、情報が更新されました。

21.新しいコンソール3時間全アクション3.png

これは嬉しいアップデートです。

ちなみに、このとき裏側で実行されていたCloudWatch Logs Insightsは以下のとおりです。

fields httpRequest.clientIp, action
        | parse @message '"nonTerminatingMatchingRules":[{"ruleId":"*","action"' as nonTerminatingMatchingRules 
        | filter strcontains(nonTerminatingMatchingRules, 'GeoBlockRule') or terminatingRuleId == "GeoBlockRule" 
        | filter action in ['ALLOW','BLOCK','CHALLENGE','CAPTCHA'] 
        | filter webaclId in ['arn:aws:wafv2:us-east-1:<AWSアカウントID>:global/webacl/website/84a704a7-6965-44af-887e-d196dcd881ac']
        | stats count(*) as cnt by httpRequest.clientIp 
        | sort cnt desc 
        | limit 100 | limit 100
stats count(*) as cnt by concat(httpSourceName, ' | ', httpSourceId) as combined_field 
        | parse @message '"nonTerminatingMatchingRules":[{"ruleId":"*","action"' as nonTerminatingMatchingRules 
        | filter strcontains(nonTerminatingMatchingRules, 'GeoBlockRule') or terminatingRuleId == "GeoBlockRule" 
        | filter action in ['ALLOW','BLOCK','CHALLENGE','CAPTCHA'] 
        | filter webaclId in ['arn:aws:wafv2:us-east-1:<AWSアカウントID>:global/webacl/website/84a704a7-6965-44af-887e-d196dcd881ac'] 
        | sort cnt desc 
        | limit 100 | limit 100
fields httpRequest.httpMethod, action 
        | parse @message '"nonTerminatingMatchingRules":[{"ruleId":"*","action"' as nonTerminatingMatchingRules 
        | filter strcontains(nonTerminatingMatchingRules, 'GeoBlockRule') or terminatingRuleId == "GeoBlockRule" 
        | filter action in ['ALLOW','BLOCK','CHALLENGE','CAPTCHA'] 
        | filter webaclId in ['arn:aws:wafv2:us-east-1:<AWSアカウントID>:global/webacl/website/84a704a7-6965-44af-887e-d196dcd881ac'] 
        | stats count(*) as count by httpRequest.httpMethod 
        | sort count desc 
        | limit 100 | limit 100
fields httpRequest.uri as uri, action
        | parse @message '"nonTerminatingMatchingRules":[{"ruleId":"*","action"' as nonTerminatingMatchingRules 
        | filter strcontains(nonTerminatingMatchingRules, 'GeoBlockRule') or terminatingRuleId == "GeoBlockRule" 
        | filter action in ['ALLOW','BLOCK','CHALLENGE','CAPTCHA'] 
        | filter webaclId in ['arn:aws:wafv2:us-east-1:<AWSアカウントID>:global/webacl/website/84a704a7-6965-44af-887e-d196dcd881ac']
        | stats count(*) as cnt by uri 
        | sort cnt desc 
        | limit 100 | limit 100
fields jsonParse(@message) as json_message , action
        | parse @message '"nonTerminatingMatchingRules":[{"ruleId":"*","action"' as nonTerminatingMatchingRules 
        | filter strcontains(nonTerminatingMatchingRules, 'GeoBlockRule') or terminatingRuleId == "GeoBlockRule" 
        | filter action in ['ALLOW','BLOCK','CHALLENGE','CAPTCHA'] 
        | filter webaclId in ['arn:aws:wafv2:us-east-1:<AWSアカウントID>:global/webacl/website/84a704a7-6965-44af-887e-d196dcd881ac']
        | unnest json_message.labels into labelsvalues
        | stats count(*) as cnt by labelsvalues.name
        | sort cnt desc 
        | limit 100 | limit 100
fields @timestamp, @message 
        | parse @message /\{"name":"(U|u)ser-(A|a)gent","value":"(?<userAgent>.*?)"\}/ 
        | parse @message '"nonTerminatingMatchingRules":[{"ruleId":"*","action"' as nonTerminatingMatchingRules 
        | filter strcontains(nonTerminatingMatchingRules, 'GeoBlockRule') or terminatingRuleId == "GeoBlockRule" 
        | filter action in ['ALLOW','BLOCK','CHALLENGE','CAPTCHA'] 
        | filter webaclId in ['arn:aws:wafv2:us-east-1:<AWSアカウントID>:global/webacl/website/84a704a7-6965-44af-887e-d196dcd881ac'] 
        | stats count(*) as requestCount by userAgent 
        | sort requestCount desc 
        | limit 100 | limit 100
fields ja4Fingerprint 
        | parse @message '"nonTerminatingMatchingRules":[{"ruleId":"*","action"' as nonTerminatingMatchingRules 
        | filter strcontains(nonTerminatingMatchingRules, 'GeoBlockRule') or terminatingRuleId == "GeoBlockRule" 
        | filter action in ['ALLOW','BLOCK','CHALLENGE','CAPTCHA'] 
        | filter webaclId in ['arn:aws:wafv2:us-east-1:<AWSアカウントID>:global/webacl/website/84a704a7-6965-44af-887e-d196dcd881ac'] 
        | stats count(*) as cnt by ja4Fingerprint 
        | sort cnt desc 
        | limit 100 | limit 100
fields ja3Fingerprint 
        | parse @message '"nonTerminatingMatchingRules":[{"ruleId":"*","action"' as nonTerminatingMatchingRules 
        | filter strcontains(nonTerminatingMatchingRules, 'GeoBlockRule') or terminatingRuleId == "GeoBlockRule" 
        | filter action in ['ALLOW','BLOCK','CHALLENGE','CAPTCHA'] 
        | filter webaclId in ['arn:aws:wafv2:us-east-1:<AWSアカウントID>:global/webacl/website/84a704a7-6965-44af-887e-d196dcd881ac'] 
        | stats count(*) as cnt by ja3Fingerprint 
        | sort cnt desc 
        | limit 100 | limit 100

ログエクスプローラーで簡単により詳細なログ分析が行えるようになった

Top Insightsセクションで表示されている値をクリックすると、ログエクスプローラーで表示と表示されます。

14.ログエクスプローラーで表示.png

こちらをクリックすると、選択した値に該当するログを抽出してくれます。

15.ログエクスプローラーの結果.png

複数の条件でフィルタリングも可能です。

22.ログエクスプローラーで複数フィルタリング.png

これによってGUIで簡単に通信の絞り込みを行うことが可能です。非常に便利ですね。

なお、裏側でしっかりCloudWatch Logs Insightsが実行されています。

16.ログエクスプローラー実行のタイミングでLogs Insightsが実行.png

先ほどの複数条件でフィルタリングをした時に実行されたクエリは以下のとおりです。

fields timestamp, action, httpRequest.host as host, httpRequest.uri as uri, httpRequest.httpMethod as httpMethod, httpRequest.clientIp as clientIp, httpRequest.country as country, terminatingRuleId, httpSourceName, httpSourceId, concat(httpSourceName, ' | ', httpSourceId) as resourceDetails, ja3Fingerprint, ja4Fingerprint, @message | parse @message '"name":"User-Agent","value":"*"' as userAgent
        | filter action in ['BLOCK'] 
        | filter webaclId in ['arn:aws:wafv2:us-east-1:<AWSアカウントID>:global/webacl/website/84a704a7-6965-44af-887e-d196dcd881ac'] 
        | filter timestamp > 1757188173 
        | filter httpRequest.httpMethod = 'GET' 
        | filter httpRequest.country = 'US'
        | sort timestamp desc 
        | limit 500 | limit 500

ログエクスプローラーを使用する場合はフィールドインデックスを有効活用してコスト削減をしたいですね。

各設定値の確認場所の整理

コンソールが新しくなるに伴い、各設定値の確認場所が気になります。

ということで、新しいコンソールにおけるWeb ACLの各設定値の確認場所の整理してみました。

項目 確認場所 備考
Name リソースと保護パック Web ACL(保護パック)の名前
Description リソースと保護パック-<保護パック名>-説明 Web ACL(保護パック)の説明
Resource type リソースと保護パック-<保護パック名>-スコープ Regional scopeCloudFront (Global) and Regionalを選択することで画面遷移なしで全Web ACL(保護パック)の一覧を表示
Region リソースと保護パック-<保護パック名> Web ACL(保護パック)があるリージョン
Associated AWS resources リソースと保護パック-<保護パック名>内の"リソース"横の表示および編集-リソースを管理 Web ACL(保護パック)と関連付けるリソース
Body size limit リソースと保護パック-<保護パック名>内の"リソース"横の表示および編集-本文サイズの制限 リクエストボディを検査する際の検査サイズの上限
Rules リソースと保護パック-<保護パック名>内の"リソース"横の表示および編集 Web ACL(保護パック)に設定するルール
WCUs used by your web ACL リソースと保護パック-<保護パック名>-キャパシティ WCUsの使用量
Default action リソースと保護パック-<保護パック名>-デフォルトアクション ルールにマッチしなかった場合の処理
CAPTCHA Immunity time リソースと保護パック-<保護パック名>-デフォルトイミュニティ時間内のCAPTCHA CAPTCHAトークンを使用できる期間
Challenge Immunity time リソースと保護パック-<保護パック名>-デフォルトイミュニティ時間内のChallenge Challengeトークンを使用できる期間
Token domain list リソースと保護パック-<保護パック名>-トークンドメイン AWS WAF が受け入れるリクエストを送信しているドメイン
Custom response bodies リソースと保護パック-<保護パック名>-カスタムレスポンス本文 カスタムレスポンスボディ
Sampled requests リソースと保護パック-<保護パック名>内の"ログ記録の設定"横の表示および編集-サンプルリクエスト ルールに一致する Web リクエストのサンプルを保持するか
Sampled requests for web ACL default actions リソースと保護パック-<保護パック名>内の"ログ記録の設定"横の表示および編集-サンプルリクエスト内の保護パックのデフォルトアクションのサンプルリクエスト デフォルトアクションで処理された Web リクエストのサンプルを保持するか
除外を含むサンプルリクエストを有効化デフォルトアクション有効化済みを切り替えることで明示的な指定が可能
Logging リソースと保護パック-<保護パック名>内の"ログ記録の設定"横の表示および編集-ログ記録内のステータス ログの有効化
Logging destination リソースと保護パック-<保護パック名>内の"ログ記録の設定"横の表示および編集-ログ記録内のログ記録送信先 ログの出力先となるS3バケット/CloudWatch Logs/Data Firehoseを指定
Redacted fields リソースと保護パック-<保護パック名>内の"ログ記録の設定"横の表示および編集-データ保護設定内の保護フィールド 以下から選択可能
- HTTP method
- Query string
- URI path
- 任意のヘッダー
Default log filter behavior リソースと保護パック-<保護パック名>内の"ログ記録の設定"横の表示および編集-データ保護設定内のデフォルトのログフィルター動作 デフォルトのログ出力の挙動

新しいコンソールに慣れていこう

AWS WAFのWeb ACL(保護パック)でCloudWatch Logsにログを出力している場合はコスト削減のためにも、運用負荷軽減のためにも新しいコンソールを使用する方が良いということを紹介しました。

個人的にはログエクスプローラーは最高ですね。これからは新しいコンソールを積極的に使っていきます。

この記事が誰かの助けになれば幸いです。

以上、クラウド事業本部 コンサルティング部の のんピ(@non____97)でした!

この記事をシェアする

facebookのロゴhatenaのロゴtwitterのロゴ

© Classmethod, Inc. All rights reserved.