Suricata with Raspberry Piで遊ぼう!【ELK編(Elastic Integrations)】

概要

ELK Stack(以下ELKと呼称)を導入し、Suricataによって生成されたログeve.jsonの内容を可視化してみる。

今回はElastic Integrationsを活用する。Elastic Integrationsは多くの一般的なデータソースやアプリケーションに対応したダッシュボードやビジュアライゼーションコンポーネント(グラフなど)、インデックス設定をプリセットとして提供している。これにより、ログの可視化を簡単かつ迅速に実現できる。

前提

  • ELK動作環境
    • OS: CentOS 9 Stream / vCPU: 4 / メモリ: 8GB
    • Docker v25.0.3
    • docker compose v2.25.5
    • Elasticsearch/Logstash/Kibana v8.11.4
      • docker-elk環境
  • Suricata動作環境
    • Raspberry Pi 4 Model [RAM 4GB, Raspberry Pi OS Lite (64-bit)]
    • Suricata v6.0.13
    • Filebeat v8.12.1

作業

ELK環境構築

Dockerインストール

今回、ELK環境構築にはdocker-elkを使用するため、はじめにDockerをインストールしていく。

$ sudo hostnamectl set-hostname ELK-analysis
$ logout # ホスト名反映のために一度再ログイン
$ sudo dnf update -y
$ sudo dnf install -y git
# Dockerインストール
$ sudo dnf config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo
$ sudo dnf install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
# 権限設定、Docker起動
$ sudo chmod 666 /var/run/docker.sock
$ sudo systemctl enable docker
$ sudo systemctl start docker

docker-elkの導入

# docker-elkクローン
$ git clone https://github.com/deviantony/docker-elk.git
$ cd docker-elk

Elasticsearch 8.xではデフォルトでX-Pack Securityが有効化されている
本環境では外部に公開せず、宅内ネットワーク上で完結するため、簡単のためにX-Pack Securityを無効化する。
また、ElasticsearchとLogstashのメモリサイズも変更しておく。
設定変更にはdocker-compose.ymlを編集する。

$ vi docker-compose.yml
docker-compose.yml
elasticsearch:
build:
...
environment:
node.name: elasticsearch
ES_JAVA_OPTS: -Xms2g -Xmx4g # 任意のメモリサイズに変更
# Bootstrap password.
# Used to initialize the keystore during the initial startup of
# Elasticsearch. Ignored on subsequent runs.
ELASTIC_PASSWORD: ${ELASTIC_PASSWORD:-}
# Use single node discovery in order to disable production mode and avoid bootstrap checks.
# see: https://www.elastic.co/guide/en/elasticsearch/reference/current/bootstrap-checks.html
discovery.type: single-node
xpack.security.enabled: false # 追記
xpack.security.enrollment.enabled: false # 追記
...
logstash:
build:
...
environment:
LS_JAVA_OPTS: -Xms2g -Xmx4g # 任意のメモリサイズに変更
LOGSTASH_INTERNAL_PASSWORD: ${LOGSTASH_INTERNAL_PASSWORD:-}

編集が完了したらコンテナをビルド&起動する。

$ docker compose up -d
$ docker compose ps
NAME IMAGE COMMAND SERVICE CREATED STATUS PORTS
docker-elk-elasticsearch-1 docker-elk-elasticsearch "/bin/tini -- /usr/l…" elasticsearch 49 seconds ago Up 45 seconds 0.0.0.0:9200->9200/tcp, :::9200->9200/tcp, 0.0.0.0:9300->9300/tcp, :::9300->9300/tcp
docker-elk-kibana-1 docker-elk-kibana "/bin/tini -- /usr/l…" kibana 47 seconds ago Up 44 seconds 0.0.0.0:5601->5601/tcp, :::5601->5601/tcp
docker-elk-logstash-1 docker-elk-logstash "/usr/local/bin/dock…" logstash 47 seconds ago Up 44 seconds 0.0.0.0:5044->5044/tcp, :::5044->5044/tcp, 0.0.0.0:9600->9600/tcp, :::9600->9600/tcp, 0.0.0.0:50000->50000/tcp, :::50000->50000/tcp, 0.0.0.0:50000->50000/udp, :::50000->50000/udp

