ログ収集分析基盤 Rsyslog + Elasticsearch + Kibana (Rsyslog構築)

はじめに

以前なんちゃってセキュリティレポートを書いた.

heavymoon.hateblo.jp

これは ddwrt のログを使っているのだけれど,手動で分析するのは面倒なので,昨今流行りの(?) Elasticsearch を使ってみようと思う.

heavymoon.hateblo.jp

構成としては表題の通り,Rsyslog でログ収集して,Elasticsearch に蓄積して,Kibana で可視化する.

最初は Fluentd を使おうと思って適当に設定してみたものの, あまり直感的じゃないし,絶賛発展途上中という印象を受けたのでやめた.

Logstash を使えばいいじゃないかという気もするが, OS標準っぽい Rsyslog を使ってみたくなったのでこれを使う.

長そうなので今回は Rsyslog の構築部分について書く.

公式ドキュメントももちろん参照するべきだが,以下さくらのナレッジも非常に参考になるので Rsyslog なにそれな人は一読するといい.

knowledge.sakura.ad.jp

knowledge.sakura.ad.jp

ちなみに OS は例のごとく CentOS7 を使う.

$ cat /etc/centos-release
CentOS Linux release 7.7.1908 (Core)

Rsyslog について

www.rsyslog.com

Rsyslog は様々な形式のログの収集と配信ができる. Logstash 風に言うとデータ処理パイプラインである.

公式の説明では以下の特徴がある.

  • Multi-threading
  • TCP, SSL, TLS, RELP
  • MySQL, PostgreSQL, Oracle and more
  • Filter any part of syslog message
  • Fully configurable output format
  • Suitable for enterprise-class relay chains

つまり,いろいろできると.

今回 Rsyslog でやりたいのは dd-wrt のログを Elasticsearch に入れることなので,Rsyslog の機能で十分に実現できそう.

https://www.rsyslog.com/common/images/rsyslog-features-imagemap.png

Rsyslog 構築

インストール

$ rsyslogd -v
rsyslogd 8.24.0-41.el7_7.2, compiled with:
    PLATFORM:               x86_64-redhat-linux-gnu
    PLATFORM (lsb_release -d):      
    FEATURE_REGEXP:             Yes
    GSSAPI Kerberos 5 support:      Yes
    FEATURE_DEBUG (debug build, slow code): No
    32bit Atomic operations supported:  Yes
    64bit Atomic operations supported:  Yes
    memory allocator:           system default
    Runtime Instrumentation (slow code):    No
    uuid support:               Yes
    Number of Bits in RainerScript integers: 64

See http://www.rsyslog.com for more information.

デフォルトの Rsyslog は古すぎて使い物にならないので最新にする必要がある.

公式の手順 1 に従い最新の安定版とその他必要な物をインストールする.

# cd /etc/yum.repos.d/
# wget http://rpms.adiscon.com/v8-stable/rsyslog.repo
# yum install rsyslog rsyslog-elasticsearch liblognorm liblognorm5-utils
  • rsyslog
    • Rsyslog 本体
  • rsyslog-elasticsearch
    • Elasticsearch 用モジュール
  • liblognorm
    • メッセージを正規化するモジュール 2
  • liblognorm5-utils
    • メッセージの正規化ルールを作成するときのコマンドラインツール
    • あとで出てくるlognormalizerコマンドで使う

設定

今回設定する必要があるのは以下3つ.

/etc/rsyslog.conf           # Rsyslog全体の設定
/etc/rsyslog.d/
├ ddwrt.rulebase             # 個別設定のメッセージ正規化ルール
└ ddwrt.conf                 # 個別設定

rsyslog.conf

デフォルトでは以下のようにな設定になっていた. 適当に整形して,今回関係ある部分だけコメントをつけた.

$ cat /etc/rsyslog.conf
# モジュール読み込み
$ModLoad imuxsock # provides support for local system logging (e.g. via logger command)
$ModLoad imjournal # provides access to the systemd journal

