rsyslog から名前付きパイプ経由で出力したログを snmptrap で飛ばす

前回からの引き続き。

rsyslog の omsnmp モジュールでは、やりたいことには微妙に足りない感じなので、何か代替案はないかとドキュメントを漁ったりググってみた結果、名前付きパイプ経由でやればいいのでは、という結論に達したので、実際に試してみた。

簡単に流れを書き出すと、

  • 名前付きパイプを準備
  • rsyslog から特定条件のログを、名前付きパイプに出力
  • 名前付きパイプに出力されたログを、Perl スクリプトで処理して、snmptrap コマンドを利用してトラップ発信
  • snmptrapd でトラップを受信

という感じ。


実際にやってみる

まずは、名前付きパイプの生成。
これは、コマンドラインで

nexus01:~# mkfifo /tmp/fifo_test.txt

を実行。
ちゃんと、出来ていることを確認する。

nexus01:~# ls -l /tmp/fifo_test.txt
prw-r--r-- 1 root root 0  4月 12 15:35 /tmp/fifo_test.txt

次に、rsyslog で名前付きパイプにログを出力するように設定。

nexus01:~# more /etc/rsyslog.d/output2FIFO.conf
if $fromhost-ip == '172.16.0.1' then |/tmp/fifo_test.txt

/etc/rsyslog.d にある .conf という拡張子付きのファイルをインクルードするようになっているので、1行しか設定項目はないけど別ファイルに切り出してある。(勿論、 /etc/rsyslog.conf に書いても大丈夫。)
設定を追加したら、rsyslogd を再起動。

このあと、/tmp/fifo_test.txt のタイムスタンプが更新されるのをチェックするか、cat /tmp/fifo_test.txt を実行して希望するログが出力されてきているのが確認できたら、準備完了。

nexus01:~# cat /tmp/fifo_test.txt
Apr 12 22:05:01 sweethome CRON[9762]: pam_unix(cron:session): session opened for user root by (uid=0)
Apr 12 22:05:01 sweethome /USR/SBIN/CRON[9764]: (root) CMD (if [ -x /etc/munin/plugins/apt_all ]; then /etc/munin/plugins/apt_all update 7200 12 >/dev/null; elif [ -x /etc/munin/plugins/apt ]; then /etc/munin/plugins/apt update 7200 12 >/dev/null; fi)
Apr 12 22:05:01 sweethome CRON[9762]: pam_unix(cron:session): session closed for user root
^C

あとは /tmp/fifo_test.txt にログが出力されるたびに、内容に合わせて処理を行うスクリプトを Perl なり Ruby なりで書いて、実行しておく、と。
凄く簡単な例として、特定の条件に合うログが出てきたら、そのログだけ出力するというもの( FIFO_test.pl )を書いてみた。

#!/usr/bin/perl
use strict;
my $fifo_file = "/tmp/fifo_test.txt";
my $fifo_fh;
open ($fifo_fh, "+< $fifo_file") or die "Aborted!";
while (<$fifo_fh>) {
 if ( $_ =~ "munin" ) {
  chomp;
  print $_."\n";
 }
}
close $fifo_fh;
exit(0);

上の例の if ブロックのところに、好きな処理を書けば、好きな様にイロイロと処理が出来る、というわけ。
実際に実行してみると、

nexus01:~# ./FIFO_test.pl
Apr 12 22:10:01 sweethome /USR/SBIN/CRON[10226]: (root) CMD (if [ -x /etc/munin/plugins/apt_all ]; then /etc/munin/plugins/apt_all update 7200 12 >/dev/null; elif [ -x /etc/munin/plugins/apt ]; then /etc/munin/plugins/apt update 7200 12 >/dev/null; fi)
Apr 12 22:15:01 sweethome /USR/SBIN/CRON[10688]: (root) CMD (if [ -x /etc/munin/plugins/apt_all ]; then /etc/munin/plugins/apt_all update 7200 12 >/dev/null; elif [ -x /etc/munin/plugins/apt ]; then /etc/munin/plugins/apt update 7200 12 >/dev/null; fi)

と、条件にあったものだけが出力されてきて、ctrl+c でスクリプトの実行を中断するまで延々と処理を続けてくれます。

実際に snmptrap を飛ばすようにしたのは、下のもの(Log2Trap.pl)。

#!/usr/bin/perl

