10日で覚えるSplunkDay 10: 総合プロジェクト

Day 10: 総合プロジェクト

今日のゴール

これまで学んだすべてのSplunk技術を使って、セキュリティ監視ダッシュボードを構築します。


プロジェクト概要

項目 内容
ダッシュボード名 Security Operations Center (SOC)
機能 脅威検知、インシデント対応、コンプライアンスレポート
使用技術 SPL全般、ダッシュボード、アラート、ルックアップ、マクロ
flowchart TB
    subgraph SOC["SOC Dashboard"]
        KPI["KPIパネル<br>総イベント・アラート数"]
        Timeline["タイムライン<br>イベント推移"]
        Threat["脅威検知<br>異常パターン"]
        Detail["詳細分析<br>ドリルダウン"]
    end
    style KPI fill:#3b82f6,color:#fff
    style Timeline fill:#22c55e,color:#fff
    style Threat fill:#ef4444,color:#fff
    style Detail fill:#f59e0b,color:#fff

Step 1: サンプルデータの準備

セキュリティログの生成

以下のログを用意します。

firewall.log

2026-01-30 10:00:01 action=allowed src_ip=192.168.1.10 dst_ip=10.0.0.1 dst_port=443 proto=TCP bytes=2048
2026-01-30 10:00:02 action=blocked src_ip=10.10.10.5 dst_ip=192.168.1.100 dst_port=22 proto=TCP bytes=0
2026-01-30 10:00:03 action=allowed src_ip=192.168.1.20 dst_ip=172.16.0.5 dst_port=80 proto=TCP bytes=4096
2026-01-30 10:00:05 action=blocked src_ip=203.0.113.50 dst_ip=192.168.1.100 dst_port=3389 proto=TCP bytes=0
2026-01-30 10:00:10 action=allowed src_ip=192.168.1.30 dst_ip=10.0.0.2 dst_port=53 proto=UDP bytes=128

auth.log

2026-01-30 10:00:01 action=login_success user=alice src_ip=192.168.1.10 method=password
2026-01-30 10:00:05 action=login_failed user=admin src_ip=203.0.113.50 method=password
2026-01-30 10:00:06 action=login_failed user=admin src_ip=203.0.113.50 method=password
2026-01-30 10:00:07 action=login_failed user=admin src_ip=203.0.113.50 method=password
2026-01-30 10:00:10 action=login_success user=bob src_ip=192.168.1.20 method=ssh_key
2026-01-30 10:00:15 action=login_failed user=root src_ip=198.51.100.10 method=password
2026-01-30 10:00:20 action=privilege_escalation user=alice src_ip=192.168.1.10 target=root

web_access.log

192.168.1.10 - alice [30/Jan/2026:10:00:01 +0900] "GET /admin HTTP/1.1" 200 2048
203.0.113.50 - - [30/Jan/2026:10:00:05 +0900] "GET /../../../../etc/passwd HTTP/1.1" 403 128
192.168.1.20 - bob [30/Jan/2026:10:00:10 +0900] "GET /api/users HTTP/1.1" 200 4096
198.51.100.10 - - [30/Jan/2026:10:00:15 +0900] "POST /api/login HTTP/1.1" 401 64
10.10.10.5 - - [30/Jan/2026:10:00:20 +0900] "GET /wp-admin HTTP/1.1" 404 128

Step 2: ルックアップテーブル

threat_intel.csv(脅威インテリジェンス)

ip_address,threat_type,severity,description
203.0.113.50,brute_force,high,Known brute force attacker
198.51.100.10,scanner,medium,Network scanner
10.10.10.5,botnet,critical,Botnet C2 server

asset_inventory.csv(資産情報)

ip_address,hostname,department,criticality
192.168.1.10,ws-alice,Engineering,medium
192.168.1.20,ws-bob,Marketing,low
192.168.1.30,ws-charlie,Finance,high
192.168.1.100,srv-web01,IT,critical
10.0.0.1,srv-db01,IT,critical

Step 3: サーチマクロ

# macros.conf

# 脅威IPの検出
[threat_detected]
definition = lookup threat_intel ip_address AS src_ip OUTPUT threat_type, severity, description AS threat_description | where isnotnull(threat_type)

# セキュリティイベントの重要度分類
[severity_classification]
definition = eval alert_severity=case(severity="critical", 4, severity="high", 3, severity="medium", 2, severity="low", 1, 1=1, 0)

# 認証失敗の検出
[auth_failures(1)]
args = threshold
definition = index=security sourcetype=auth_log action=login_failed | stats count by src_ip, user | where count >= $threshold$

Step 4: アラートの定義

