ホーム » 技術 » Fluentd/Elasticsearch/Kibanaでsyslogを管理してみる

Fluentd/Elasticsearch/Kibanaでsyslogを管理してみる

この記事では、Elasticsearch/Kibanaのver5.xをインストールしている。2019年6月時点での最新版 7.1 をインストールしたい方は Fluentd/Elasticsearch7/Kibana7でsyslogを管理してみる のほうをご覧いただきたい。

rsyslogとjournaldのことの回で、長いことsyslog管理をほったらかしにしていたことを告白したわけだが、これを機にFluentdで集めてKibanaで閲覧する環境を整えてみることにした。というわけでインストール手順と結果についてまとめてみる。

全体の構成はこんな感じだ。

構成イメージ

受信サーバの準備

ではまず受信サーバを準備しよう。

Elasticsearch/Kibanaのインストール

Elasticsearch/Kibanaの運用にどれぐらいのスペックが必要なのかいまいちよく分からない。管理対象のサーバは10台になるかならないかぐらいなのだが、Zabbixサーバに同居させるのはちょっと不安だったので、新しく専用のサーバを立てることにした。というわけで何もないところからスタートだ。

最初に、yumのためにrepoファイルを作成する。面倒だが手動だ。コピペできるようにバッチ風に書いておこう。

cat <<EOL >/etc/yum.repos.d/elasticsearch.repo
[elasticsearch-5.x]
name=Elasticsearch repository for 5.x packages
baseurl=https://artifacts.elastic.co/packages/5.x/yum
gpgcheck=1
gpgkey=https://artifacts.elastic.co/GPG-KEY-elasticsearch
enabled=1
autorefresh=1
type=rpm-md
EOL

こうしておいて、yum installする。

rpm --import https://artifacts.elastic.co/GPG-KEY-elasticsearch
yum install java-1.8.0-openjdk elasticsearch kibana

続いてBasic認証ぐらいさせたいのでx-packをインストールする。

/usr/share/elasticsearch/bin/elasticsearch-plugin install x-pack
/usr/share/kibana/bin/kibana-plugin install x-pack

Elasticsearchの設定ファイルは /etc/elasticsearch/elasticsearch.yml だ。こんな風に書く。

cluster.name: クラスタ名
node.name: ノード名
network.host: 0.0.0.0
transport.host: localhost
transport.tcp.port: 9300

もうひとつ、/etc/elasticsearch/jvm.options にメモリ量に応じてオプションを指定する。

-Xms2g
-Xmx2g
# メモリの半分を指定

Kibanaの設定ファイルは /etc/kibana/kibana.yml だ。

server.host: "0.0.0.0"
elasticsearch.url: "http://受信サーバ名:9200"

次にファイアウォールを設定する。Kibanaにアクセスするだけなら5601ポートを開ければよい。

firewall-cmd --permanent --add-port=5601/tcp
firewall-cmd --reload

続いて、ElasticsearchとKibanaを起動する。

systemctl start elasticsearch kibana
systemctl enable elasticsearch kibana

ここから、急いでパスワードを設定する(本来コマンドラインで設定できるはずなのだが、マニュアル通りのコマンドが見つからず、やむを得ずGUIから設定している)。まずKibanaのコンパネにアクセスする。URLは「http://サーバのIP:5601」だ。するとログイン画面が出てくる。

Kibanaのログイン画面

困ったことに、Kibanaのデフォルトのユーザ名とパスワードは固定されている。ユーザ名が「elastic」、パスワードが「changeme」だ。他人に乗っ取られる前に、これを変更しなければならない。まずはログインして、左のサイドバーの「Management」をクリックして管理画面を表示させる。

Kibanaの管理画面

「Security」セクションの「Users」を選択すると、予約ユーザ一覧が表示される。

ユーザ一覧画面

「elastic」を選択し、続いて「Change Password」を選ぶ。

ユーザelasticのパスワード変更

自分で決めた強固なパスワードを指定して「Save」をクリックすれば一安心だ。

なお、他に「kibana」と「logstash_system」が予約されているので、これらのパスワードも変更しておく。

ユーザkibanaのパスワード変更

注意書きにある通り、kibana.ymlに設定したパスワードを記述しなければならない。具体的には以下のような手順になる。まずコンソールから /etc/kibana/kibana.yml を編集して、次のように追記する。

elasticsearch.username: "kibana"
elasticsearch.password: "設定したパスワード"

そうしておいて、Kibanaをリスタートする。

systemctl restart kibana

ユーザ「elastic」のパスワードもFluentdの設定時に使うのでメモしておく。

受信用のFluentdインストール

次に受信サーバでのFluentdの準備だ。インストールは次のone linerで行う。

curl -L https://toolbelt.treasuredata.com/sh/install-redhat-td-agent3.sh | sh

続いてElasticsearch用のプラグインを追加する。

td-agent-gem install fluent-plugin-elasticsearch

[2019年6月25日追記] Fluentdはport24224を使って通信するので、そのポートも開けておく。全部あけてしまうのも気が引けるので、ログを受け取る対象サーバを選んで受け取るルールにしておこう。