ELK動作確認

コンテナを起動し、しばらく待機(5分程度?)してからブラウザでhttp://localhost:5601にアクセスする。
以下のような「Welcome home」ページが表示されたらOK。
elk_top
※ 設定によりダークモード適用済みの画像 (初回はライトモード)

Suricataログ送信

以降の作業はSuricataが導入されたマシン(今回はRaspberryPi)にて行う。

Filebeat導入

Suricataログの送信にはFilebeatを使用する。
FilebeatはElasticsearchにログを送信するための軽量なデータ転送エージェントである。

Filebeat導入にあたって、基本的にはhttp://localhost:5601/app/home#/tutorial/suricataLogsにある手順に沿って進めればよい。
しかし、RaspberryPiの場合はアーキテクチャがarm64なので、異なるアーキテクチャのFilebeatパッケージをダウンロードしないように注意すること。

# Filebeatインストール
$ curl -L -O https://artifacts.elastic.co/downloads/beats/filebeat/filebeat-8.11.4-arm64.deb
$ sudo dpkg -i filebeat-8.11.4-arm64.deb

インストールが完了したら、filebeat.ymlにてKibanaとElasticsearchの接続設定を行う。

$ sudo vi /etc/filebeat/filebeat.yml
filebeat.yml
...
setup.kibana:
# Kibana Host
# Scheme and port can be left out and will be set to the default (http and 5601)
# In case you specify and additional path, the scheme is required: http://localhost:5601/path
# IPv6 addresses should always be defined as: https://[2001:db8::1]:5601
host: "192.168.120.4:5601" # KibanaのIPアドレス/ポートを指定
...
output.elasticsearch:
# Array of hosts to connect to.
hosts: ["192.168.120.4:9200"] # ElasticsearchのIPアドレス/ポートを指定
...

モジュールの有効化

続いて、Filebeatに同梱されたSuricataモジュールを有効化する。

$ sudo filebeat modules enable suricata
$ sudo filebeat modules list
Enabled:
suricata
Disabled:
activemq
apache
auditd
aws
...

注意
本来であればFilebeatセットアップ時、無効化された(Disabled)モジュールについては取り込まれないはず(多分)が、
なぜか無効化されたモジュールも取り込まれ、一部モジュールの設定ファイルで文法エラー(?)が発生しているようで、正常にセットアップが完了しない問題が発生した。

参考: エラーメッセージ(抜粋)

{"log.level":"error","@timestamp":"2024-02-23T04:10:33.739+0900","log.origin":{"function":"github.com/elastic/beats/v7/libbeat/cfgfile.(*Reloader).Load","file.name":"cfgfile/reload.go","file.line":255},"message":"Error loading configuration files: 1 error: Unable to hash given config: missing field accessing '0.vpcflow' (source:'/etc/filebeat/modules.d/gcp.yml.disabled')","service.name":"filebeat","ecs.version":"1.6.0"}

すべてのFilebeatモジュールの設定ファイルは/etc/filebeat/modules.dに存在し、そのディレクトリ内にある*.ymlを取り込むようになっているはずなのだが...(無効化されたモジュールの設定ファイルは*.yml.disabled)
そして、同梱されているモジュールの設定ファイルに素の状態で誤りがあるというのも奇妙である...

謎ではあるがそれはさて置き、面倒だったので雑な対応ではあるが、無効化されたモジュールの設定ファイル(*.yml.disabled)をmodules.dから別のディレクトリに退避させてからセットアップを行った。これにより問題は解消された。