ブルートフォース検知

index=security sourcetype=auth_log action=login_failed
| bin _time span=5m
| stats count by src_ip, _time
| where count >= 5
| `threat_detected`

設定:

  • Schedule: */5 * * * *
  • Trigger: Number of Results > 0
  • Suppress: 30分、src_ipごと
  • Action: メール、Slack通知

不正アクセス試行

index=web sourcetype=access_combined
| rex field=uri "(?P<attack_pattern>(\.\./|etc/passwd|wp-admin|\.env|\.git))"
| where isnotnull(attack_pattern)
| stats count by clientip, attack_pattern

Step 5: SOCダッシュボード

<dashboard theme="dark">
  <label>Security Operations Center</label>
  <description>セキュリティ監視ダッシュボード</description>

  <fieldset submitButton="false">
    <input type="time" token="time">
      <default>
        <earliest>-24h@h</earliest>
        <latest>now</latest>
      </default>
    </input>
    <input type="dropdown" token="severity_filter">
      <label>Severity</label>
      <choice value="*">All</choice>
      <choice value="critical">Critical</choice>
      <choice value="high">High</choice>
      <choice value="medium">Medium</choice>
      <default>*</default>
    </input>
  </fieldset>

  <!-- KPI行 -->
  <row>
    <panel><title>Total Security Events</title>
      <single>
        <search>
          <query>index=security OR index=web | stats count</query>
          <earliest>$time.earliest$</earliest>
          <latest>$time.latest$</latest>
        </search>
        <option name="colorMode">block</option>
        <option name="rangeColors">["0x22c55e","0xf59e0b","0xef4444"]</option>
        <option name="rangeValues">[1000,5000]</option>
        <option name="useColors">true</option>
      </single>
    </panel>
    <panel><title>Threat Detections</title>
      <single>
        <search>
          <query>
            index=security OR index=web
            | `threat_detected`
            | stats dc(src_ip) AS threat_count
          </query>
          <earliest>$time.earliest$</earliest>
          <latest>$time.latest$</latest>
        </search>
        <option name="colorMode">block</option>
        <option name="rangeColors">["0x22c55e","0xef4444"]</option>
        <option name="rangeValues">[0]</option>
        <option name="useColors">true</option>
      </single>
    </panel>
    <panel><title>Failed Logins</title>
      <single>
        <search>
          <query>index=security sourcetype=auth_log action=login_failed | stats count</query>
          <earliest>$time.earliest$</earliest>
          <latest>$time.latest$</latest>
        </search>
      </single>
    </panel>
    <panel><title>Blocked Connections</title>
      <single>
        <search>
          <query>index=security sourcetype=firewall action=blocked | stats count</query>
          <earliest>$time.earliest$</earliest>
          <latest>$time.latest$</latest>
        </search>
      </single>
    </panel>
  </row>

  <!-- タイムライン -->
  <row>
    <panel><title>Security Events Timeline</title>
      <chart>
        <search>
          <query>
            index=security OR index=web
            | eval event_type=case(
                action="blocked", "Firewall Block",
                action="login_failed", "Auth Failure",
                status>=400, "Web Error",
                1=1, "Other"
            )
            | timechart span=1h count by event_type
          </query>
          <earliest>$time.earliest$</earliest>
          <latest>$time.latest$</latest>
        </search>
        <option name="charting.chart">area</option>
        <option name="charting.chart.stackMode">stacked</option>
        <option name="charting.legend.placement">bottom</option>
      </chart>
    </panel>
  </row>

  <!-- 脅威分析 -->
  <row>
    <panel><title>Threat Intelligence Matches</title>
      <table>
        <search>
          <query>
            index=security OR index=web
            | `threat_detected`
            | stats count, values(action) AS actions, latest(_time) AS last_seen by src_ip, threat_type, severity
            | eval last_seen=strftime(last_seen, "%Y-%m-%d %H:%M:%S")
            | sort -count
          </query>
          <earliest>$time.earliest$</earliest>
          <latest>$time.latest$</latest>
        </search>
        <option name="drilldown">row</option>
        <drilldown>
          <link target="_blank">/app/search/search?q=index%3Dsecurity%20src_ip%3D$row.src_ip$</link>
        </drilldown>
      </table>
    </panel>
    <panel><title>Top Blocked IPs</title>
      <chart>
        <search>
          <query>
            index=security sourcetype=firewall action=blocked
            | stats count by src_ip
            | sort -count
            | head 10
          </query>
          <earliest>$time.earliest$</earliest>
          <latest>$time.latest$</latest>
        </search>
        <option name="charting.chart">bar</option>
      </chart>
    </panel>
  </row>

  <!-- 認証分析 -->
  <row>
    <panel><title>Authentication Failures by User</title>
      <chart>
        <search>
          <query>
            index=security sourcetype=auth_log action=login_failed
            | stats count by user
            | sort -count
          </query>
          <earliest>$time.earliest$</earliest>
          <latest>$time.latest$</latest>
        </search>
        <option name="charting.chart">pie</option>
      </chart>
    </panel>
    <panel><title>Recent Security Events</title>
      <table>
        <search>
          <query>
            index=security
            | eval severity=case(
                action="privilege_escalation", "critical",
                action="login_failed", "warning",
                action="blocked", "info",
                1=1, "low"
            )
            | table _time, sourcetype, action, user, src_ip, severity
            | sort -_time
            | head 20
          </query>
          <earliest>$time.earliest$</earliest>
          <latest>$time.latest$</latest>
        </search>
      </table>
    </panel>
  </row>