firewall-cmd --permanent --new-zone=fluentd
firewall-cmd --permanent --zone=fluentd --set-target=ACCEPT
firewall-cmd --permanent --zone=fluentd --add-port=24224/tcp
firewall-cmd --permanent --zone=fluentd --add-source=送信サーバIP1
firewall-cmd --permanent --zone=fluentd --add-source=送信サーバIP2
firewall-cmd --reload

次に設定ファイルを書く。設定ファイルは/etc/td-agent/td-agent.confだが、インストール直後にデフォルトのファイルが置いてあるので、その末尾にこんな風に追記する。まずは送信サーバの設定を示す。途中にElasticsearchで設定したパスワードを指定する部分があるので、自分で設定したものを記述する。

<source>
  @type syslog
  port 5140
  tag fluentd.syslog
  format syslog
</source>

<match fluentd.**>
  @type copy
  <store>
    @type elasticsearch
    logstash_format true
    include_timestamp true
    port 9200
    user elastic
    password elasticのパスワード
    buffer_type file
    buffer_path /var/log/td-agent/buffer/fluentd.back
  </store>
</match>

この設定ファイルは2つのディレクティブから成る。sourceはポート5140からsyslogメッセージを受信して解析することを指示する部分、matchは内外から受信するFluentdのメッセージをElasticsearchへ突っ込む設定だ。syslogの設定はちょっと後に回して、まずは設定ファイルを作っておこう。できたらFluentdを起動する。

systemctl enable td-agent
systemctl start td-agent

さてsyslogメッセージだが、 Fluentdがログを送信する方法はいくつかある。たとえばログファイルを直接パースして送信することもできる(実際は/var/log/messagesのファイル権限の都合でうまくいかない)。だがsyslogを扱うなら本家のドキュメントが示す手段を使うのがよさそうだ。概要はこんな感じだ。

  1. rsyslogに設定を加えて、local port 5140にsyslogを送るようにする
  2. Fluentdでそれを捕まえて受信サーバへ送る

2のFluentdで捕まえるほうは、すでにtd-agent.confに記述済みなので、1のrsyslogの設定を行う。/etc/rsyslog.conf の末尾に、次の1行を追加する。

*.info;mail.none;authpriv.none;cron.none                @127.0.0.1:5140

設定はお好みに合わせて変えていただきたい。上記の場合、/var/log/messagesと同じレベルの情報をFluentdに送る設定にしている。いったんこれで様子を見て、慣れてきたら情報を増やすとよい。syslogの出力全部を送り付けたい場合は

*.*  @127.0.0.1:5140

と書けばよい。設定ができたら、rsyslogを再起動する。

systemctl restart rsyslog

これで受信側はできた。

送信サーバの準備

次に送信サーバ側の設定を示す。監視対象となるサーバの設定は、Fluentdをインストールした後、送信用の設定をいくつか施すことになる。

インストールは受信サーバと同じone linerで行う。

curl -L https://toolbelt.treasuredata.com/sh/install-redhat-td-agent3.sh | sh

rsyslogの設定と再起動も忘れずに行っておく。念のため記載しておこう。

*.info;mail.none;authpriv.none;cron.none                @127.0.0.1:5140

または

*.*  @127.0.0.1:5140

を追記しておいて、rsyslogを再起動する。

systemctl restart rsyslog

次にFluentdの設定ファイルを書く。送信サーバはこんな感じだ。

<source>
  @type syslog
  port 5140
  tag fluentd.syslog
  format syslog
</source>

<match fluentd.**>
  @type forward
  <server>
    host 受信サーバのホスト名またはIPアドレス
    port 24224
  </server>
</match>

設定ファイルができたら、こちらのFluentdも起動する。

systemctl enable td-agent
systemctl start td-agent

Kibanaの使い方

設定が完了したら、あらためてKibanaにアクセスしてみよう。ログインするとこんな画面になるはずだ。サイドメニューから順に呼び出すには、「Management」→「Kibana」→「Index Patterns」でたどり着ける。

Index patternの作成

td-agent.conf で logstash_format を指定しているので、syslogの受信がうまくいっていれば Index patternがアクティブ(認識できている状態)になっているはずだ。そして Time Filter field name にもデフォルトの「@timestamp」が入った状態になっている。 「Unable to fetch mapping…」と出ている場合は、何かがうまくいっていない。設定をチェックしてみて欲しい。 問題がなければ「Create」ボタンを押す。

Field設定画面

次の画面では、読み込んだ情報の各フィールドを表示している。細かな設定を行うならここから操作するが、最初はやることがないので飛ばして構わない。次はサイドメニューの「Discover」をクリックする。

Discover画面

