◆ 目的
監視対象ノードからのトラップを監視サーバのsnmptrapdで受理し、
その内容を同じく監視サーバで稼動しているサーバ(今回はnagiosを利用)へ通知させる。
nagiosの分散監視方法についてはこちらを参照のこと。
◆ 概要(トラップ処理の流れ)
1. トラップが飛んでくる
(トラップ例)
host101
UDP: [10.0.0.1]:59360
.1.3.6.1.2.1.1.3.0 87:21:51:52.92
.1.3.6.1.6.3.1.1.4.1.0 .1.3.6.1.6.3.1.1.5.3
.1.3.6.1.2.1.2.2.1.1.10106 10106
.1.3.6.1.2.1.2.2.1.2.10106 "eth0"
.1.3.6.1.2.1.2.2.1.3.10106 ethernet-csmacd
.1.3.6.1.4.1.9.2.2.1.1.20.10106 "down"
.1.3.6.1.6.3.18.1.3.0 10.24.7.14
.1.3.6.1.6.3.18.1.4.0 "public"
.1.3.6.1.6.3.1.1.4.3.0 .1.3.6.1.6.3.1.1.5
2. /usr/sbin/snmptrapdデーモンがトラップを受理
3. snmptrapd.conf内のtraphandleディレクティブで指定したコマンドが実行される
実行されるコマンドはトラップ内容を解析し、その結果を元にsend_nscaを実行して
パッシブなデータの転送処理を担当するNSCA(Nagios Service Check Acceptor)に通知させる。
そしてNSCA経由でNagiosは結果を受け取る。
※snmptrapd.confファイルの場所はsnmptrapdの起動スクリプト/etc/init.d/snmptrapdで指定される。
◆ 準備(監視サーバ側)
● インストール
# yum -y install net-snmp
# yum -y install nagios
# yum -y install nagios-nsca
トラップ受信時に一部データベースを使うためである(後ほど説明する)。
# yum -y install mysql mysql-server
● /etc/init.d/snmptrapdファイルの設定
飛んできたtrapを名前変換させないようにする。
# cp /etc/init.d/snmptrapd /etc/init.d/snmptrapd.yyyymmdd
# vi /etc/init.d/snmptrapd
(前)
OPTIONS="-Lsd -p /var/run/snmptrapd.pid"
(後)
OPTIONS="-On -Lsd -p /var/run/snmptrapd.pid"
(後)
OPTIONS="-On -Lsd -p /var/run/snmptrapd.pid"
● snmptrapd.confファイルの設定
飛んできたtrapの認証は不要とする。
traphandle ディレクティブで実行するコマンドを指定する。
traphandle ディレクティブで実行するコマンドを指定する。
# cp /etc/snmp/snmptrapd.conf /etc/snmp/snmptrapd.conf.yyyymmdd
# vi /etc/snmp/snmptrapd.conf
disableAuthorization yes
# traphandle default /usr/local/bin/trap.sh ← (a)
traphandle default /usr/local/bin/trap.rb ← (b)
● traphandleディレクティブで指定したツールの概要
(a)
単純にトラップの内容をログに追記する。
(a)は今回は使わないが、単純にトラップの内容をログに出すだけならこれで十分だろう。
コードは別途下記に記載する。
(b)
(a)と同様にトラップの内容をログに追記していくのだが、
トラップの内容からデータベースを参照してoidの数字をテキストに変換、
また発報させるかさせないのかを判断をさせる処理を加えている。
データベースを用意する目的
1) 数字のoidでは内容が直感的に分からないため、テキストに変換する役割
2) 監視アラームとして発報させる、させないを制御する役割
そして、nagiosへの通知手段としてnagios-nscaをツール内で実行。
● トラップ処理ツールのコード
(a)
# vi /usr/local/bin/trap.sh
#!/bin/sh
echo --------------------------------- >> /var/log/snmptrap/traphandle.log
echo "`date '+%Y%m%d%H%M%S'`" >> /var/log/snmptrap/traphandle.log
while read line
do
echo "$line" >> /var/log/snmptrap/traphandle.log
done
# chmod 755 /usr/local/bin/trap.sh
(b)
# vi /usr/local/bin/trap.rb
#!/usr/bin/ruby
require 'mysql'
def error(exc)
f = open('/var/log/snmptrap/traphandle_error.log','a+')
f.puts '---------------'
f.puts(Time.now.strftime("%Y%m%d%H%M%S"))
f.puts(exc)
f.close
exit 1
end
def no_alert(host, mib_num)
f = open('/var/log/snmptrap/traphandle_no_alert.log','a+')
f.puts '---------------'
f.puts(Time.now.strftime("%Y%m%d%H%M%S"))
f.puts("host : #{host}")
f.puts("mib_num : #{mib_num}")
f.close
exit 0
end
def alert(host, mib_text)
begin
command = "/usr/lib/nagios/plugins/submit_check_result #{host} 'TRAP [#{mib_text}]' 1 'check /var/log/snmptrap/traphandle.log'"
#system command
puts command
rescue => exc
error(exc)
end
exit 0
end
# TRAP RECEIVE
begin
f = open('/var/log/snmptrap/traphandle.log','a+')
f.puts '---------------'
f.puts(Time.now.strftime("%Y%m%d%H%M%S"))
host = gets.chomp!
# /etc/hosts ファイルへホスト名の登録が必要
if host =~ /.*: (\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}\d)/ || host =~ /<UNKNOWN>/
host = 'other'
end
f.puts(host)
f.puts(gets)
f.puts(gets)
oid = gets
f.puts(oid.chomp!)
mib_num = oid.scan(/.* (.*)/)
while line = gets
f.puts(line)
end
f.close
rescue => exc
error(exc)
end
# DATABASE
begin
db = Mysql::new('localhost', 'trapuser', 'password', 'trapdb')
res = db.query("select id from ignore_table where mib_id = (select id from mib_table where mib_num = '#{mib_num}')")
id = nil
res.each { | i | id = i }
no_alert(host, mib_num) if id != nil
res = db.query("select host, mib_text from host_table as h, mib_table as m, host_mib_table as hm where h.id = hm.host_id and m.id = hm.mib_id and h.host = '#{host}' and mib_num = '#{mib_num}'")
mib_text = nil
res.each { | h, m | mib_text = m }
mib_text = 'other' if mib_text == nil
alert(host, mib_text)
rescue => exc
error(exc)
ensure
db.close
end
# chmod 755 /usr/local/bin/trap.rb
# vi /usr/lib/nagios/plugins/submit_check_result
#!/bin/sh
printfcmd="/usr/bin/printf"
NscaBin="/usr/sbin/send_nsca"
NscaCfg="/etc/nagios/send_nsca.cfg"
NagiosHost1=10.0.0.1
$printfcmd "%s\t%s\t%s\t%s\n" "$1" "$2" "$3" "$4" | $NscaBin $NagiosHost1 -p 5667 -c $NscaCfg
# chmod 755 /usr/lib/nagios/plugins/submit_check_result
● 各種プロセスの起動
# /etc/init.d/snmptrapd start
# /etc/init.d/mysqld start
# chkconfig snmptrapd on
# chkconfig mysqld on
● データベースの準備
mysqlの初期設定
# mysql_secure_installation
Set root password? [Y/n] ← 空ENTER(rootパスワード設定)
New password: ← rootパスワード応答
Re-enter new password: ← rootパスワード応答(確認)
Remove anonymous users? [Y/n] ← 空ENTER(匿名ユーザー削除)
Disallow root login remotely? [Y/n] ← 空ENTER(リモートからのrootログイン禁止)
Remove test database and access to it? [Y/n] ← 空ENTER(testデータベース削除)
Reload privilege tables now? [Y/n] ← 空ENTER
ルートユーザでログイン
# mysql -u root -p
Enter password:
ユーザの作成
> GRANT ALL PRIVILEGES ON trapdb.* TO trapuser@localhost IDENTIFIED BY 'password';
> quit
トラップDBを操作するユーザで再ログイン
# mysql -u trapuser -p
Enter password:
データベースの作成
> CREATE DATABASE trapdb;
データベースへ接続
> USE trapdb;
テーブルの作成
ホスト管理テーブル
> CREATE TABLE host_table (
id INT NOT NULL AUTO_INCREMENT,
host VARCHAR(255) NOT NULL UNIQUE,
PRIMARY KEY(id));
PRIMARY KEY(id));
> SHOW COLUMNS FROM host_table;
+-------+--------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+-------+--------------+------+-----+---------+----------------+
| id | int(11) | NO | PRI | NULL | auto_increment |
| host | varchar(255) | NO | UNI | NULL | |
+-------+--------------+------+-----+---------+----------------+
mib管理テーブル
> CREATE TABLE mib_table (
id INT NOT NULL AUTO_INCREMENT,
mib_num VARCHAR(255) NOT NULL UNIQUE,
mib_text VARCHAR(255) NOT NULL,
PRIMARY KEY(id));
PRIMARY KEY(id));
> SHOW COLUMNS FROM mib_table;
+----------+--------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+----------+--------------+------+-----+---------+----------------+
| id | int(11) | NO | PRI | NULL | auto_increment |
| mib_num | varchar(255) | NO | UNI | NULL | |
| mib_text | varchar(255) | NO | | NULL | |
+----------+--------------+------+-----+---------+----------------+
ホストとmib管理テーブル
> CREATE TABLE host_mib_table (
host_id INT NOT NULL,
mib_id INT NOT NULL,
FOREIGN KEY(host_id) REFERENCES host_table(id),
FOREIGN KEY(mib_id) REFERENCES mib_table(id));
> SHOW COLUMNS from host_mib_table;
+---------+---------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+---------+---------+------+-----+---------+-------+
| host_id | int(11) | NO | MUL | NULL | |
| mib_id | int(11) | NO | MUL | NULL | |
+---------+---------+------+-----+---------+-------+
不要トラップ管理テーブル
> CREATE TABLE ignore_table (
id INT NOT NULL AUTO_INCREMENT,
mib_id INT NOT NULL UNIQUE,
PRIMARY KEY(id),
FOREIGN KEY(mib_id) REFERENCES mib_table(id));
> SHOW COLUMNS FROM ignore_table;
+--------+---------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+--------+---------+------+-----+---------+----------------+
| id | int(11) | NO | PRI | NULL | auto_increment |
| mib_id | int(11) | NO | MUL | NULL | |
+--------+---------+------+-----+---------+----------------+
登録
ホストの登録
> INSERT INTO host_table (host) VALUES('host101');
> INSERT INTO host_table (host) VALUES('host102');
> INSERT INTO host_table (host) VALUES('host103');
> SELECT * FROM host_table;
+----+---------+
| id | host |
+----+---------+
| 1 | host101 |
| 2 | host102 |
| 3 | host103 |
+----+---------+
MIBの登録
> INSERT INTO mib_table (mib_num, mib_text) VALUES('.1.3.6.1.6.3.1.1.5.3', 'linkDown');
> INSERT INTO mib_table (mib_num, mib_text) VALUES('.1.3.6.1.6.3.1.1.5.4', 'linkUp');
> SELECT * FROM mib_table;
+----+----------------------+-----------------------+
| id | mib_num | mib_text |
+----+----------------------+-----------------------+
| 1 | .1.3.6.1.6.3.1.1.5.3 | linkDown |
| 2 | .1.3.6.1.6.3.1.1.5.4 | linkUp |
| 3 | .1.3.6.1.6.3.1.1.5.5 | authenticationFailure |
+----+----------------------+-----------------------+
不要トラップの登録
> INSERT INTO ignore_table (mib_id) VALUES(13);
> SELECT * FROM mib_table;
+----+--------+
| id | mib_id |
+----+--------+
| 1 | 3 |
+----+--------+
ホストとMIBの登録
下のようにホストとMIBを結びつけるようにデータベースに登録する。
host101 ⇔ linkDown
host101 ⇔ linkUp
host102 ⇔ linkDown
host_mib_tableをこのようにしたいわけである。
+---------+--------+
| host_id | mib_id |
+---------+--------+
| 1 | 1 |
| 1 | 2 |
| 2 | 1 |
+---------+--------+
アラーム発報
上記のようにホストとMIBを対応させた場合にどのように発報するのかまとめておく。
・ host101
linkDown → host101, TRAP [lindDown] として発報する
linkUp → host101, TRAP [lindUp] として発報する
authenticationFailure → 発報しない
未定義TRAP → host101, TRAP [other] として発報する
・ host102
linkDown → host102, TRAP [lindDown] として発報する
linkUp → host102, TRAP [other] として発報する
authenticationFailure → 発報しない
未定義TRAP → host102, TRAP [other] として発報する
・ host103
linkDown → host101, TRAP [other] として発報する
linkUp → host101, TRAP [other] として発報する
authenticationFailure → 発報しない
未定義TRAP → host103, TRAP [other] として発報する
・ 未定義ホスト
linkDown → other, TRAP [other] として発報する
linkUp → other, TRAP [other] として発報する
authenticationFailure → 発報しない
未定義TRAP → other, TRAP [other] として発報する
idごとにひもづけるのだが手間がかかるのでツールを用意しておく。
# /usr/lib/nagios/plugins/update_db.rb [ホスト名] [mib(oid)] [insert|delete]
# /usr/lib/nagios/plugins/update_db.rb host101 .1.3.6.1.6.3.1.1.5.3 insert
# /usr/lib/nagios/plugins/update_db.rb host101 .1.3.6.1.6.3.1.1.5.4 insert
# /usr/lib/nagios/plugins/update_db.rb host102 .1.3.6.1.6.3.1.1.5.3 insert
削除したい場合は"insert"を"delete"に変える
# vi /usr/lib/nagios/plugins/update_db.rb
#!/usr/bin/ruby
require 'mysql'
host = ARGV[0]
mib = ARGV[1]
action = ARGV[2]
if ARGV.length != 3
puts "argument error : ./update_db.rb [host] [mib number] [insert | delete]"
exit 1
end
$db = Mysql::new('localhost', 'trapuser', 'password', 'trapdb')
def select(q)
begin
id = nil
query = q
res = $db.query(query);
res.each do | i |
id = i
end
return id
rescue => exc
puts exc
end
end
def insert(host_id, mib_id)
begin
query = "insert into host_mib_table (host_id, mib_id) values(#{host_id}, #{mib_id})"
$db.query(query);
puts "OK : #{query}"
exit 0
rescue => exc
puts exc
end
end
def delete(host_id, mib_id)
begin
query = "delete from host_mib_table where host_id = #{host_id} and mib_id = #{mib_id}"
$db.query(query);
puts "OK : #{query}"
exit 0
rescue => exc
puts exc
end
end
def check_duplicate(host_id, mib_id)
begin
query = "select host_id, mib_id from host_mib_table where host_id = #{host_id} and mib_id = #{mib_id}"
res = $db.query(query);
flag = nil
res.each do | i |
flag = 1
end
if flag == 1
puts("ERROR : Already registered");
exit 1
end
rescue => exc
puts exc
end
end
query = "select id as host_id from host_table where host = '#{host}'"
host_id = select(query)
if host_id == nil
puts "ERROR : '#{host}' is not registered!!"
exit 1
end
query = "select id as mib_id from mib_table where mib_num = '#{mib}'"
mib_id = select(query)
if mib_id == nil
puts "ERROR : '#{mib}' is not registered!!"
exit 1
end
if action == "insert"
check_duplicate(host_id, mib_id)
insert(host_id, mib_id)
elsif action == "delete"
delete(host_id, mib_id)
else
puts "ERROR : Action is bad."
puts "Action is [insert|delete]."
exit 1
end
● nagiosの準備
設定
トラップを受け付けるサービス設定は以下でよい。
細かい設定に関しては省略する。
define service{
use generic-service
host_name host01, host02
service_description TRAP [LinkUp]
check_period none
active_checks_enabled 1
max_check_attempts 1
is_volatile 1
check_command check_dummy!0!"OK"
}
define service{
use generic-service
host_name host03
service_description TRAP [LinkDown]
check_period none
active_checks_enabled 1
max_check_attempts 1
is_volatile 1
check_command check_dummy!0!"OK"
}
文法チェック
# nagios -v /etc/nagios/nagios.cfg
起動
# /etc/init.d/nagios restart
# chkconfig nagios on
● nscaの準備
設定
設定ファイルは下だが、基本ディフォルトのままでいいだろう。
/etc/nagios/nsca.cfg
nscaは5667/tcpポートでsend_nscaからの結果を受け取るので、
iptablesなど確認しておいた方がいいだろう。
起動
nacaも立ち上げておく
# /etc/init.d/nsca restart
# chkconfig nsca on
◆ 準備(監視対象ノード側)
監視対象ノードがLinuxサーバであれば、
/etc/snmp/snmpd.confファイルを編集する
下のディレクティブに監視サーバのIPアドレスを入れておけばいいだろう
trapsink 監視サーバのIPアドレス
trap2sink 監視サーバのIPアドレス
◆ 発報試験
1) 監視対象ノードからトラップを飛ばす
2) 監視サーバ側でログを確認する
2-1) trap.rbが処理するログの確認
アラームとして発報させるtrapのログ
/var/log/snmptrap/traphandle.log
trapが飛んできたけれどテーブルに登録していない(アラートをあげない)場合のログ
/var/log/snmptrap/traphandle_no_alert.log
例外発生時のログ
/var/log/snmptrap/traphandle_error.log
2-2) nagiosが処理するログ
/var/log/nagios/nagios.log
監視対象ノードからトラップを飛ばせないのであれば、
監視サーバ側で手動で試験できる。
ツールを実行
# /usr/local/bin/trap.rb
以下をまるごと貼り付け
host101
UDP: [10.0.0.1]:59360
.1.3.6.1.2.1.1.3.0 87:21:51:52.92
.1.3.6.1.6.3.1.1.4.1.0 .1.3.6.1.6.3.1.1.5.3
.1.3.6.1.2.1.2.2.1.1.10106 10106
.1.3.6.1.2.1.2.2.1.2.10106 "eth0"
.1.3.6.1.2.1.2.2.1.3.10106 ethernet-csmacd
.1.3.6.1.4.1.9.2.2.1.1.20.10106 "down"
.1.3.6.1.6.3.18.1.3.0 10.24.7.14
.1.3.6.1.6.3.18.1.4.0 "public"
.1.3.6.1.6.3.1.1.4.3.0 .1.3.6.1.6.3.1.1.5
Ctrl + D で抜ける
"1 data packet(s) sent to host successfully."
と出ればツールは正常に動作している。
それでもnagios側で表示されないようであれば、
nagiosの設定の問題であろう。