</dashboard>

10日間の振り返り

flowchart TB
    D1["Day 1<br>Splunkの基礎<br>アーキテクチャ"]
    D2["Day 2<br>データ取り込み<br>inputs.conf"]
    D3["Day 3<br>サーチの基本<br>SPL入門"]
    D4["Day 4<br>フィールドと<br>フィルタリング"]
    D5["Day 5<br>統計と集計<br>stats/timechart"]
    D6["Day 6<br>データの可視化<br>ダッシュボード"]
    D7["Day 7<br>サーチの応用<br>lookup/join"]
    D8["Day 8<br>アラートと<br>レポート"]
    D9["Day 9<br>Splunkの管理<br>ロール/アプリ"]
    D10["Day 10<br>総合プロジェクト"]
    D1 --> D2 --> D3 --> D4 --> D5
    D5 --> D6 --> D7 --> D8 --> D9 --> D10
    style D1 fill:#3b82f6,color:#fff
    style D2 fill:#3b82f6,color:#fff
    style D3 fill:#22c55e,color:#fff
    style D4 fill:#22c55e,color:#fff
    style D5 fill:#22c55e,color:#fff
    style D6 fill:#f59e0b,color:#fff
    style D7 fill:#f59e0b,color:#fff
    style D8 fill:#8b5cf6,color:#fff
    style D9 fill:#8b5cf6,color:#fff
    style D10 fill:#ef4444,color:#fff
Day トピック 習得したスキル
1 Splunkの世界へようこそ アーキテクチャ、インストール、Web UI
2 データの取り込み monitor, HEC, sourcetype, indexes
3 サーチの基本 SPL構文、キーワード/フィールド検索、パイプ
4 フィールドとフィルタリング eval, where, rex
5 統計と集計 stats, chart, timechart, top, eventstats
6 データの可視化 ダッシュボード、Simple XML、ドリルダウン
7 サーチの応用 サブサーチ、lookup, join, transaction
8 アラートとレポート スケジュールサーチ、アラート、マクロ
9 Splunkの管理 ロール、インデックス管理、ナレッジオブジェクト
10 総合プロジェクト SOCダッシュボード構築

次のステップ

Splunkの基礎を習得しました。次に学ぶべきトピックを紹介します。

トピック 説明
Splunk Enterprise Security (ES) SIEM機能の活用
Splunk SOAR セキュリティオーケストレーション
SPL2 次世代のサーチ言語
データモデルとCIM Common Information Model
Splunk Cloud クラウド版の活用
Splunk認定資格 Splunk Core Certified User / Power User

Splunk認定資格

資格 レベル 対象
Splunk Core Certified User 基礎 SPLの基本操作
Splunk Core Certified Power User 中級 高度なSPL、ダッシュボード
Splunk Core Certified Advanced Power User 上級 データモデル、最適化
Splunk Enterprise Certified Admin 管理 インフラ管理、設定

練習問題

問題1: 機能追加

地理情報(iplocationコマンド)を使って、攻撃元の国をマップ上に表示するパネルを追加してください。

問題2: 応用

eventstatsを使って、各IPの通常のアクセス頻度を計算し、異常なアクセス数(平均の3倍以上)を検知するクエリを作成してください。

チャレンジ問題

完全なSplunkアプリとして、このSOCダッシュボードをパッケージ化してください。app.conf、ナビゲーション、ダッシュボード、ルックアップ、マクロ、保存済みサーチ(アラート)を含めましょう。


参考リンク


おめでとうございます! 10日間でSplunkの基礎をマスターしました。ここで学んだ知識は、セキュリティ運用、IT監視、データ分析など、あらゆるSplunk活用の土台になります。