$ cd /etc/filebeat
$ sudo mkdir disabled_modules
$ sudo mv modules.d/*.disabled disabled_modules/
$ sudo filebeat modules list
Enabled:
suricata
Disabled:

モジュールを有効化したら、モジュールの設定ファイルにてeve.jsonのパスを指定する。

$ vi modules.d/suricata.yml
modules.d/suricata.yml
1
# Module: suricata
2
# Docs: https://www.elastic.co/guide/en/beats/filebeat/main/filebeat-module-suricata.html
3
4
- module: suricata
5
# All logs
6
eve:
7
enabled: true # 変更
8
9
# Set custom paths for the log files. If left empty,
10
# Filebeat will choose the paths depending on your OS.
11
var.paths: ["/usr/local/var/log/suricata/eve.json"] # 追記

設定も完了したら、Filebeatセットアップの実行とFilebeatを起動する。

$ sudo filebeat setup
$ sudo systemctl enable filebeat
$ sudo systemctl start filebeat

Filebeat起動から少し待って、http://localhost:5601/app/home#/tutorial/suricataLogsの「Module status」内の「Check data」をクリックする。
その後、以下のように表示されれば、Filebeatがログファイルを読込んでElasticsearchへの送信に成功していることとなる。
filebeat_suricata_check

ダッシュボードの確認

最後にダッシュボードを確認する。

Kibanaページに戻り、左上のハンバーガーメニューをクリックしてDashboardを選択する。
続いて、検索バーに「suricata」と入力し、表示された[Filebeat Suricata] Events Overview[Filebeat Suricata] Alert Overviewを確認してみてデータが表示されていれば完了。
dashboard_search

  • Eventsダッシュボード
    suricata_events_dashboard

  • Alertsダッシュボード
    suricata_alerts_dashboard

表示されない?

FilebeatやELKが正常に動作しているにも関わらず、ダッシュボードでデータを確認できない場合は、データの表示期間範囲を広げてみてほしい。
とくにSuricataを以前から稼働させている場合は、古いログかつ巨大なデータサイズになっている可能性があり、全期間の取得にはそれなりに時間がかかるかもしれない....
もちろん、FilebeatやELKが本当に正常動作しているかも確認すること。

参考

Appendix

Appendix 1. Suricataログローテーション設定

Suricataログ、とくにeve.jsonはすぐに膨大なデータサイズになり、ストレージを圧迫するため、ログローテーション設定は必須である。
今回はログローテーション設定にlogrotateを使用する。

Suricata PIDファイル作成

ログローテーションを行う際には、PIDファイルが必要とされる。
PIDファイルは、--pidfile {pidファイルパス}をコマンドに含めることで作成される。
(参考: 17.6. Log Rotation — Suricata 8.0.0-dev documentation)

systemdユニットファイルのExecStartで、以下のようにオプションを追記する。

$ sudo systemctl stop suricata
$ sudo vi /etc/systemd/system/suricata.service
suricata.service
1
[Unit]
2
Description=Suricata service
3
After=network-online.target
4
5
[Service]
6
Type=simple
7
WorkingDirectory=/usr/local/bin
-
ExecStart=/usr/local/bin/suricata -c /usr/local/etc/suricata/suricata.yaml -i eth0 -i eth2
+
ExecStart=/usr/local/bin/suricata -c /usr/local/etc/suricata/suricata.yaml -i eth0 -i eth2 --pidfile /var/run/suricata.pid
10
Restart=always
11
12
[Install]
13
WantedBy=multi-user.target

追記が完了したら、daemon-reloadの実行とSuricataを起動する。

$ sudo systemctl daemon-reload
$ sudo systemctl restart suricata

ログローテーション設定

/etc/logrotate.d配下にファイルを作成し、ログローテーションの設定内容を記述する。

$ sudo vi /etc/logrotate.d/suricata

例:

suricata
/usr/local/var/log/suricata/*.json
{
rotate 3
daily
dateext
missingok
nocompress
notifempty
create
sharedscripts
postrotate
/bin/kill -HUP `cat /var/run/suricata.pid 2>/dev/null` 2>/dev/null || true
endscript
}
/usr/local/var/log/suricata/*.log
{
rotate 3
minsize 100M
daily
dateext
missingok
nocompress
notifempty
create
sharedscripts
postrotate
/bin/kill -HUP `cat /var/run/suricata.pid 2>/dev/null` 2>/dev/null || true
endscript
}

上記の例では、
*.json(eve.json)については、ファイルサイズに関わらず1日1回ローテーションを実施し、最大4ファイルを残す(最新ファイル含む)。
*.log(fast.log, suricata.log, stats.log)については、ファイルサイズが100MB以上であれば最大で1日1回ローテーションを実施し、最大4ファイルを残す(最新ファイル含む)。