Elastic Securityで始める検知エンジニアリング — 環境構築とログの取り込み(第1回)

BLOG

これから5回に分けて、Elastic Securityを使ったセキュリティ監視の基礎を、手を動かしながら学んでいきます。第1回はデータの取り込みと、Discover・Securityの両方で見えるようにするまでの環境構築です。

今後の予定

本シリーズでは、以下の流れでステップアップしていきます。

  • 第2回:KQLでログを読み、最初の検知ルールを作る
  • 第3回:Timelineで攻撃の全体像を追う
  • 第4回:EQL / ES|QLで攻撃を自動検出・集計する
  • 第5回:ノイズを減らし、運用できるルールにする

本ブログでは、ローカル環境に構築した Elastic Stack v9.3 を使用して、実際に手を動かしながら検証・解説を行っています。

Elastic Stack はオープンソースとして利用可能であり、クラウド版(Elastic Cloud)も無料トライアルで試すことができます。


この記事を読むと何ができるか

  • サンプルデータ82件をElasticsearchに正しく取り込める
  • Discoverでイベントを確認できる
  • Elastic Securityの画面でも同じデータが見える状態になる

まず覚えておく5つの用語

このシリーズ全体で繰り返し登場します。最初に整理しておきます。

  • イベント:1件のログです。「ログイン成功」「プロセス起動」「外部への通信」など、「何かが起きた記録」です。このガイドでは 82件のイベントを使います。
  • ルール:イベントを条件で監視し、怪しいものを自動で見つけるための設定です。「ログイン失敗が起きたら知らせる」という定義がルールです。
  • アラート:ルールの条件に一致した結果です。イベントは「原材料」、アラートは「調査が必要かもしれない、という通知」です。アラートが出たからといって、必ずしもインシデントではありません。
  • Timeline:複数のイベントを時系列で並べながら、攻撃の流れを追う調査画面です。第3章で詳しく使います。
  • Case:調査メモ、担当者のアサイン、証拠をひとまとめにする入れ物です。チームで調査内容を共有するために使います。

演習データについて

今回使うサンプルデータ security_sample_v2.ndjson の概要です。

項目
形式NDJSON(1行1イベント)
件数82件
時間範囲2025-03-18 09:45:00 〜 10:30:00(UTC)
取り込み先インデックス名training-security-logs

このデータはElastic Securityの学習用に設計されたサンプルです。完全な本番用ECSデータではありませんが、Discover・検知ルール・Timelineの練習には十分使えます。

ECS(Elastic Common Schema)とは 異なるログソース間でフィールド名を統一するための共通ルールです。WindowsイベントログでもLinux syslogでも、「ログイン失敗」は event.outcome: "failure" と書く、という約束事です。この共通化によって、複数製品のログを横断して検索・分析できるようになります。


Step 1:ファイルをアップロードする

KibanaのIntegrationメニューから「Upload file」を開きます。画面遷移はバージョン差が出ることがあるので、迷ったら Global Search で検索して開いてください。

またはKibanaのホーム画面から「Upload a file」を選んでもかまいません。

security_sample_v2.ndjson を画面にドラッグ&ドロップします。Kibanaがファイルを自動解析します(数秒かかります)。

インデックス名をlogs-training-securityに指定します。


Step 2:インデックス名を確認する

「Advanced options」を展開し、「Create data view」にチェックが入っていることを確認します。このチェックが入っていると、取り込みと同時にDiscover用のデータビューが自動で作成されます。

training-security-logs

⚠️ このインデックス名は正確に入力してください 第2回以降の手順でこの名前を前提にしています。別の名前で取り込むと、後の手順がすべて動作しません。


Step 3:マッピングを設定する

「Mappings」欄に次のJSONを入力します。マッピングとは「このフィールドを日付として扱う」「これをIPアドレスとして扱う」という型の定義です。省略すると集計や範囲検索が正しく動かなくなります。

{
  "properties": {
    "@timestamp":           { "type": "date" },
    "agent.type":           { "type": "keyword" },
    "ecs.version":          { "type": "keyword" },
    "event.kind":           { "type": "keyword" },
    "event.type":           { "type": "keyword" },
    "event.category":       { "type": "keyword" },
    "event.action":         { "type": "keyword" },
    "event.outcome":        { "type": "keyword" },
    "source.ip":            { "type": "ip" },
    "destination.ip":       { "type": "ip" },
    "destination.port":     { "type": "integer" },
    "network.bytes":        { "type": "long" },
    "network.transport":    { "type": "keyword" },
    "network.protocol":     { "type": "keyword" },
    "user.name":            { "type": "keyword" },
    "host.name":            { "type": "keyword" },
    "process.name":         { "type": "keyword" },
    "process.pid":          { "type": "integer" },
    "process.command_line": { "type": "wildcard" },
    "process.parent.name":  { "type": "keyword" },
    "dns.question.name":    { "type": "keyword" },
    "rule.name":            { "type": "keyword" }
  }
}

