AWS WAF のアクセスログをAmazon Managed Grafana で可視化する

維持費がとってもリーズナブルです
2024.06.06

こんにちは、なおにしです。

Amazon S3に保存されているAWS WAF のアクセスログを Amazon Managed Grafana のAmazon Athena 組み込みデータソースを使用して可視化してみましたのでご紹介します。

はじめに

Amazon S3に保存されているAWS WAF のアクセスログをAmazon Athena で解析することがあるかと思います。その際、トラブルシューティングなどでのアドホックな利用ではなく、例えば月次レポート用にデータを確認するようなシチュエーションであれば、Athena のクエリも時間指定のみが異なるだけで基本的には同じクエリを使用するというケースもあるかもしれません。

もちろん、トラブルシューティングにおいても必ず見るべき内容(特定条件のアクセス数など)が決まっているのであれば実行クエリも決まっていると思います。あとはデータ取得の時間指定と可視化を効率的にできればなあという状況であれば、本記事でご紹介するような Amazon Managed Grafana の利用がマッチするかもしれません。

やってみた

前提

ドキュメントに記載の以下2つの前提条件をAthena、S3 のそれぞれで設定しておきます。

・ Athena ワークグループに GrafanaDataSource: true でタグ付けします。

・ grafana-athena-query-results-で始まる名前の S3 バケットを作成します。このポリシーは、その命名規則を使用してクエリ結果を S3 バケットに書き込むためのアクセス許可を提供します。

また、以下の記事に記載のテーブル作成をAthena で実施済みという前提で進めます。

Amazon Managed Grafana のセットアップについては割愛します。IAM Identity Centerによる認証を利用したログインが最も簡単にセットアップできますが、AWS Organizations が使用できない環境の場合は以下の記事などをご参照ください。

セットアップする際はAmazon Athena のデータソースを有効化するように選択してください。
今回はGrafana バージョン「9.4」で動作を確認しました。

Athena データソースの追加

作成されたGrafana のワークスペースから[データソース]タブでAthena のデータソースが有効化されていることを確認します。

上記スクリーンショットの[Grafana で設定]のリンクからGrafana のデータソースの追加画面に遷移します。
[Service]でAthenaが選択されている状態なので、今回はリージョンで[Asia Pacific(Tokyo)]を選択します。
すると既存のAthenaのデータソース/データベースが表示されるので、対象を選択してデータソースの追加ボタンを押下します。

一瞬ですが画面右上に以下のとおりデータソースが追加されたメッセージが出力されます。

すると画面下部に以下のように追加されたデータソースが表示されます。(私が作業している端末の解像度では画面下部が絶妙に見切れていたため、最初は「どこに追加されたんだ?」ってなりました。同様の方はご注意ください)

実際に追加されたデータソースが管理されている箇所は[Home] - [Administration] - [Data Sources] 配下になります。

ここで各種セッティングを行います。今回は[Workgroup]の項目だけAthena で作成したテスト用のワークグループを指定しました。

Athena クエリの実行

可視化する前に実際にAthena のクエリを実行して結果を確認することができます。左ペインから[Explore]を選択します。

先ほど作成したデータソースを選択すると、クエリの実行画面になります。
画面左部分で各種設定をします。TableとColumnについてはクエリ内で指定するので空欄で問題ありません。

前提に記載した記事に記載のクエリをそのままコピー&ペーストして実行してみます。

Athenaで実行した時のようにクエリ実行結果が画面下部に出力されています。また、クエリを貼り付けた際に[Format as]には自動的に[Table]が入力されました。

なお、[Explore]でクエリを実行した際のログはデータソース設定の[Output Location]ではなくAthena の設定に基づいて出力されていました。このため、クエリを実行した際に「Query error: 400 Bad Request」が表示される場合はログ出力先のS3 バケットへの書き込み権限(s3:PutObject)をAmazonGrafanaServiceRoleに追加してみてください。

時系列クエリで利用可能なマクロの活用

上記で実行したクエリではデータを取得する対象の時間をクエリ内で直接指定しています。このため、画面右上にある時間指定の機能を完全に無視している状態です。実際には以下のように詳細かつ直感的に時間指定をするための機能が提供されています。

この機能とAthena で実行するクエリを連携させるためには、組み込みのマクロをクエリ内で記述します。
マクロについてはこちらのAWSドキュメントにまとまっています。

また、今回はクエリ内でtimestampカラムに対して条件を指定したいため、UNIXミリ秒を直接指定できるようなマクロがあれば良かったのですが、前述のAWSドキュメントには記載がありませんでした。

このため Grafana のドキュメントを確認したところ、こちらに該当のマクロ(グローバル変数)の記載がありました。

まとめると、今回は以下のマクロ(グローバル変数)を利用して先ほど実行したクエリをGrafana の時間指定と連携するように修正してみます。

マクロ 説明 出力例
$__timeFrom() $__timeFrom は、パネルの範囲の現在の開始時刻を引用符で出力します $__timeFrom() TIMESTAMP '2017-07-18 11:15:52'
$__timeTo() $__timeTo は、パネルの範囲の現在の終了時刻を引用符で出力します $__timeTo() TIMESTAMP '2017-07-18 11:15:52'
${__from} パネルの時間範囲のFromで指定した時刻のUNIXミリ秒を返します ${__from} 1594671549254
${__to} パネルの時間範囲のToで指定した時刻のUNIXミリ秒を返します ${__to} 1594671549254

修正後のクエリは以下のとおりです。