Discover画面では、時系列にイベントの数をカウントしたグラフとイベントの一覧を表示してくれる。スケールは右上の「Last 12 hours」などと表示されているところをクリックすると調整できるし、グラフを直接クリックするとそこを拡大できる。さて画面では試験的に1台のサーバのすべてのsyslogを12時間ほど集めた状態なのだが、すでに多数のログが集まっている。こういうとき、どういう種類のどんなメッセージが集まっているのかを調べたい。そういうときは左のサブメニューの「ident」をクリックする。すると受信しているメッセージ種別ごとにヒストグラムを表示してくれる。

Fieldを詳細化する手順

例を見ると、Kibanaのログが92%を占めているのが分かる。他を見てみると、sshdのログが多いようだ。そこでこれを抽出してみよう。特定のidentを抽出するには、ルーペアイコンをクリックすればよい。

sshdログを抽出

これで過去12時間に渡って記録されたsshdのメッセージを抽出できた。よく見るとこれは、サーバを設置した後に22番ポートへスキャンしに来ている不埒者のログだ。12時間のうちにこれほどの頻度でポートスキャンがあるということなのだ。ちなみにこれらのスキャンは、fail2banでブラックリスト送りにしてしまうので特に問題は起こっていない。

以上が簡単なKibanaの使い方だ。複数ホストのログを集約し始めたら、hostフィールドで分類やフィルタをすればよいし、個々のメッセージも確認できるので、気になるログは全部この画面からチェックできるようになる。何かアタックの兆しがあったら、個々に対処することになるが、それはまた別のお話ということで。

KibanaをHTTPS化する

Kibanaにアクセスすると、HTTPなので「保護されていない通信」と出る。実にうざったいのでLet’s Encryptを利用してHTTPS化したい。もしサーバにホスト名を割り当てられる方なら、次のような手順で実施できる。

まずサーバにcertbotをインストールする。

yum install certbot

firewall-cmdでHTTPをあけておく。

firewall-cmd --permanent --add-service=http
firewall-cmd --reload

次にstandaloneモードでLet’s Encryptから証明書をもらう。

certbot --standalone certonly

certbotの使い方は説明しないが、メールアドレスや登録したいFQDNを聞かれるのできちんと答える。最後までうまくいけば、正しく証明書ファイルが作成される。/etc/letsencrypt/archive/登録したFQDN、というディレクトリにファイルが格納されているはずだ。

次がトリックなのだが、Kibanaはこのディレクトリを直接読めない。root権限で保護されてしまっているからだ。仕方がないのでこれをコピーする。適切な場所を選んで、次のようなバッチを設置する。たとえば /usr/local/bin/kibana-letsencrypt などとしておこう。

#!/bin/sh

FQDN=登録したFQDN

LETSENCRYPT_DIR=/etc/letsencrypt/archive
KIBANA_DIR=/etc/kibana/ssl

mkdir -p $KIBANA_DIR
cp -rp $LETSENCRYPT_DIR/$FQDN $KIBANA_DIR
chmod 750 $KIBANA_DIR/$FQDN
chmod 640 $KIBANA_DIR/$FQDN/*
chown -R root:kibana $KIBANA_DIR

このバッチを実行して、ファイルが適切な場所に適切なパーミッションでコピーされていることを確認する。

[root@syslog3 ~]# ll /etc/kibana/ssl/xxxxxxxxxxxxxxxxxxx/
total 16
-rw-r----- 1 root kibana 1948 Jun 18 16:38 cert1.pem
-rw-r----- 1 root kibana 1647 Jun 18 16:38 chain1.pem
-rw-r----- 1 root kibana 3595 Jun 18 16:38 fullchain1.pem
-rw-r----- 1 root kibana 1704 Jun 18 16:38 privkey1.pem

次に /etc/kibana/kibana.yml を編集する。次の3行を追加する。

server.ssl.enabled: true
server.ssl.certificate: /etc/kibana/ssl/登録したFQDN/fullchain1.pem
server.ssl.key: /etc/kibana/ssl/登録したFQDN/privkey1.pem

最後にKibanaをリスタートする。

systemctl restart kibana

これで、https://サーバ名:5601 という名前でアクセスすることができるようになった。

なお Let’s Encrypt の証明書は3ヶ月ごとに更新が必要なので、cronを設定しておく。たとえば /etc/cron.d/cert-renew のようなバッチを用意する。これは毎週月曜日の9時30分に期限をチェックして、更新があればファイルのコピーも行ってくれる。

MAILTO=
30 9 * * mon root /usr/bin/certbot renew --standalone --post-hook "/usr/loal/bin/kibana-letsencrypt" | logger -t certbot-renew -p local0.info

ただ、このバッチはまだ期限を迎えていないのでテストできていない。3ヵ月後に本当に更新できたか確認しなければならない。

Kibanaのログがうざい場合

Kibanaはアクセスごとに大量のログをsyslogに流すので、受信サーバ自体を監視に含めると大変なことになる。Kibanaのフィルタを使って排除してもよいが、rsyslogにフィルタを入れる方法もある。具体的には /etc/rsyslog.d/ignore-kibana.conf というファイルを作成する。

if $programname == "kibana" then stop

そうしておいて rsyslog を再起動すれば kibana からのメッセージは記録されなくなる。

参考リンク