マッピングが重要な理由:

  • @timestampdate 型でないと、時間範囲で絞り込めない
  • network.byteslong 型でないと、合計・最大値の集計ができない
  • source.ipip 型でないと、CIDRなどのIP範囲検索が使えない

設定を確認したら「Import」をクリックします。「Import complete」と表示されれば成功です。


Step 4:Security画面でもデータを見えるようにする

Data Viewを作っただけでは、SecurityアプリはこのインデックスをElastic Securityが使うインデックス一覧に含みません。securitySolution:defaultIndex という設定にインデックス名を追加する必要があります。

Stack Management → Advanced Settings → securitySolution:defaultIndex

現在の値の末尾に training-security-logs を追加して「Save changes」をクリックし、ページをリロードします。

なぜこの設定が必要か Elastic Securityはデフォルトで logs-*metrics-* などの決まったパターンのインデックスしか見ません。training-security-logs はそのパターンに含まれないため、明示的に追加する必要があります。本番環境でも、カスタムインデックスを使う場合は同じ手順が必要になります。

⚠️ バージョンについての注意 securitySolution:defaultIndex の設定箇所はElasticのバージョンによって異なる場合があります。公式ドキュメントも合わせて確認してください。


Step 5:時間範囲の調整

このサンプルデータは 2025-03-18 のタイムスタンプを持っています。Kibanaのデフォルト表示は「直近15分」や「Today」なので、そのままではデータが空に見えることがあります。取り込み失敗ではなく、単に時間範囲が合っていないだけです。

方法操作
ざっくり確認したい画面右上の時間範囲ピッカーで「Last 2 years」を選択
正確に指定したい「Absolute」で開始 2025-03-18 09:45:00、終了 2025-03-18 10:30:00 を入力

UTC と日本時間(JST)のズレに注意 サンプルデータのタイムスタンプはUTCで記録されています。Kibanaの表示はブラウザのタイムゾーン(日本環境ではJST = UTC+9)で表示されるため、画面上では 18:45〜19:30 のように見えます。このシリーズでは時刻をUTCで記述します。画面上の表示が9時間ずれていても異常ではありません。


取り込みの確認

取り込みが完了したら、次の3つで正しく入ったか確認します。

確認1:件数確認

Dev Tools(Console)で実行します。

GET training-security-logs/_count

期待値:82

確認2:時間範囲確認

POST _query
{
  "query": """
    FROM training-security-logs
    | STATS
        total   = COUNT(*),
        earliest = MIN(@timestamp),
        latest   = MAX(@timestamp)
  """
}

期待値:

  • total = 82
  • earliest = 2025-03-18T09:45:00.000Z
  • latest = 2025-03-18T10:30:00.000Z

確認3:数値フィールドの型確認

POST _query
{
  "query": """
    FROM training-security-logs
    | WHERE network.bytes IS NOT NULL
    | STATS
        max_bytes = MAX(network.bytes),
        sum_bytes = SUM(network.bytes)
  """
}

期待値:max_bytes = 120000000(120MB)

この値が返ってくれば、network.bytes が数値型として正しく取り込まれています。文字列型で取り込まれていると、この集計はエラーになります。

確認4:データ種別確認

POST _query
{
  "query": """
  FROM training-security-logs
  | STATS count = COUNT(*) BY agent.type
  | SORT count DESC
  """
}

期待値:

  • winlogbeat = 53
  • packetbeat = 29

よくあるつまずきポイント

取り込んだはずなのにDiscoverに何も表示されない場合は、次を順番に確認してください。

  1. 時間範囲が「Last 15 minutes」になっていないか:「Last 2 years」に変更する
  2. Data Viewが training-security-logs になっているか:左上のドロップダウンで確認
  3. インデックス名にタイポがないかtraining-security-log(sなし)は別のインデックス

Discoverでは見えるのにSecurityでは見えない場合は、Step 4の securitySolution:defaultIndex の設定を再確認してください。


この章のまとめ

やったことなぜ必要か
インデックス名を training-security-logs に指定後の章の全手順がこの名前を前提にしているため
マッピングに型を明示時間検索・数値集計・IP検索を正しく動かすため
securitySolution:defaultIndex に追加Security画面でこのデータを使えるようにするため
時間範囲を調整2025-03-18の過去データを画面に表示するため

第1回チェックリスト

  • [ ] GET training-security-logs/_count82 を返す
  • [ ] Discoverで training-security-logs データビューを開き、イベントが見える
  • [ ] Security → Rules 画面を開いたときにエラーが出ていない

次回は: KQLでログの中身を読みながら、最初の検知ルールを正しい条件で作ります。event.outcome:"failure" だけでは何が起きるか、第2回で確認します。