GeekFactory

int128.hatenablog.com

syslog-ngによるログ監視とメール通知

ログ監視はシステムの異常を検知する重要な方法です。外部にサービスを公開すると侵入される可能性がありますし、サービス障害に気づかない可能性もあります。

syslog-ngではログに特定のパターンが出現したらメールで通知することが可能です。destinationのprogram()にメール送信スクリプトを指定します。

8.2.4. program()

This driver starts an external application or script and sends the log messages to its standard input (stdin).

The program() driver has a single required parameter, specifying a program name to start.

Declaration:
program(command_to_run);

http://www.balabit.com/dl/html/syslog-ng-v3.0-guide-admin-en.html/ch08s02.html#reference_destination_program

例えば以下の監視項目を考えてみます。

  • 認証に失敗した場合。
  • コンソールからログインした場合。
  • LANケーブルが抜線された場合。
  • USBケーブルが抜線された場合。

syslog-ng.confは以下のようになります。パターンは実際のログから地道に作るのが最良です。

# alert-mail notification
destination alert_mail { program("/usr/local/bin/syslog-ng-alert" flush_lines(0) flush_timeout(0)); };

filter alert_auth { filter(auth) and message("failure"); };
filter alert_console { program("login"); };
filter alert_network { program("kernel") and message("bonding:|e1000e:"); };
filter alert_device { program("kernel") and message("USB device|USB disconnect"); };

log { source(src); filter(alert_auth); destination(alert_mail); };
log { source(src); filter(alert_console); destination(alert_mail); };
log { source(src); filter(alert_network); destination(alert_mail); };
log { source(src); filter(alert_device); destination(alert_mail); };

メール送信スクリプト

program()に指定したメール送信スクリプトはsyslog-ngの子プロセスとして常時起動されたままになります。パターンが出現する度に起動されるのではなく、syslog-ngの開始時に起動されてから標準出力が開きっぱなしになります。標準出力が閉じられないので、mailコマンドにリダイレクトするだけではいつまで経ってもメールが飛びません。

1行読み込んでメールを送れば問題は解決します。エントリを引用させて頂きます。

/usr/local/bin/syslog-ng-notify の内容は例えば以下のようになっています。メッセージを mail コマンドにパイプして渡して、hoge@fuga-mail.com に送信しています。

#!/bin/sh
TO=hoge@fuga-mail.com
while read line
do
    echo $line | /bin/mail -s "mail_title `hostname`" $TO
done
http://d.hatena.ne.jp/japanrock_pg/20090616/1245144439

ただし、メッセージ1行がメール1通になります。一度に何行もログを出力するデーモンではメールが増えてしまうため、連続して出力されたメッセージを1通に収めるよう改良してみました。

#!/bin/sh
# http://d.hatena.ne.jp/int128/20100516

INTERVAL=5
MAILTO=alert
BUFFER=/var/run/syslog-ng-alert-buffer

rm -f "$BUFFER"
while true; do
    read -t $INTERVAL line
    readstatus=$?
    if [ $readstatus -gt 128 ]; then
        # timeout: flush buffer
        if [ -s "$BUFFER" ]; then
            mail "$MAILTO" < "$BUFFER"
            rm -f "$BUFFER"
        fi
    elif [ $readstatus -gt 1 ]; then
        # error: exit
        rm -f "$BUFFER"
        exit
    else
        # otherwise: append line to buffer
        echo "$line" >> "$BUFFER"
    fi
done

メッセージを読み込むごとにバッファに追記していきます。メッセージが5秒間途切れると、バッファの内容をメールで送信してクリアします。

ログが大量に出た場合はメール爆弾になってしまうので通知量を制限してもよいと思います。しつこい接続をファイアウォールでdropするのも有効ですね。メール通知を増やしすぎると生活に支障を来すおそれがありますので、ご利用は計画的に!