$WorkDirectory /var/lib/rsyslog
$ActionFileDefaultTemplate RSYSLOG_TraditionalFileFormat        # デフォルトの出力フォーマット指定
$IncludeConfig /etc/rsyslog.d/*.conf                            # 個別設定読み込み
$OmitLocalLogging on
$IMJournalStateFile imjournal.state

# ファシリティとプライオリティ毎に出力先変更
*.info;mail.none;authpriv.none;cron.none                /var/log/messages
authpriv.*                                              /var/log/secure
mail.*                                                  -/var/log/maillog
cron.*                                                  /var/log/cron
*.emerg                                                 :omusrmsg:*
uucp,news.crit                                          /var/log/spooler
local7.*                                                /var/log/boot.log

ややこしいことに Rsyslog の設定ファイルのフォーマットは3種類ある3. obsolete legacy は廃止されたファーマットなので使わないほうがいい. 単純な設定には basic,複雑な設定には advanced を使うといいが, 設定サンプルを参考に設定を書いていけば問題ないので,最初のうちはフォーマットは気にしなくてもいい.

  • basic
  • advanced
  • obsolete legacy

とか言いながら,デフォルトからフォーマットをがらっと変更して適当に設定した. 入力はとりあえず syslog 標準の 514/udp に設定.

$ cat /etc/rsyslog.conf
#############################
# GLOBAL DIRECTIVES
##############################
global(workDirectory="/var/lib/rsyslog")


##############################
# MODULES
##############################
module(
    load="imuxsock"
    SysSock.Use="on"
    SysSock.Name="/run/systemd/journal/syslog"
)
module(
    load="imjournal"
    StateFile="imjournal.state"
)
module(load="imudp")
module(load="mmnormalize")              # 正規化モジュール
module(load="omelasticsearch")          # Elasticsearchモジュール


##############################
# RULES
##############################
## INPUT
input(type="imudp" port="514" ruleset="ddwrt")  # 入力ポート

## USER CUSTOMIZED
include(file="/etc/rsyslog.d/*.conf")

## DEFAULTS
*.info;mail.none;authpriv.none;cron.none    /var/log/messages
authpriv.*                                  /var/log/secure
mail.*                                      -/var/log/maillog
cron.*                                      /var/log/cron
*.emerg                                     :omusrmsg:*
uucp,news.crit                              /var/log/spooler
local7.*                                    /var/log/boot.log


##############################
# forwarding rule
##############################

ddwrt.conf

個別の設定についてはあまり需要ないと思うので, 設定する上で知っておくべきポイントだけ書いておく.

ここで設定する必要があるのは以下の通り.

  1. Elasticsearch へ出力するためのテンプレートの設定する
  2. mmnormalize モジュールを使ってメッセージを正規化する
  3. omelasticsearch モジュールを使って Elasticsearch へ出力する

設定のイメージはこんな感じ.

$ cat ddwrt.conf
# TEMPLATE
template(name="elast_insert"
         type="list"
         option.json="on") {
            constant(value="{")
            constant(value="\"timereported\":\"")           property(name="timereported" dateFormat="rfc3339")  constant(value="\",")
            constant(value="\"hostname\":\"")               property(name="hostname")                           constant(value="\",")
            constant(value="\"syslogfacility-text\":\"")    property(name="syslogfacility-text")                constant(value="\",")
            constant(value="\"syslogpriority-text\":\"")    property(name="syslogpriority-text")                constant(value="\",")
            constant(value="\"syslogtag\":\"")              property(name="syslogtag")                          constant(value="\",")
            constant(value="\"ab\":\"")                     property(name="$!ab")                               constant(value="\",")
            constant(value="\"cd\":\"")                     property(name="$!cd")                               constant(value="\"")
            constant(value="}\n")
        }

template(name="debug"
         type="string"
         string="TMP: %msg%\n"
         #string="TMP: %rawmsg%\n"
)

ruleset(name="ddwrt"){
    # NORMALIZE
    action(type="mmnormalize" ruleBase="/etc/rsyslog.d/ddwrt.rulebase")
    #action(type="mmnormalize" ruleBase="/etc/rsyslog.d/ddwrt.rulebase" useRawMsg="on")

    # OUTPUT
    #action(type="omfile" dirCreateMode="0700" FileCreateMode="0644" File="/tmp/debug.log"      Template="elast_insert")
    #action(type="omfile" dirCreateMode="0700" FileCreateMode="0644" File="/tmp/debug_json.log" Template="debug")
    action(type="omelasticsearch"
           server="localhost:9200"
           template="elast_ins_tcp"
           dynSearchIndex="on"
           bulkmode="on"
           queue.type="linkedlist"
           queue.size="5000"
           queue.dequeuebatchsize="300"
           action.resumeretrycount="-1")
    & stop
}

Rsyslog では Message Properties 4 といって,メッセージなどの情報を保持する変数があり, 定義済みのプロパティもいくつか存在する.
Rsyslog に入力されたメッセージは msgrawmsg に格納されている.
mmnormalize の正規化処理はデフォルトで msg を対象としている.
useRawMsg="on" のオプションを使うと正規化対象を rawmsg に変更出来る.

正規化ルールを作成する際には debug テンプレートを使って,どんなメッセージが送られてきているか確認するといい.

Elasticsearch への出力が終わったら,& stop で以降の処理を止める.

ddwrt.rulebase

ここでもポイントだけ書いておく.

正規化ルールは入力されたメッセージから必要な部分だけを抽出することが出来る.

例えばこんなルールを書いたとすると, TEST1 ab=123 cd=456 というメッセージの数字部分だけをプロパティに格納することが出来る.

$ cat ddwrt.rulebase 
rule=:TEST1 ab=%ab:word% cd=%cd:word%

正しくプロパティが抽出できているかは lognormalizer コマンドで確認することが出来る.

$ # 設定が正しい場合
$ echo 'TEST1 ab=123 cd=456' | lognormalizer -r ./sample.rulebase 
{ "cd": "456", "ab": "123" }
$ # 設定が間違っている場合
$ echo ' TEST1 ab=123 cd=456' | lognormalizer -r ./sample.rulebase 
{ "originalmsg": " TEST1 ab=123 cd=456", "unparsed-data": " TEST1 ab=123 cd=456" }
$ echo 'TEST1 ab=123  cd=456' | lognormalizer -r ./sample.rulebase 
{ "originalmsg": "TEST1 ab=123  cd=456", "unparsed-data": " cd=456" }

半角スペース1つでもルールに反するものはパースできない. 途中でパースが失敗していたらunparsed-data部分で表示される.

こんな感じで目的のメッセージに合わせてルールを作り込んでいく.

ここでパースしたプロパティは ddwrt.conf で設定しているテンプレートで利用される.

サービス起動

$ sudo systemctl restart rsyslog.service 

start なり restart なりで起動する. ただし,まだ Elasticsearch の構築前なので,Elasticsearch への出力部分はコメントアウトしておいたほうがいい.

まとめ

Rsyslog で設定するまでの流れを大まかに書いた. ポイントだけつかめれば他の用途でも使いやすそう.

設定の過程でプロパティが正常に参照できないバグにハマって結構時間を取られてしまった事以外は概ね満足.

ツイッターの使い方はまだ良くわかっていない.