Zabbix で SNMP Trap を受信する

# はじめに
何かあったとき、監視対象から監視装置へ通知させたいことがある。Network 機器であれば Link downしてトポロジが変わったとかが典型例。標準的には SNMP Trap を監視装置に飛ばして実現する。監視装置としては Zabbix が定番だが、一つだけ問題がある。 Zabbix は単独では Trap を受信できない。
設定は公式ドキュメントに従い、以下の流れで行うことになる（[Zabbix マニュアル 3 SNMP trap](https://www.zabbix.com/documentation/6.0/jp/manual/config/items/itemtypes/snmptrap) より抜粋）

> 1. snmptrapdがトラップを受信
> 2. snmptrapd はトラップをレシーバー スクリプト (Bash,Perl) または SNMPTT に渡します。
> 3. 受信者はトラップを解析、フォーマットし、ファイルに書き込みます
> 4. Zabbix SNMP トラッパーは、トラップ ファイルを読み取り、解析します。
> 5. トラップごとに、Zabbix は、受信したトラップ アドレスと一致するホスト インターフェイスを持つすべての"SNMP トラッパー"アイテムを検索します。 マッチングでは、ホスト インターフェイスで選択した"IP"または"DNS"のみが使用されることに注意してください。
> 6. 見つかった項目ごとに、トラップは snmptrap[regexp] の正規表現と比較されます。 トラップは、一致した すべて のアイテムの値として設定されます。 一致するアイテムが見つからず、snmptrap.fallback アイテムが存在する場合、トラップはその値として設定されます。
> 7. トラップがアイテムの値として設定されていない場合、Zabbix はデフォルトで、一致しないトラップをログに記録します。 (これは"管理" → "一般設定" → "その他" の "マッチしないSNMPトラップをログに記録" で設定されます。)

SNMP Trap 受信周りは装置ごとに設定が異なり、Zabbixの公式ドキュメントは残念ながらこの辺りはどうにも手薄でドハマりした。怨念を込めて構築メモを整理する。

Zabbixの構築自体の記事はこちら。検証はUbuntu 22.04/Zabbix 6.0.10で行ったが、20.04/5.0の組み合わせとほとんど変わらなかった。

https://qiita.com/Shakapon/items/e2433d0ce429baa6cc7f


## ターゲット環境

| ソフトウェア | バージョン |
|:-:|:-:|
| Ubuntu | 22.04  |
| Zabbix  | 6.0.10  |
| snmptrapd  | 5.9.1  |
| VyOS  | VyOS 1.4-rolling-202208010217  |

Zabbix を動かしてみた系の作例はかなりあるが、ほとんどが CentOS ベース。 Ubuntu ではほとんど見かけなかった。SNMPTTで加工するのが一般的のようだが、Ubuntu でのやり方が見つけられず、最終的にZabbix Receiver Scriptを利用した。実装方法見つかればそちらでも作成する。
VyOSは Trapの送信元として用意。

| 設定項目 | パラメータ |
|:-:|:-:|
| Zabbix サーバのアドレス | 192.168.1.105 |
| VyOS の送信元アドレス | 192.168.1.161 |
| SNMP Version | v2c |
| SNMP Community | shakapon |

## 試験環境構築
### Zabbix Serverの設定
#### 必要パッケージのインストール
```
sudo apt install snmp snmptrapd snmptt libconfig-inifiles-perl libsnmp-perl libnet-ip-perl
```
SNMPTTを動かすときに追加したものも混じっている。必要最低限かは怪しい。

#### Zabbix Trap Receiver
SNMPTT に代わり、`zabbix_trap_receiver.pl` で受信したパケットを解析、フォーマット、保存を行う。ただしこのファイル、apt で落としてきた Zabbix パッケージに含まれていない。zabbix_trap_receiver.pl を使った設定例は以下のQiita記事が詳しかった。

https://qiita.com/atanaka7/items/17db7271a99473fcff79

```
$ sudo apt-file search zabbix_trap_receiver.pl
$ ### 存在していれば返ってくれるハズが、回答は空っぽ
```

是非もなく、Source Codeに含まれているものを回収し、`/usr/local/bin`に配備する。
```
wget https://cdn.zabbix.com/zabbix/sources/stable/6.0/zabbix-6.0.10.tar.gz
tar zxvf zabbix-6.0.10.tar.gz
sudo cp -p ./zabbix-6.0.10/misc/snmptrap/zabbix_trap_receiver.pl /usr/local/bin/
sudo chmod
```

##### ログ保存先の変更
Trapの保存先はこの Perlスクリプト内で直接設定されている。デフォルトだと/tmpなので、サーバ再起動時に備えて/var/log 配下とする。ただしここに配備した場合、ログローテート設計が必須。これは後で実施。

```diff_shell
sudo vi /usr/local/bin/zabbix_trap_receiver.pl
- $SNMPTrapperFile = '/tmp/zabbix_traps.tmp';
+ $SNMPTrapperFile = '/var/log/snmptrapd/snmptrap.log';
```
スクリプト自体はこれで完成。実行権限と、保存先のディレクトリを作成する。このディレクトリに書き込むのはsnmptrapd からとなり、snmptrapd の実行権限でも書き込めるようにユーザ/グループを変更する。

```shell
sudo chmod +x /usr/local/bin/zabbix_trap_receiver.pl
sudo mkdir /var/log/snmptrapd
sudo chown Debian-snmp:Debian-snmp /var/log/snmptrapd
```

#### SNMPTrapd
Ubuntuの場合、snmptrapd は2か所の設定を行う必要がある。
1. snmptrapd.conf の設定
2. snmptrapd の起動オプションの設定

##### snmptrad.conf
SNMPTrapd から Zabbix Trap Receiver を呼び出せるようsnmptrapd.conf の末尾に以下を追加。
```diff_shell
vi /etc/snmp/snmptrapd.conf 
perl do "/usr/local/bin/zabbix_trap_receiver.pl";
```

##### snmptrapd.service
Ubuntu において snmptrapd は service として動作している。実態は`/lib/systemd/system/snmptrapd.service`なのだが、ここを直接書き換えるとソフトウェアの更新で上書きされてしまう。これを防ぐため、`*.service`なファイルを`/etc/systemd/system/` にコピーして使用することが推奨されている。このあたりの説明は 次のgihyo.jpの記事が詳しい。

https://gihyo.jp/admin/serial/01/ubuntu-recipe/0598

主な理由は次の二つ。
1. `/var/systemd/`と`/etc/systemd/`に同じファイルがあった場合、`/etc/systemd`が優先される. 
2. apt でソフトウェア更新しても`/etc/systemd`は上書きされない

```shell
sudo cp /lib/systemd/system/snmptrapd.service /etc/systemd/system/snmptrapd.service
```

```diff_shell
sudo vi /etc/systemd/system/snmptrapd.service
- ExecStart=/usr/sbin/snmptrapd -LOw -f udp:162 udp6:162
+ ExecStart=/usr/sbin/snmptrapd -Lsd -f udp:162 udp6:162
```

変更したオプションはnet-snmpのsnmpcmdで定義されている。今回使用したオプションの意味は表の通り。

https://net-snmp.sourceforge.io/docs/man/snmpcmd.html

| オプション | 意味 |
|:-:|:-:|
|-f   |呼び出されたシェルからフォークしない |
|-O   |出力オプション |
|-On  |（OIDのまま）数値で出力 |
|-L   |ロギングオプション |
|-Ls  |Facilityを設定 |
|-Lsd |LOG_DAEMON へ出力 |
|-LO  |標準出力 |
|-LOw | ？|

`-LOw`は Ubuntu のデフォルト値。調べても意味が取れきれない。warning を出す、なのかもだが裏は取り切れず。

##### snmptrapdの再起動

```
sudo systemctl daemon-reload # snmptrapd.serviceを書き換えたときだけ実施
sudo systemctl restart snmptrapd
sudo systemctl status snmptrapd
```

#### Zabbix Server の設定
Zabbix から定期的に SNMP Trap を取りに行くよう、```zabbix_server.conf``` を更新する。

```diff_shell
sudo vi /etc/zabbix/zabbix_server.conf
### Option: SNMPTrapperFile
#       Temporary file used for passing data from SNMP trap daemon to the server.
#       Must be the same as in zabbix_trap_receiver.pl or SNMPTT configuration file.
#
# Mandatory: no
# Default:
# SNMPTrapperFile=/tmp/zabbix_traps.tmp
+ SNMPTrapperFile=/var/log/snmptrapd/snmptrap.log
(snip)

### Option: StartSNMPTrapper
#       If 1, SNMP trapper process is started.
#
# Mandatory: no
# Range: 0-1
# Default:
# StartSNMPTrapper=0
+ StartSNMPTrapper=1
```

##### Zabbixの再起動
```shell
sudo systemctl restart zabbix-server
sudo systemctl status zabbix-server
```

### VyOSの準備
VyOS から Zabbix へ Trapが飛ぶようにする。

```shell-session VyOS の Trap設定
set service snmp trap-source '192.168.1.161'
set service snmp trap-target 192.168.1.105 community 'shakapon'
set service snmp trap-target 192.168.1.105 port '162'
```

#### MIBの回収
VyOS の MIB はマニュアル通り機器から直接回収。

https://docs.vyos.io/en/equuleus/configuration/service/snmp.html

```shell-session
scp -r vyos@192.168.1.161:/usr/share/snmp/mibs /your_folder/mib
```

#### MIBの配備
VyOSのMIBを読み込めるよう、```snmp.conf``` を修正。SNMPTrapd はデフォルトでsnmp.confに記載されたMIBファイルを使用する。今回は```/usr/share/snmp/vyos_mibs```に配備した。

```diff_shell
vi /etc/snmp/snmp.conf
- mibs :
+ #mibs :
- mibdirs /usr/share/snmp/mibs:/usr/share/snmp/mibs/iana:/usr/share/snmp/mibs/ietf
+ mibdirs /usr/share/snmp/mibs:/usr/share/snmp/mibs/iana:/usr/share/snmp/mibs/ietf:/usr/share/snmp/vyos_mibs
```

### Zabbixの設定
実際にVyOS が飛ばしたSNMP Trap を Zabbix で受信させてみる。

#### ホスト設定
Zabbixトップ画面 → 設定 → ホスト → ホストの設定を選択して添付画像のように設定。インターフェースとしてSNMPを選択、SNMPコミュニティ名は直接記載してもよいが、マクロでの設定が推奨される。

![Zabbix_Host設定.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/409463/d3a98f63-ac36-b3f1-498b-74322eb2df1d.png)

#### アイテムの設定
Zabbixトップ画面→ 設定 → ホスト → ホスト（VyOS）の欄にあるアイテム → アイテムの作成と辿る。
すべてのSNMP Trapを受け取れるよう、キーとしてsnmptrap.fallbackを指定する。ログの時間の形式は実際のTrapログに依存して設定。

![アイテムの設定.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/409463/d385191c-0d81-5c66-2d90-bb6054987bae.png)

#### 実際にTrapを飛ばしてみる
VyOS上で適当な Port を閉塞してみる。
```shell-session
configure
set interfaces ethernet eth2 disable
commit
exit
```

Zabbixトップ画面 → 監視データ → 最新データ → ホスト/VyOS → SNMP Trap fallback →値 を選択して確認。これで飛んでいることが確認できた。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/409463/878c9d04-ecff-8815-b49b-4f02d832a6b1.png)