WITH
    waf_logs_test_partition AS (
        SELECT
        	*
        FROM
            waf_logs_test
        WHERE
            date BETWEEN format_datetime($__timeFrom(), 'YYYY/MM/dd/HH') AND format_datetime($__timeTo(), 'YYYY/MM/dd/HH')
    )
SELECT
	timestamp,
	date_format(from_unixtime(timestamp/1000), '%Y/%m/%d %H:%i:%s') AS timestamp_converted,
	action,
	httprequest.country AS country,
	NOW() AS date_now,
	date
FROM
    waf_logs_test_partition
WHERE
    timestamp BETWEEN ${__from} AND ${__to}
ORDER BY timestamp DESC

実際にGrafana で実行してみます。

Grafana では「5/22 9:00 〜 5/22 9:01」を時間指定したところ、取得できたデータは「5/22 0:00 〜 5/22 0:01」の範囲でした。これは、時間指定する際のタイムゾーンが[Browser Time Japan, JST UTC+09:00]となっているためであり、自動的に9時間マイナスしてくれているからです。タイムゾーンを意図的に変更したい場合は[Change time settings]から変更可能です。

また、マクロ(グローバル変数)に実際の時間が入ったクエリを確認するには、画面上の[Inspector]ボタンを選択して、[クエリ]タブを開いてクエリを再実行すること確認できます。

同様の履歴はAthena のコンソールからも確認可能です。Athena のクエリエディタから[最近のクエリ]を開いて、他にクエリを実行していなければ直近の[実行ID]を選択すると、以下のように表示されます。

[スキャンしたデータ]の容量などはこちらで確認できます。(Grafana のデータソースでは[test]ワークグループを指定していましたが、[primary]ワークグループの方に実行履歴がありました。Exploreでのクエリ実行はそういう挙動なのかもしれません)

Grafana による可視化

それではGrafana のダッシュボードを用いてデータを可視化してみます。先ほどのクエリはアクセスログに含まれる時間を確認することが目的だったため、今回は可視化しやすくするために[actions](ALLOW または BLOCK)の件数を取得してみます。使用するクエリは以下のとおりです。

WITH
    waf_logs_test_partition AS (
        SELECT
            timestamp,
        	  action
        FROM
            waf_logs_test
        WHERE
            date BETWEEN format_datetime($__timeFrom(), 'YYYY/MM/dd/HH') AND format_datetime($__timeTo(), 'YYYY/MM/dd/HH')
    )
SELECT
	action,
	COUNT(action)
FROM
    waf_logs_test_partition
WHERE
    timestamp BETWEEN ${__from} AND ${__to}
GROUP BY action

まず、Explore で実行した結果は以下のとおりです。この結果を可視化するために、[Add to dashboard]を選択します。

以下のポップアップが表示されるので、新しくダッシュボードを作成する場合は[New dashboard]を選択します。

最初の状態ではテーブルのパネルとして表示されるので、パネル右上から[Edit]を選択します。

パネルの設定画面が表示されます。ここでクエリの編集をしたり、パネルでどのように表示するのか設定することが可能です。右上の枠で囲った部分が[Table]になっているため、上記のようなパネル表示になっています。このため、[Table]以外を選択してみます。

数多くの可視化方法が選択可能ですが、分かりやすいのはデータに応じて適した可視化方法を提示してくれる[Suggestions]タブから選択することです。以下のように直感的に分かりやすい可視化方法が表示されています。

上記の中の[Pie Chart]を選択してみます。また、[Title]を例えば[WAF アクセス]に設定すると、以下のようになります。[Apply]を押すと、ダッシュボードに戻ります。

良い感じに可視化できてます。あとは[Add panel]ボタンから同様にパネルを作成して、保存ボタンを押してダッシュボードを保存すれば完成です。

料金

細かなクエリを検討する必要があるものの、本構成の大きな利点は維持費にあると思います。今回の構成であればAmazon Managed Grafana の Enterprise プラグインは不要であるため、「エディター」ライセンスと「ビューアー」ライセンスのみを検討すれば良いことになります。

  • エディター:9ドル/月 (160円/ドルなら 1,440円/月)
  • ビューアー:5ドル/月 (160円/ドルなら 800円/月)

仮に1ヶ月の間に誰もGrafanaにログインしない、もしくはエディターライセンスのユーザ1人がログインしたというケースであれば、Amazon Managed Grafana として請求される費用はエディターライセンス1名分のみです。 そこにAthena のクエリ料金を加算する形になりますが、前提としてAthena のPartition Projection を活用したクエリを実行するように設定できていれば、クエリ実行による課金も相当抑えることができます。このため、それほどログデータが多くない環境でクエリ実行頻度も高くなければ、おおよそ1,500円~が維持費の目安です。

Amazon Managed Grafana の料金の詳細はこちらからご確認ください。上記の料金計算パターンはサイト内の例3 ワークスペースAの場合に相当します。

まとめ

同様の可視化は例えば Amazon OpenSearch Service にアクセスログを連携させることで、OpenSearch と OpenSearch Dashboards(≒ Elasticsearch と Kibana)によって実現できるかと思いますが、今回の構成に比べると維持費が非常に高くなります。もちろん、Amazon OpenSearch Service の機能を活用してログ分析をするのであれば選択肢の一つとなりますが、アクセスログを可視化してダッシュボードで閲覧したいといった用途のみであれば今回の構成でも十分かもしれません。本記事がどなたかのお役に立てれば幸いです。