1. はじめに
FortiGate を想定したファイアウォールログを、
S3 + Glue Data Catalog + Athena + IAM で検索できるようにする
Terraform リポジトリを作りました。
https://github.com/tenpa7188/terraform-fw-log-analytics
このリポジトリを作ったきっかけは、
syslog サーバ上で 1 年分の FW ログを zgrep などで検索していると、
検索に時間がかかるうえに、
担当者ごとに調査手順がばらついていたことでした。
最初の段階で優先したのは、
「とにかく最速の検索基盤を作ること」ではなく、
「検索手順を標準化し、再現しやすくすること」でした。
MVP 時点では、検索手順の標準化と再現性の確保を優先しており、
大量ログ検索の速度課題そのものはまだ完全には解決していませんでした。
その後、raw ログを原本として残したまま、
Athena ベースの ETL で Parquet を日次生成する構成まで実装しました。
今は標準検索を Parquet テーブルへ寄せることで、
検索時間の課題も改善できています。
この記事では、どんな課題を解決したかったのか、
なぜこの構成にしたのか、
そして Parquet 化を入れたあとに何が変わったのかをまとめます。
2. 解決したかった課題
- syslog サーバ上で大量のログを
zgrepしていて時間がかかる - 一部ログ抽出や正規表現の使い方が担当者ごとに違う
- 調査の再現性が低く、引き継ぎもしづらい
この状況に対して、次の 3 点を整えたかったです。
- ログを安全かつ低コストで保管する
- Athena で検索できる状態を Terraform で再現可能にする
- Runbook と SQL テンプレートで検索手順を標準化する
単に AWS リソースを作るのではなく、
「ログ調査のやり方ごとコード化する」ことを目標にしました。
評価軸として置いたのは、
「zgrep より常に速いか」だけではなく、
「再作成できるか」「権限を分けられるか」「調査手順を共有できるか」です。
そのうえで、
検索時間の課題に対しても段階的に手を入れています。
text + gzip + RegexSerDe構成では、検索速度の抜本改善は今後の課題として残る- 現在は raw ログから Parquet を生成し、
標準検索先をfw_log_analytics.fortigate_logs_parquetに切り替えている - 障害時や生ログ確認は raw テーブルへフォールバックできるようにしている
3. 今回の前提と、まず揃えたこと
まず、今回の構成は次の前提で組んでいます。
| 項目 | 前提 |
|---|---|
| 想定ログ量 | 0.5-2GB/日(生ログ) |
| 既定保持期間 | 365日 |
| 延長上限 | 1825日 |
| Athena 同時実行 | 最大 10 クエリ想定 |
| 検索対象 | FortiGate の traffic ログ |
| 優先順位 | 最速化より、標準化・再現性・責務分離 |
| 適用範囲 | まずは検証環境で再現するところまで。本番導入時は既存 syslog 経路、監視、監査要件を別途考慮 |
そのうえで、今回まず揃えたものは次の通りです。
- Terraform で S3、Glue、Athena、Lambda、EventBridge Scheduler、IAM を再作成できる状態
- S3 の公開禁止、暗号化、Versioning、Lifecycle の適用
- raw テーブルと Parquet テーブルの両方を定義し、
標準検索は Parquet、障害時は raw へ切り替えられる状態 - Athena で
srcip、dstip、期間、actionを検索できる状態 - Runbook と SQL テンプレートによる検索手順の標準化
- backfill / rebuild / 性能比較まで回せる補助スクリプト
- IAM ロールでの責務分離
今回の主眼は、検索速度の抜本改善そのものよりも、
「保管」「検索」「権限制御」「運用手順」を
再現可能な形でまとめることでした。
現在はそこに加えて、
Parquet 標準検索まで含めて
「運用に乗せられる検索基盤」をまとめた状態になっています。
4. 作ったもの
全体像は次のような構成です。
ここで示しているのは、再現性を確認するための検証環境です。
FortiGate VM と syslog サーバは、ローカルの VirtualBox 上で動かしています。
そのため、本番環境にそのまま適用する前提ではなく、
実運用では既存の syslog 経路、監視、アラート、監査要件を別途組み込む想定です。
流れとしてはシンプルです。
FortiGate から syslog サーバでログを受け取り、
日次ローテートした gzip ログを raw として S3 に送ります。
その raw を元に Parquet を生成し、
Athena で検索できるようにしています。
現在の検索経路は、次の 2 段構えです。
- raw テーブル
fw_log_analytics.fortigate_logs-
text + gzip + RegexSerDeで生ログを読む -
raw_lineを保持し、抽出漏れ確認やHIVE_BAD_DATA切り分けに使う
-
- Parquet テーブル
fw_log_analytics.fortigate_logs_parquet- Lambda
parquet-etl-runnerが Athena ETL WorkGroup を使って raw から生成する - 標準検索はこちらを使う
- Lambda
当初は、S3 に text + gzip の生ログを保存し、
Glue Data Catalog のテーブル定義に RegexSerDe を持たせ、
Athena がクエリ時にその定義を使って必要な列を解釈する構成だけでした。
今は raw を原本として残しつつ、
Parquet を検索最適化用の派生データとして持つ構成です。
Terraform で作成している主なリソースは次の通りです。
- FortiGate raw ログ保管用プレフィックス
fortigate/ - FortiGate Parquet ログ保管用プレフィックス
fortigate-parquet/ - Athena の結果出力先プレフィックス
athena-results/ - Athena ETL の結果出力先プレフィックス
athena-results/etl/ - Glue Database
fw_log_analytics - Glue Table
fortigate_logs - Glue Table
fortigate_logs_parquet - Athena WorkGroup
fw-log-analytics-wg - Athena ETL WorkGroup
fw-log-analytics-etl-wg - Lambda
parquet-etl-runner - EventBridge Scheduler による日次 ETL 起動設定
- IAM ロール
ingestanalystparquet_etlparquet_etl_schedulerterraform
Terraform だけでなく、運用に必要な補助ファイルも同じリポジトリに入れました。
- ログ検索・運用手順書
runbook/athena-search.mdrunbook/sql-templates.md
- syslog サーバ -> S3 アップロード用スクリプト
scripts/30-fortigate.confscripts/upload-fortigate-logs.sh
- Parquet ETL 補助スクリプト
scripts/invoke-parquet-backfill.ps1scripts/invoke-parquet-rebuild.ps1
- 性能比較スクリプト
scripts/run-athena-performance-tests.ps1
- IAM 権限テスト用スクリプト
terraform/tests/iam-policy-simulator.ps1
5. Terraform 側で意識したこと
5.1 まずは安全に保管できること
ログを置くバケットでは、
「あとで事故りやすいところ」を最初から Terraform に入れました。
- Public Access Block を全有効化
- バケットデフォルト暗号化を有効化
- Versioning を有効化
-
force_destroy = falseにして、バケット内にオブジェクトが残っていると destroy できないようにする
5.2 コストが暴れないようにすること
Athena は便利ですが、
何も考えずに使うとスキャン量で課金が膨らみます。
そのため、次の前提を強く置いています。
- raw / Parquet ともに S3 パスは
year/month/dayパーティション前提 - Athena の標準検索結果と ETL 結果の保存先を分ける
- 1 クエリあたりのスキャン上限を設定する
- raw ログは
.log.gzで圧縮保存する - Parquet は
SNAPPY圧縮で保持する - Runbook でも
count(*)と日付条件の確認を先に行う
S3 側でも Lifecycle を設定して、
fortigate/ は一定期間後に STANDARD_IA へ移行し、
保持期間を過ぎたら削除するようにしています。
「保管は長く、でも無駄には高くしない」を狙った構成です。
5.3 raw と Parquet の役割を分けること
raw テーブルでは RegexSerDe を使って、
FortiGate の key=value ログから必要な項目だけを抽出しています。
全部の項目を厳密に列化するのではなく、
日常的によく使う検索軸を優先しました。
-
log_date: FortiGate ログ中のdate=から取り出した通信発生日 -
log_time: FortiGate ログ中のtime=から取り出した通信発生時刻 -
srcip: 通信元 IP アドレス -
dstip: 通信先 IP アドレス -
srcport: 通信元ポート番号 -
dstport: 通信先ポート番号 -
proto: 通信プロトコル番号。たとえば6は TCP、17は UDP -
action_raw: FortiGate が記録した通信の処理結果。acceptやdenyなど -
policyid: どの FortiGate ポリシーにマッチした通信かを示すポリシー ID -
raw_line: 元のログ 1 行をそのまま保持した文字列。抽出していない項目を後から確認するときのフォールバック
特に残したかったのが raw_line です。
よく使う検索軸は列として持たせつつ、
想定外の調査では生ログ文字列へフォールバックできるようにしました。
そのうえで、
標準検索用には Parquet テーブルを別に持たせています。
Parquet 側では srcport、dstport、proto、policyid を数値型にし、
通常検索でよく使う列だけに寄せています。
使い分けとしては次のイメージです。
- 標準検索
fw_log_analytics.fortigate_logs_parquet
- 障害時のフォールバック
fw_log_analytics.fortigate_logs
- 生ログ行の確認
raw_line
-
HIVE_BAD_DATAや抽出漏れ確認- raw テーブル
また、対象はあえて traffic ログに絞っています。
event/system ログまで同時にやると初期段階の構成が複雑になりすぎるので、
rsyslog 側で traffic と event/system を分離し、
Athena の検索対象は traffic のみにしています。
6. IAM と運用の責務分離
IAM では、役割を 5 つに分けました。
-
ingestロール -
analystロール -
parquet_etlロール -
parquet_etl_schedulerロール -
terraformロール
それぞれの責務は次のイメージです。
-
ingest- raw ログの S3 アップロード
- raw Glue パーティション登録
-
analyst- Athena での標準検索
- Glue メタデータ参照
- raw / Parquet の読み取り
-
parquet_etl- Athena ETL WorkGroup を使った Parquet 生成
- Parquet Glue パーティション登録
-
fortigate-parquet/と ETL 結果出力先の書き込み
-
parquet_etl_scheduler- EventBridge Scheduler から Lambda を起動
-
terraform- このプロジェクトに必要な S3、Glue、Athena、Lambda、Scheduler、IAM の管理
特に意識したのは、
ログを投入する役割、
検索する役割、
ETL を回す役割を分けることです。
標準検索用 WorkGroup と ETL 用 WorkGroup も分けているので、
クエリ履歴、失敗確認、コスト把握を切り分けやすくしています。
7. Terraform だけで終わらせないために入れたもの
今回のリポジトリでは、
AWS リソースを作るだけで終わらないようにしたかったので、
運用手順も一緒に揃えました。
7.1 syslog サーバ側の補助ファイル
scripts/30-fortigate.conf では、
FortiGate の syslog を受けて、
traffic と event/system を別ファイルに振り分けています。
scripts/upload-fortigate-logs.sh では、
日次ローテート済みの gzip ログを S3 にアップロードし、
必要であれば raw Glue パーティション登録まで自動実行します。
これにより、
Athena 側で毎回手動の ALTER TABLE を打たなくても、
日次運用しやすい形にしました。
7.2 Runbook と SQL テンプレート
検索の属人化を減らすために、
Runbook と SQL テンプレートを用意しています。
Runbook では、
次のような順番で確認する前提にしています。
- S3 に対象日のログがあるか
- raw パーティションが見えているか
- Parquet パーティションが見えているか
- まず
count(*)で件数があるか - その後に
srcipやdstipの詳細検索をする
また、一次切り分けも揃えました。
- 0 件のとき
- Parquet パーティション未生成のとき
-
AccessDeniedのとき -
HIVE_BAD_DATAのとき
ログ形式の崩れや想定外データが混ざっていないかを確認する
調査の最初の 10 分で迷いやすいところを、
できるだけ文章化したかったというのがあります。
7.3 Parquet ETL 補助スクリプト
Parquet 化を入れたあと、
対象日だけを埋める backfill と、
対象日を作り直す rebuild を
PowerShell スクリプトで回せるようにしました。
-
scripts/invoke-parquet-backfill.ps1- raw はあるが Parquet が未生成の日を埋める
-
scripts/invoke-parquet-rebuild.ps1- 対象日の Parquet を削除して再生成する
-
scripts/run-athena-performance-tests.ps1- raw / Parquet を同条件で比較する
-
terraform/tests/iam-policy-simulator.ps1- 役割ごとの権限境界を確認する
特に backfill / rebuild を入れたことで、
日次 ETL が遅れた日や、
対象日だけ作り直したいケースにも対応しやすくなりました。
7.4 zgrep と Athena Parquet の検索時間比較
速度面についても、
どの条件でどちらを使うのが妥当かを確認するために、
gzip ログを syslog サーバで zgrep した場合と
Athena で検索した場合の実行時間を比較しました。
raw text ベースの Athena 検索では、
1 日分と 30 日分は zgrep の方が速く、
速度改善は今後の課題として残っていました。
現在は Parquet 化を入れたことで、
標準検索の比較結果は次のようになっています。
| 条件 | zgrep 実行時間 | Athena 実行時間 | Athena 改善比(対 zgrep) | 結果 |
|---|---|---|---|---|
| 100万行・1ファイル(1日分) | 3.37 sec | 0.82 sec | 72.8% 短縮 | Athena Parquet の方が速い |
| 100万行・30ファイル(1ヶ月分) | 1 min 52 sec | 2.16 sec | 98.1% 短縮 | Athena Parquet の方が大幅に速い |
| 100万行・365ファイル(1年分) | 28 min 39 sec | 9.57 sec | 99.4% 短縮 | Athena Parquet の方が大幅に速い |
この結果を見ると、
短期の検索でも Athena Parquet が十分に速く、
ファイル数が増えるほど差は広がります。
少なくとも今の構成では、
「長期横断検索のときだけ Athena が有利」という段階ではなく、
標準検索そのものを Parquet 側へ寄せてよい状態になりました。
今回の価値は、速度だけでなく、
検索手順の標準化、権限制御、再現性の確保にあります。
ただ、そこに加えて
検索時間の課題もちゃんと改善できたのが
今回の更新で一番大きかったところです。
8. 今回あえて割り切ったこと・今後やりたいこと
一番大きい割り切りは、
検索速度そのものの抜本改善まではやっていないことです。
現在は traffic ログについては、
raw -> Parquet の ETL と
Parquet 標準検索まで実装できています。
今回まず取りたかった価値は次の 2 つです。
- 再現可能な形で保管と検索基盤を作ること
- 検索手順を標準化すること
逆に、今はスコープ外にしているものもあります。
Parquet 変換による Athena の速度とコストの改善- event/system ログの Parquet 化と検索対象拡張
- GUI の検索画面
- Terraform の modules 化
このあたりは、実際に使いながら必要性が高くなった段階で広げる前提です。
まずはここまでで、
「安全に保管できる」
「Athena で速く調べられる」
「運用手順が揃っている」
ところまでを形にできました。
9. まとめ
このリポジトリでやりたかったことを一言で言うと、
ログ調査を「担当者の勘と手癖」ではなく、
「再現可能な運用手順」に寄せることです。
今は raw を原本として残しつつ、
Parquet を標準検索先にしたことで、
「安全に保管できる」
「速く検索できる」
「調査手順を共有できる」
ところまでを形にできています。
Terraform で AWS リソースを作るだけでなく、
Runbook、SQL テンプレート、ETL 補助スクリプトまで含めて管理することで、
運用で使い始めるための土台を揃えています。
実装の過程で Terraform や AI 補助を試せたのも副次的な収穫でした。
