syslogを向けるだけでAIが機器種別を自動判定して監視を始める仕組みを作った #
新しい機器がsyslogを送り始めた瞬間に、LLMがログサンプルを読んで「これはWindowsクライアントだ」「これはファイアウォールだ」と自動判定。適切な監視テンプレートを適用して即座に監視を開始する。機器の手動登録は不要。
従来の監視導入で一番面倒なこと #
監視ツールを導入するとき、最も工数がかかるのは初期設定ではなく「機器ごとの登録作業」です。
Zabbixでもその他のSIEMでも、新しい機器を監視対象に追加するたびに「ホスト登録→テンプレート選択→パーサー設定→テスト→本番適用」の手順が必要です。10台なら2〜3人日、100台なら20〜30人日。しかも機器が増減するたびにこの作業が発生します。
BASTIONではこの工程自体を消しました。
仕組みの全体像 #
以下の5つのステップが全自動で動きます。
| ステップ | やること | 実行タイミング |
|---|---|---|
| 1. ログ到着 | 新しい機器がsyslogを送信。rsyslogがホスト名でディレクトリを自動作成 | 即時 |
| 2. 新規ホスト検出 | 前回のホストリストと比較し、新しいディレクトリを発見 | 1日1回(cron) |
| 3. LLM分類 | ログサンプルをLLMに送り、機器種別を自動判定 | 新規検出時 |
| 4. テンプレート適用 | 判定結果に応じた監視テンプレートをデバイスレジストリに登録 | 分類完了時 |
| 5. 監視開始 | 次回の定期分析(15分ごと)でテンプレートが自動的に呼び出される | 次回cron実行時 |
つまり、機器がsyslogを送り始めてから最短で15分後には監視レポートがSlackに届きます。
ステップ1: rsyslogによるディレクトリ自動生成 #
BASTIONのrsyslogは、受け取ったsyslogの送信元ホスト名ごとにディレクトリを自動作成します。
/var/log/remote/ ホスト名A/2026/04/Security-Auditing.log ホスト名B/2026/04/sshd.log ホスト名C/2026/04/filterlog.log ...
新しい機器がsyslogを送り始めると、設定変更なしでディレクトリが出現します。これがすべての自動化の起点です。
ステップ2: 新規ホストの自動検出 #
検出スクリプトが1日1回、ディレクトリの一覧を前回のリストと比較します。
ここで重要なのは「何を監視するか」ではなく「何を除外するか」を管理するという逆転の発想です。既存のサーバーやネットワーク機器(既にsummarize.shで個別にパース処理を書いているもの)は除外リストに入れておき、それ以外は全部「新規クライアント」として扱います。
# 除外リスト(サーバー/NW機器のホスト名パターン) EXCLUDE_HOSTS="既存サーバー1|既存サーバー2|既存FW|..." # /var/log/remote/ のホスト一覧から除外リストを引く # → 残ったものが新規クライアント
検出結果に応じてSlackに通知します。
| 状況 | 通知 |
|---|---|
| 新規ホスト出現 | 「新しいクライアントからログが届き始めました。自動分類して監視を開始します」 |
| ログ停止 | 「このクライアントからログが届かなくなりました。NXLogの状態を確認してください」 |
| 48時間以上非アクティブ | 「48時間以上ログが更新されていません」 |
| 変化なし | 通知しない(ログのみ) |
ステップ3: LLMによる自動分類 #
ここが核心です。新規ホストが検出されると、そのホストのログファイルからサンプル(上位5ファイル×末尾20行)を取得し、LLMに分類を依頼します。
何を判定するか #
以下の9カテゴリに分類します。
| カテゴリ | 機器種別 | ログの特徴(LLMが見るポイント) |
|---|---|---|
| win_client | Windows クライアント | Security-Auditing、LogonType 2/10、PowerShell |
| win_server | Windows Server | Security-Auditing、Kerberos TGT/TGS、Directory Service |
| linux | Linux サーバー | sshd、sudo、systemd、kernel |
| firewall | ファイアウォール | filterlog、block/pass、NAT、VPN |
| switch | L2/L3 スイッチ | link up/down、STP、loop |
| loadbalancer | ロードバランサー | backend、frontend、health check |
| webserver | Web サーバー | HTTP status、GET/POST、access_log形式 |
| router | ルーター | BGP、OSPF、routing |
| unknown | 判定不能 | 上記いずれにも該当しない → 人間にエスカレーション |
LLMへの分類依頼 #
GPUStack(ローカルLLMサーバー)のOpenAI互換APIに直接リクエストを送ります。プロンプトにはホスト名、ログファイル一覧、ログサンプルを添付し、JSON形式で分類結果を返すよう指示します。
# 分類リクエスト(概要)
curl -s -X POST "${GPUSTACK_URL}/v1/chat/completions" \
-H "Authorization: Bearer ${API_KEY}" \
-d '{
"model": "qwen2.5-14b-instruct",
"messages": [{
"role": "system",
"content": "You are a device classifier. Classify this host..."
}, {
"role": "user",
"content": "Hostname: XXX\nLog files: ...\nSample: ..."
}],
"temperature": 0.1
}'
# → 応答例
{
"category": "win_client",
"confidence": "high",
"os_detail": "Windows 10/11 desktop",
"reasoning": "Security-Auditing logs with LogonType 2..."
}LLMの応答からJSON部分を抽出し、デバイスレジストリに登録します。
実装で踏んだ罠:OpenClaw経由だと全部unknownになる #
最初はOpenClaw(AIエージェント基盤)経由でLLMを呼んでいましたが、分類プロンプト内の「win_client」「firewall」等のキーワードがAGENTS.md(システムプロンプト)のキーワードマッピングに干渉し、LLMが分類の代わりにツール呼び出し文字列を返してしまいました。解決策はシンプルで、分類処理だけはOpenClawを経由せず、GPUStackのAPIを直接curlで叩くようにしました。プロンプトも英語化してキーワード干渉を排除しています。
もう1つの罠:bashのheredocとpipeのstdin衝突 #
LLM応答のJSON抽出をPythonで書いたところ、bashのheredoc(<<'EOF')がpipeの標準入力を奪い、Python側のjson.load(sys.stdin)がPythonコード自体を読もうとする問題が発生。常に空の分類結果が返っていました。Python部分を外部スクリプトに切り出して解決。見た目は正しいのに動かない、再現性100%のバグで、デバッグに時間を取られました。
ステップ4: テンプレートベースの監視 #
デバイスレジストリ #
分類結果はJSONファイル(デバイスレジストリ)に蓄積されます。
{
"devices": [
{
"hostname": "CLIENT-001",
"category": "win_client",
"template": "win_client.sh",
"confidence": "high",
"os_detail": "Windows 10/11 desktop",
"active": true
},
...
],
"exclude_hosts": ["既存サーバー1", "既存FW", ...],
"last_scan": "2026-04-21T06:00:00+09:00"
}監視テンプレート #
各カテゴリに対応するテンプレートスクリプトを用意しています。テンプレートは2つの関数を提供します。
# templates/win_client.sh
# 要約出力(summarize.shから呼ばれる)
template_summarize_win_client() {
# 認証異常、PowerShell、USB、アカウント変更のカウント
}
# 詳細分析(analyze-detail.shから呼ばれる)
template_detail_win_client() {
# ログイン失敗の端末別内訳、特権ログオン詳細、LOLBin検知...
}既存のsummarize.sh(定期分析スクリプト)の末尾に、デバイスレジストリを読んでテンプレートを動的に呼び出すブロックを追記しています。
# summarize.sh 末尾に追記
jq -r '.devices[] | select(.active==true) | ...' device-registry.json \
| while read HOST CATEGORY TEMPLATE; do
source "templates/${TEMPLATE}"
template_summarize_${CATEGORY} "$HOST" ...
done既存のハードコード部分には一切触れず、追記だけで拡張しています。
ステップ5: 全自動の結果 #
初回スキャンで14台のWindowsクライアントを自動検出しました。LLMが各端末のログサンプルを読み、「Security-Auditingログにログオンイベントがある→Windowsクライアント」と判定。win_clientテンプレートが自動適用され、認証異常・PowerShell実行・USB接続・アカウント変更の4カテゴリの監視が即座に開始されました。
LLM分類の精度 #
14台中、13台がconfidence: highで正しく分類されました。1台だけconfidence: highで「win_server」と判定されましたが、実際にはWindowsクライアントでした。ホスト名にサーバーを連想させる文字列が含まれていたことが原因と推定されます。
win_clientとwin_serverで監視テンプレートは共通にしてあるため、実害はありません。ただし、カテゴリの正確性が重要な場合は、デバイスレジストリのcategoryフィールドを手動で修正するオーバーライド機能を検討中です。
既存の監視との共存 #
BASTIONでは既にファイアウォール・認証基盤・ロードバランサー・スイッチ・Webサーバーの分析処理をsummarize.shにハードコードしています。自動分類の対象はこれらの既存機器を除外した残りです。
既に動いているものを壊すリスクは取りません。将来的には既存のハードコード部分もテンプレート化して統合可能ですが、現時点では「既存機器=ハードコード」「新規機器=テンプレート自動適用」の二層構成です。
今後の拡張 #
現在はwin_clientテンプレートと汎用(unknown)テンプレートの2種類ですが、顧客導入のたびにテンプレートが増えていきます。
| テンプレート | 状態 | 主な監視項目 |
|---|---|---|
| win_client / win_server | 実装済み | 認証異常、PowerShell、USB、アカウント変更 |
| generic(unknown用) | 実装済み | error/warning/criticalのカウント |
| linux | 計画中 | SSH認証、sudo実行、systemdサービス、OOM |
| firewall | 計画中 | ブロック数、攻撃元IP、ポート分布、VPN |
| switch | 計画中 | リンクダウン、STP変更、ループ、ストーム |
テンプレートのライブラリが増えるほど「syslogを向けるだけ」で対応できる機器の範囲が広がり、これがそのまま蓄積型の競争優位になります。
まとめ #
BASTIONの自動機器分類は、rsyslogのディレクトリ自動生成 → ホスト検出 → LLMログ分類 → テンプレート自動適用 → 監視開始を全自動で行います。syslogの宛先を設定するだけで、機器の種別判定も監視ルールの選択も端末の増減管理も自動化されます。
従来の監視導入における最大のボトルネック「機器ごとの登録・設定」を構造的に消す仕組みです。10台でも100台でも、人間の作業は同じ(syslog宛先の1行設定のみ)。「知らないうちに監視対象外の機器が増えていた」という問題が構造的に発生しません。
BASTIONは閉域環境でAIセキュリティ監視を実現するサービスです。
