【目次】
1. はじめに
AWSでは、Amazon CloudWatchというAWS内の他のリソースのモニタリングなどをできるサービスがあります。
AWS WAFのWAFログの出力先をCloudWatch Logsにした場合、WAFの検知状況などもCloudWatchにて集計し、ダッシュボードとして表示できます。
本ブログ記事では、Github上で公開されていたCloudWatch Dashboard for AWS WAFのCloudFormationテンプレートを参考に、ダッシュボードを作成してみます。
2. ダッシュボードの作成方法
CloudWatchのダッシュボードは、以下の手順で作成が可能です。
- AWS WAFのLogging and metrics画面にてAmazon CloudWatch Logs log groupにWAFログを出力するよう設定する
- AWSマネージメントコンソールでCloudWatchを開く
- 左側のメニューのDashboardをクリックする
- Create dashboardをクリックする
- ダッシュボードの名前を入力し、Create dashboardをクリックする
- Add widgetというポップアップが表示されますので、MetricsやLogsなどの選択肢から、表示したいデータを調整する
画面右上の「+」アイコンからもウィジェットを追加できます。
今回はCloudWatch Dashboard for AWS WAFのテンプレートを使用するため、CloudFormationを使って簡単にダッシュボードを作成することができます。
また、既存のダッシュボードがあり、その中にウィジェットを追加したいといった場合には、ActionsメニューからView/edit sourceをクリックして、テンプレートのJSON文をペーストすることも可能です。
JSON文のシンタックスなどについては、以下のAWS公式ドキュメントもご参考ください。
Dashboard Body Structure and Syntax
3. 作成したダッシュボードについて
上記テンプレートを用いて作成したダッシュボードは以下のスクリーンショットのようになります。
表示されるウィジェットは以下の通りとなっており、さまざまなデータをまとめて閲覧できるようになっています。
- 許可されたリクエスト vs ブロックされたリクエスト
- Countされたリクエスト
- Botによるリクエスト vs Botではないリクエスト
- Botリクエストの割合
- 検知したルールのランキング
- リクエスト元の国のランキング
- User-Agentのランキング
- リクエスト元のIPアドレスのランキング
- CountされたURIのランキング
- ブロックされたURIのランキング
- Countされたリクエスト
- ブロックされたリクエスト
Botに関するデータについては、AWSが提供するBot Controlのマネージドルールで付与されるラベルを用いています。今回作成したテスト環境ではBot Controlルールを使用していないため、Botによるリクエストは集計できていません。
また、このテンプレートでは、「COUNT」という文字列を対象にログを検索する「Counted Requests」ウィジェットがあります。
AWS WAFではルールそのもののアクションがCountになっている場合や、ルールグループをCountでオーバーライドしている場合など、Countといっても集計すべきデータが異なる場合がありますので、「COUNT」という文字列でさまざまなケースをカバーできるようになっています。
あまりないケースかとは思いますが、「COUNT」という文字列での一致になりますので、例えばルール名で同じ文字列を使用した場合もマッチ対象となります。この方法で集計する際にはルール名に「COUNT」という文字列を使用しないようにする必要があります。
※大文字小文字は区別されますので、「Count」や「count」はマッチしません。
4. 変数について
2023年6月30日にCloudWatchダッシュボードでは変数の提供が開始されました。
Amazon CloudWatch がダッシュボード変数のサポートを開始
変数を使うことで、複数のリージョンやWeb ACLのデータを同じダッシュボード内で切り替えてみることができるようです。
今回は、上記テンプレートの一部ウィジェットを使ってメトリクスとログ両方のウィジェットでWeb ACLやロググループ名の変更を試しました。
スクリーンショット上部に表示されている「WebACL」や「LogGroupName」などのプルダウンで選択肢を切り替えることで、表示するデータが変わります。
JSON形式のソースは以下の通りです。
※JSON内の "Web ACL名"
、 "リージョン"
、 "aws-waf-logs-ロググループ名1,2"
は環境にあわせて変更が必要です。
{ "variables": [ { "type": "property", "property": "WebACL", "inputType": "select", "id": "WebACL", "label": "WebACL", "visible": true, "search": "{AWS/WAFV2,Region,Rule,WebACL}", "populateFrom": "WebACL" }, { "type": "pattern", "pattern": "LogGroupName", "inputType": "select", "id": "LogGroupName", "label": "LogGroupName", "defaultValue": "aws-waf-logs-ロググループ名1", "visible": true, "values": [ { "value": "aws-waf-logs-ロググループ名1", "label": "aws-waf-logs-ロググループ名1" }, { "value": "aws-waf-logs-ロググループ名2", "label": "aws-waf-logs-ロググループ名2" } ] } ], "widgets": [ { "height": 6, "width": 6, "y": 0, "x": 0, "type": "metric", "properties": { "metrics": [ [ "AWS/WAFV2", "AllowedRequests", "WebACL", "Web ACL名", "Region", "リージョン", "Rule", "ALL", { "id": "m1" } ], [ ".", "BlockedRequests", ".", ".", ".", ".", ".", ".", { "id": "m2" } ] ], "view": "timeSeries", "stacked": true, "region": "リージョン", "stat": "Sum", "title": "Allowed vs Blocked Requests", "period": 300, "yAxis": { "left": { "showUnits": false } } } }, { "height": 6, "width": 6, "y": 0, "x": 6, "type": "metric", "properties": { "metrics": [ [ "AWS/WAFV2", "CountedRequests", "WebACL", "Web ACL名", "Region", "リージョン", "Rule", "ALL" ] ], "view": "timeSeries", "stacked": true, "region": "リージョン", "stat": "Sum", "title": "All Counted Requests", "period": 300, "yAxis": { "left": { "showUnits": false } } } }, { "height": 6, "width": 6, "y": 0, "x": 12, "type": "log", "properties": { "query": "SOURCE 'LogGroupName' | fields httpRequest.clientIp\n| stats count(*) as requestCount by httpRequest.country\n| sort requestCount desc\n| limit 100", "region": "リージョン", "title": "Top Countries", "view": "pie" } }, { "height": 6, "width": 6, "y": 0, "x": 18, "type": "log", "properties": { "query": "SOURCE 'LogGroupName' | fields httpRequest.clientIp\n| stats count(*) as requestCount by httpRequest.clientIp\n| sort requestCount desc\n| limit 100", "region": "リージョン", "title": "Top IP Addresses", "view": "table" } } ] }
このダッシュボードでは、「Allowed vs Blocked Requests」と「All Counted Requests」がメトリクスを使用したウィジェットになっています。
こちらは、WebACLというプルダウンに指定したWeb ACLの名前をもとに、そのWeb ACLのデータを集計します。
「Top Countries」と「Top IP Addresses」はログを使用したウィジェットです。
こちらはクエリを使って集計しており、ログウィジェットのqueryでは必ず SOURCE
というキーワードを使ってロググループ名を指定する必要があります。
プロパティ変数で簡単に指定するといった仕組みはないようでしたので、パターン変数で正規表現を用いてロググループ名を記載する範囲に「LogGroupName」とあらかじめソース上で指定し、その値を差し替えるような形にしています。
なお、JSON上で SOURCE
というキーワードに対して「LogGroupName」と記載した場合、ダッシュボードを開いたタイミングなどでロードする際に存在しないロググループ名のため、エラーとなります。
プルダウンからロググループ名を指定するとクエリが再実行されデータが表示されますが、画面を開いたタイミングで表示されるエラーを回避する場合は、JSON上で defaultValue
をあらかじめ指定しておくと良いかと思います。
変数については、ダッシュボード変数を使用して柔軟なダッシュボードを作成するもご確認ください。
5. おわりに
CloudWatchのダッシュボードでは、WAFログをCloudWatch Logsに出力している場合に比較的気軽にデータの集計が行えます。
Githubにて公開されているテンプレートなども使用すると、より簡単にダッシュボードの作成が可能です。
多数のWeb ACLを運用している場合などは、変数を使うことで1つのダッシュボードの中で切り替えができる点も便利な機能かと思います。
AWSにてWafCharmをご利用の場合にご提供しております月次レポート・検知通知機能ではCloudWatch Logsに出力されたWAFログを使用できないため併用は難しいですが、すでにCloudWatch LogsにWAFログを出力されていて、ダッシュボードは作成されていない場合にはぜひ検討いただいてもいいかと思います。