ELK Stack(以下ELKと呼称)を導入し、Suricataによって生成されたログeve.json
の内容を可視化してみる。
今回はElastic Integrationsを活用する。Elastic Integrationsは多くの一般的なデータソースやアプリケーションに対応したダッシュボードやビジュアライゼーションコンポーネント(グラフなど)、インデックス設定をプリセットとして提供している。これにより、ログの可視化を簡単かつ迅速に実現できる。
今回、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クローン$ 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.ymlelasticsearch:build:...environment:node.name: elasticsearchES_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.htmldiscovery.type: single-nodexpack.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 psNAME IMAGE COMMAND SERVICE CREATED STATUS PORTSdocker-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/tcpdocker-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/tcpdocker-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
コンテナを起動し、しばらく待機(5分程度?)してからブラウザでhttp://localhost:5601にアクセスする。
以下のような「Welcome home」ページが表示されたらOK。
※ 設定によりダークモード適用済みの画像 (初回はライトモード)
以降の作業はSuricataが導入されたマシン(今回はRaspberryPi)にて行う。
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]:5601host: "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 listEnabled:suricataDisabled:activemqapacheauditdaws...
注意
本来であれば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 listEnabled:suricataDisabled:
モジュールを有効化したら、モジュールの設定ファイルにてeve.json
のパスを指定する。
$ vi modules.d/suricata.yml
modules.d/suricata.yml1# Module: suricata2# Docs: https://www.elastic.co/guide/en/beats/filebeat/main/filebeat-module-suricata.html34- module: suricata5# All logs6eve:7enabled: true # 変更89# Set custom paths for the log files. If left empty,10# Filebeat will choose the paths depending on your OS.11var.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への送信に成功していることとなる。
最後にダッシュボードを確認する。
Kibanaページに戻り、左上のハンバーガーメニューをクリックしてDashboard
を選択する。
続いて、検索バーに「suricata」と入力し、表示された[Filebeat Suricata] Events Overview
と[Filebeat Suricata] Alert Overview
を確認してみてデータが表示されていれば完了。
Eventsダッシュボード
Alertsダッシュボード
FilebeatやELKが正常に動作しているにも関わらず、ダッシュボードでデータを確認できない場合は、データの表示期間範囲を広げてみてほしい。
とくにSuricataを以前から稼働させている場合は、古いログかつ巨大なデータサイズになっている可能性があり、全期間の取得にはそれなりに時間がかかるかもしれない....
もちろん、FilebeatやELKが本当に正常動作しているかも確認すること。
Suricataログ、とくにeve.json
はすぐに膨大なデータサイズになり、ストレージを圧迫するため、ログローテーション設定は必須である。
今回はログローテーション設定にlogrotateを使用する。
ログローテーションを行う際には、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.service1[Unit]2Description=Suricata service3After=network-online.target45[Service]6Type=simple7WorkingDirectory=/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.pid10Restart=always1112[Install]13WantedBy=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 3dailydateextmissingoknocompressnotifemptycreatesharedscriptspostrotate/bin/kill -HUP `cat /var/run/suricata.pid 2>/dev/null` 2>/dev/null || trueendscript}/usr/local/var/log/suricata/*.log{rotate 3minsize 100Mdailydateextmissingoknocompressnotifemptycreatesharedscriptspostrotate/bin/kill -HUP `cat /var/run/suricata.pid 2>/dev/null` 2>/dev/null || trueendscript}
上記の例では、
*.json
(eve.json)については、ファイルサイズに関わらず1日1回ローテーションを実施し、最大4ファイルを残す(最新ファイル含む)。
*.log
(fast.log, suricata.log, stats.log)については、ファイルサイズが100MB以上であれば最大で1日1回ローテーションを実施し、最大4ファイルを残す(最新ファイル含む)。