use strict;

my $fifo_file = "/tmp/fifo_test.txt";
my $fifo_fh;
my $snmpComu = "public";
my $traphost = "localhost";
my $snmpOID = ".1.3.6.1.4.1.8072.99999";
my @keyword = (
'munin',
'FAILED LOGIN'
);

open ($fifo_fh, "+< $fifo_file") or die "Aborted!";
while (<$fifo_fh>) {
my $cnt = 0;
foreach my $key ( @keyword ) {
if ( $_ =~ "$key" ) {
chomp;
my @mesg_part = split(": ",$_);
(my $month,my $day,my $time,my $host,my $process) = split(" ",$mesg_part[0]);
system "/usr/bin/snmptrap -On -v1 -c $snmpComu $traphost $snmpOID.$cnt $host 6 1 '' $snmpOID.$cnt s \"$mesg_part[1]\"";
}
$cnt = ++$cnt;
}
}

close $fifo_fh;
exit(0);

名前付きパイプに出力されたログから、トラップ化したいログを引っ掛けるためのキーワードを @keyword に記述しておくと

Apr 13 01:25:01 nexus01 snmptrapd[7578]: 2013-04-13 01:25:01 sweethome.localhost.downtown.jp [172.16.0.1] (via UDP: [127.0.0.1]:54344->[127.0.0.1]) TRAP, SNMP v1, community public#012#011.1.3.6.1.4.1.8072.99999.0 Enterprise Specific Trap (1) Uptime: 21 days, 3:11:57.62#012#011.1.3.6.1.4.1.8072.99999.0 = STRING: "(root) CMD (if [ -x /etc/munin/plugins/apt_all ]; then /etc/munin/plugins/apt_all update 7200 12 >/dev/null; elif [ -x /etc/munin/plugins/apt ]; then /etc/munin/plugins/apt update 7200 12 >/dev/null; fi)"

こんな形で、トラップとしてログの中身が飛んできます。

で、最終目標は Zabbix との連動

んでもって、このトラップを Zabbix で処理できるように snmptt で

EVENT munin .1.3.6.1.4.1.8072.99999.0.0.1 "Log2Trap" Normal
FORMAT Z class="prettyprint linenums"BXTRAP $aA Log2Trap : $-*

整形するよう設定書いて、

01:40:01 2013/04/13 .1.3.6.1.4.1.8072.99999.0.0.1 Nomal "Log2Trap" 172.16.0.1 - ZBXTRAP 172.16.0.1 Log2Trap : .iso.3.6.1.4.1.8072.99999.0 ():(root) CMD (if [ -x /etc/munin/plugins/apt_all ]; then /etc/munin/plugins/apt_all update 7200 12 >/dev/null; elif [ -x /etc/munin/plugins/apt ]; then /etc/munin/plugins/apt update 7200 12 >/dev/null; fi)

出来上がったトラップメッセージを Zabbix で検知するためのアイテムやトリガーを作って上がれば、一丁上がりと。( Zabbix 2.0 での snmptrap の処理の仕方は、「ZABBIX-JP Study#5 Zabbix2.0rc1 SNMP Traps」というスライドで、詳しく説明されています。)

今回の方法を使えば、トラップにして飛ばしたいログの条件を複数指定したり、ログから抜き出した送信元を snmptrap コマンドでの送信元として指定するので、そのアドレスの機器から発信されたトラップに見せることが出来るわけです。

なんで、 omsnmp モジュール使ってみようとか、こんな事をやろうと思ったのかというと、Syslog サーバ上に集約されているネットワーク機器(ルータとか)からのログに対するログ監視を Zabbix で設定してみたら、元のネットワーク機器としてではなく Syslog サーバでのイベントとして検知してしまう上に同じキーワードのイベントは集約されてしまって実際に事象の起きてる機器を特定する手間が必要、ということで「運用上、使えないよねぇ〜、それじゃあ…」という事になったからだったりします。
#実際の監視業務では、速報性が重要視される局面が多いので、「どこ」で「何が起きた」のか「判別しやすい」ことが、とても重要なのです。

調べ方が悪いのか、Zabbix のログ監視機能だけで、上手くやる方法が見つからなかった、というのもありますがね。

トラックバック(1)

以前 rsyslog で名前付きパイプにログを吐き出す設定の仕方を書いておいたの... 続きを読む

コメントする