SNMP超入門

# はじめに
SNMP、それはネットワークやハードウェア機器の管理をするための仕組みです。オンプレミスからパブリッククラウドの時代になって登場回数は以前より減りましたが、昨今は**ハイブリッドクラウドの台頭**もあり物理ネットワークの管理でSNMPに遭遇することがあります。そこでSNMPについて質問を受けることが多かったため記事にしてみることにしました。
私がSNMPを覚えた頃(2006年くらい)は、まともな本というとオライリーの[SNMP入門](https://www.oreilly.co.jp/books/4873110904/)や、[マスタリングTCP/IP(SNMP編)](https://www.amazon.co.jp/dp/427406607X/)くらいしかなく、前者のオライリーの**入門が全く入門といえない内容**でした。それらの本を何度も読み返したり、MIBファイルと戯れて何とか理解した知識をお伝えできれば幸いです。

# SNMPとは何か
SNMP(Simple Network Management Protocol)はネットワーク機器やハードウェアを監視するためのプロコトルです。

- v1 の場合は[RFC1155/1157]
- v2cの場合は[RFC1901]
- v3 の場合は[RFC2273-2275])
※関連のRFCは上記にとどまらない。

ユーザが追加のソフトウェアを導入可能な汎用OSを有するサーバであれば監視製品のエージェントをインストールをした上で、同エージェントの機能によるプロセス監視やログ監視などを行い正常性を確認することができます。しかしながらハードウェア機器やネットワーク機器は**汎用OSではないため監視エージェントを追加できません**、そのため自身で監視をしてもらうための仕組みを持つ必要があります。そしてその監視機能というのは多くの監視マネージャで利用できる**互換性を有している必要**があります。
SNMPはそうした機能を標準の規格で提供するものです。
インフラエンジニアとして知っておくべきことを、ここでは説明したいと思います。

# SNMPの構成
SNMPは監視される側の機器をSNMPエージェント、監視をするための管理ソフトウェアをSNMPマネージャと呼びます。先述したようにSNMPエージェントはハードウェア、ネットワーク機器、アプライアンスなどが標準で備えています。Linuxなどにも「net-snmp」を導入することで使用することが可能です。

SNMPで監視できる項目は大きく2つに分かれます。
+ 標準: リンクアップ/リンクダウン/SNMPエージェントの再起動など決まった監視項目
+ 拡張: 特定機器のハードウェア状態、カスタムメッセージなどメーカー独自に実装された監視項目

実はSNMPは標準で監視できる項目がかなり少なく、また、実用的に使用しようとすると**かなり物足りない実装**になっています。例えば、ハードウェア機器のFANの回転数や、温度、バッテリの状態に代表されるハードウェア部品に関する監視項目は標準には実装されていないのです。実際に機器を監視する上では各ハードウェアベンダが独自実装した拡張項目を使用して監視をします。 
折角部品を冗長構成にしていたとしていたとしても**片系が壊れた時**にそれを知らなければ、当該ノードが死んだ時にしか気づけないと言うことが普通に起き得ます。
SNMPによる監視の本質は**機器を止めないための予兆検知**あります。

# SNMPの機能
SNMPには主に以下の機能があります。
- SNMPGet( Request)
- SNMPSet( Request)
- SNMPTrap

※snmpget/snmpgetおよびsnmptrapでは使用ポートがそれぞれUDP161、UDP162と異なります。ファイアウォールを経由する場合、前者はエージェント側の受信ポートを解放し、後者はマネージャ側の受信ポートを解放します。

SNMPGetはSNMPマネージャからSNMPエージェントに対して情報を取得します。動作は読み取りだけです。
SNMPSetはSNMPマネージャからSNMPエージェントに対して設定を行います。SNMPエージェント上で持っている値を書き換えます。
GetやSetなどのマネージャからエージェントへのアクセスをSNMPポーリングと呼ぶことがあります。
SNMPTrapは上記2つの動作と異なり、SNMPエージェントかSNMPマネージャにエージェントの情報を通知します。**push型のプロトコル**となります。
SNMPによる機器の正常性監視を行うためにはエージェント自身が不調を知らせる**trap機能が重要**になります。

SNMPGetにはNextやbulkなどといった派生的な機能があり、連続して情報を取得することができます(net-snmpのsnmpwalkコマンドで指定したOID配下すべての情報を取得できる)。

```
$ snmpget -c <communityname> <hostname or IPaddress> <OID>
※指定したOID単一の値を取得できる。

$ snmpwalk -c <communityname> <hostname or IPaddress> <OID>
※指定したOID配下の情報全てを取得できる。OIDを指定しないとその機器で取得でいるすべてのOIDの値が芋蔓式に引き出せる。こちらも構築後の試験などで取得しておくと何かの役に立つかもしれない。
```

TRAPを故意に通知させたい場合は当該ノードにログインしてみるか、以下のコマンドで間違ったコミュニティ名でsnmpgetをしてみると言うやり方があります。SNMPの単体試験をするときなどに参考ください。
```
$ snmpwalk -c <間違ったcommunityname> <IPaddress>
※authentication failure trapが飛ぶ。ただし、標準MIBのTRAPだと言うのに実装していないけしからん機器がいるため、別の手段も試してみること。
```

# OIDを理解する
SNMPはOID(Object ID)という単位で情報を保持しています。パブリッククラウドでいう**メトリックの概念にかなり近い**です。OIDはアドレスで管理され情の取得や設定値を挿入する際、キーバリュー型で言うキー指定の代わりにアドレスを指定します。
どこのアドレスに何のパラメタが格納されるかというのは **MIB(Management Information Base)** というものに定義されます。また、現在はMIB-2という規格が標準で使われています。先も述べましたが、MIBとOIDの関係性は標準で決まっているものと拡張されベンダ独自のものとに分かれます。

# MIBを理解する
MIBの理解はこのSNMPを理解する上でもっとも肝になる部分です。また、SNMPを学習する上で**一定以上のハードル**にもなり得ます。

まずは**MIBとOIDの関係性**について理解をしましょう。
OIDは当該機器のパラメタや情報の最小単位です。1つのOIDに1つの情報や設定が格納されます。キーバリュー型のデータベースやメトリックと同じものと考えて良いでしょう。
MIBはそれを取りまとめたものです。その機器で定義されているOIDがどのように実装されているか説明したものです。MIBはOIDの持つアドレスに名前を与え、階層が再起的に名前で記述されます。MIBファイルの中に名前とそれに対する数字と階層が入れ子のように記述されています。これがMIBファイルにとって可読性に悪影響をもたらしています。しかもMIBファイルはカテゴリによって複数に分かれており、ファイルごとに依存性があります。当該機器のMIBの全体像を把握するために複数MIBファイルの読み込みが必要になります。端的に言うと**とても読みづらい**です。

:::note
拡張MIBのOIDなら以下のような階層になっています。
iso(1) identified-organization(3) dod(6) internet(1) private(4) enterprise(1)

標準MIBであれば、上記の「private(4)」が別の数字に置き換わります。拡張MIBのOIDは必ず上記の形をしています。
:::

MIBはASN.1(Abstract Syntax Notation One: 抽象構文記法1)という情報の構造定義の言語で記述されます。 通信プロトコルのフォーマットを規定するための言語で、多くのプロトコルで使用されています。
OIDはサブツリー(.1.3.6.1.X.1...のような記述方法をとる)で構成され、上位から下位へアドレスが継承されます。
さらにMIBは複数ファイルに分かれて参照されることもあります。特定のOIDのアドレスを知りたいのに、複数ファイルに渡って読んでいかないとアドレスがわからないということがしばしば発生します。そして多くのSNMPマネージャはOIDの名前ではなくアドレスでOIDを指定します。
メジャーな製品であればOIDを一発で特定する裏技があります。それはOIDの名前でインターネット検索をすることです。結構な確率で**OIDのフルアドレス**を引くことができます。MIBファイルだけでOIDのフルアドレスを引くのは手間もかかるし、設定ミスの原因にもなりますためうまくインターネット上の情報を拾いましょう。

例えば以下のようなサイトでfortigateのMIB情報が公開されています。リンク先をご覧にいただけるとお分かりになると思いますが、いずれのOIDも **「.1.3.6.1.4.1.12356」から始まる**フルアドレスが並んでいると思います。.1.3.6.1.4.1までは拡張MIBとして決まった形をしており、12356はfortigateを表す**enterprise id**となります。
拡張MIBと格闘する上でこのアドレスの形は覚えておきましょう。というかいやでも覚えます。

https://mibs.observium.org/mib/FORTINET-FORTIGATE-MIB/

enterprise idは以下のようなサイトで探すことができます。この手のサイトは**結構な頻度で消える**ため、都度検索することをお勧めします。有名なもので言うとCisco Systems(現Cisco)の「9」でしょうか。ただこの数字は現在のCisco機器では使用されていないかもしれません。
ちょっとMACアドレスにおけるベンダーコードの趣を感じますね。

https://www.iana.org/assignments/enterprise-numbers/

MIBを構成するOIDのわかりづらさは以下にあります。
- 一見するとただの数字の羅列であるため何を意味するのかわからない
- OIDに入っている値だけで意味が理解できない

とはいえMIBファイルはその機器が有するOIDとその意味をユーザやSNMPマネージャに伝えるメッセージのような役割を果たします。よって**MIBが読み解ければOIDの意味**も読み解けます。しかしながら、RFCにおけるMIBの記述方法は必要最低限であり、ベンダごとの記述方法に差があります。場合によってはMIBだけだと何を意味しているのかわからないこともあります。
実装の違いの例を挙げてみましょう。

:::note
機器A: 1
機器B: up
:::

:::note
機器A: 0
機器B: down
:::

上記はインタフェースが接続されたおよび切断されたことを示すOIDを比較したものです。
機器Aだと数字だけがOIDに挿入されます。これだけだとupなのかdownなのかそれ以外なのか判断ができません。
機器Bですと挿入された値だけでupかどうか読み取れます。
機器Aの場合はこれだけみても意味不明なので、MIBファイルによって解決します。MIBファイルには1が挿入された場合の意味が書かれていることがあります。SNMPマネージャに事前にMIBファイルが登録されていると1が自動的にupに変換されます。
機器Bの場合は少なくともこの値にはMIBファイル登録による恩恵はないですがOIDが意味の名前に置き換わる(機器Aも同様にOIDに名前が付与される)ため、**MIBファイルをSNMPマネージャに登録**は必ずしましょう。

SANスイッチで有名なbrocade(現Broadcom)などは**とても親切**な[SNMP解説書](https://techdocs.broadcom.com/us/en/fibre-channel-networking/fabric-os/fabric-os-mib/9-2-x.html)を用意してくれており、MIBと合わせてそちらを読むとかなり理解が進みます。ただし、そんな製品は稀です。ほとんどがMIB(ファイル)しか用意されておらず、運が良ければコメントで説明をわかりやすく書いてくれている程度です。

※軽く検索してみると最近はCiscoも同種のマニュアルを用意してくれているようです。私がCisco機器を触っていた頃はなかったような。

ここでいうわかりやすいとは何かというと、MIBファイルなどでOIDに**どのような値が入るか説明**してくれているかです。
例えばインタフェースの状態を表すOIDであれば少なくともup/downかそれを意味する数字が挿入されることが想像つきますが、FRUエラーの機器IDなどは何がFRUとして定義されているかを事前に知らなければなりません。
マイナー機器のMIBファイルになると何の値がくるか説明されないことなど普通にあります。そして、それはRFCには規定されておらず義務ではないわけです。よって、OIDに付けられた**それらしい名前から想像する**しかないわけです。

翻ってパブリッククラウドのメトリックはどうでしょうか。・・・私が知る限りわかりやすい名前がついており、それが何を意味をしているかメトリック名から容易に推測ができ、かつ説明もマニュアルや設定時のUIに載せてくれています。そもそもOIDのようなアドレス(数字の羅列)も意識しません。
どメジャー機器以外の**SNMPによる監視は茨の道**です。みんながよく使っている某社のストレージ製品ですらSNMP監視のベストプラクティスは探しても見つかりません。それでも私たちはSNMPによる監視を避けて通れません。

# SNMP Trap MIB
GetやSetで利用されるOIDと異なりMIBの中で異彩を放つのが**Trap MIB**です。Trap専用のOIDが用意されており、その実態は複数の**OBJECT-TYPE**のOIDの集まりです。OIDの順番によって変数1、変数2、変数n... と並んでいます。SNMPマネージャの設定時にいきなり変数という言葉が登場してきて何これ? となる方も多いと思いますが、TRAP-TYPEのOIDの中に格納されている**複数OBJECT-TYPEのOID**と連動しているということ覚えておくとMIBが少し読みやすくなります。

※OBJECT-TYPEはsnmpget/setでも参照/設定される単一の値を格納したOIDです。

ちなみに、このTRAP-TYPEですがSNMPバージョンによって以下の通り名称が変わります。
- SNMPv1 TRAP-TYPE
- snmpv2c/v3 NOTIFICATION-TYPE

TRAP-TYPEを検索して見つからないって時はその機器がそもそもv1に対応しておらず**NOTIFICATION-TYPEの記載しかない**からです。
また、このTRAP-TYPEとNOTIFICATION-TYPEは名前が異なるだけではなくTRAP-TYPE側にだけ**TRAP番号**という概念があります。わかりづらいにも程があります。snmpv1で利用されるTRAP-TYPEはTRAP番号と組み合わせて初めてユニークなTRAPとして特定できます。

# SNMPバージョンについて
現在SNMPのバージョンは以下に分かれます。
- v1
- v2c
- v3

ざっくり言うとv2cはSNMPtrapによる再送確認(informs)ができるようになったことと**MIBの記述方法が再整理**されました。v3は**認証機能が強化**されSNMP最大の問題であるパスワード的扱いの**コミュニティ名が平文で流れてしまうという実装が回避**されています。MIBの実装はv2cと大きく変わっていません。

※informsの説明は後述します。

SNMPバージョンについては以下の記事がわかりやすいです。

https://www.infraexpert.com/study/tcpip21.5.html

# SNMPの認証について
以下の通りバージョンによって異なります。
- v1/v2c コミュニティ名による認証
- v3 ユーザ名とパスワード認証と認証暗号化/データ暗号化の実装

v1/v2cで利用されるコミュニティ名はパスワードのような扱いです。しかもコミュニティ名はネットワーク上を平文で流れていきます。
v3で利用される認証は以下に分かれます。
- ユーザID/パスワード認証の暗号化
- 通信データの暗号化

前者はID、パスワードの指定とともにその認証情報そのものの暗号化方式を指定します。正確にはMD5などに代表されるハッシュ化方式です。
後者は通信データの暗号化方式をします。暗号化はAESなどに代表される共通鍵暗号化方式です。認証後に共通鍵を相手に安全に渡してデータ通信を確立するのでしょう。
とはいえ、v3でもパスワード認証や暗号化を避けた実装ができます。マネージャでv3の**実装が完全でないものがあるため、互換性確保**のためでしょうか。
余談ですが、クレジットカード業界のセキュリティ標準である**PCI DSS** (Payment Card Industry Data Security Standard) では**v3の利用が原則必須**となっています。
PCI DSSは抽象度がそこそこ高く難解な規格ですが以下のサイトの説明がわかりやすいです。

https://www.intellilink.co.jp/column/pcidss.aspx

# SNMP TRAPとSNMP INFORMSの関係について
SNMPを擁する**トランスポート層はUDP**であり、コネクションレス型となりパケットの**到着を保証しません**。投げたら投げっぱなしで、もしかしたら途中でパケットが欠損し、届かないと言うこともあり得ます(しばらく通信していないとMACアドレステーブルの再学習などで簡単にUDPパケットが落ちます)。そのため機器によっては最低3回投げるなどの対策を講じていました。
SNMP INFORMSはそれの対策で**エージェントから応答を要求**しマネージャ側から送達確認のパケットを返送することでそれを実現します(返送がない場合、エージェントからtrapを再送する)。回線品質の高いLANよりは回線品質に一定のばらつきのあるWAN向けの機能と考えています。

# SNMPマネージャにMIBを登録すればゴールなのか
**結論だけ言うと否**です。
これまで散々語ってきた通りMIBの記述・実装は**ほとんどの機器で不親切**です。MIBに従って飛んできたSNMPTRAPを読み取ろうとしても結局何が起こっているのかわからないことがほとんどです。
MIBのマネージャへの登録は必須事項です。OIDに格納されている値が数字だけと言うこともざらです。OIDもMIBを登録しないとただの数字の羅列です。そのため、最低限の意味を読み取ると言う意味で監視マネージャへのMIBの登録を第1段階として行います。
そしてSNMPマネージャの追加設定として、以下の設定を監視マネージャに**監視したいTRAP単位**で施します。
- 具体的なTRAPの意味の解説
    → 具体的に何の問題なのか。どこが壊れているのか。
- 当該TRAPを受信した際のオペレータに対するアクション
    → 部品の交換の手配をするのか、上級SEにエスカレーションを上げるのかなど。

**これを言いたいがためにこの記事を挙げている**ようなものです。
再度言います。MIBファイルを監視マネージャに登録しておしまいではありません。MIBを登録した上で監視マネージャに監視必須のOIDにだけ運用オペレータにも伝わるアクションを説明したメッセージを登録するのです。**他の項は全部忘れて良い**のでこれだけはどうかこの記事の中で覚えておいてください。

# SNMPで何を監視するか
製品によって一律な正解はないですが、**最低限これは監視すべき**というものを例示できます。**それがなければこの記事の価値は無い**です。
以下、ご参考ください。ほとんどが拡張MIBによる実装になるため、機器によっては存在すらしない項目もあります。
- 障害検知
    - 電源・電圧
    - FAN
    - 温度
    - FRU(取り外せる部品の正常性)
    - インタフェースup/down
    - クラスタノードの切り替え
    - 負荷分散装置のプールメンバの消失など

- 性能
    - CPU使用率
    - メモリ使用率
    - ネットワーク帯域
    - パケットドロップなど

- 監査
    - ログイン・ログアウト・ログイン失敗
    - 予期しない設定変更

- セキュリティ
    - get/setコミュニティ名不正
        → 機器に不正アクセスされている可能性があります。
    - 通信制御(deny通信の頻出など)
    - IPS/IDS/WAFなどの遮断動作など

- その他
    - メッセージ
        → syslogと同等の内容が得られる場合がある。こればかりは本当に機器の実装に依存する。一緒に**severity(重要度)が変数に格納**される実装が多いため、**WARN以上**を監視マネージャに監視させることをお勧めします。

# 最後に
いかがでしょうか。
私がSNMPを学ぶ上で理解に苦労した点を中心に項目を挙げてみました。パブリッククラウドが当たり前の世界になりましたが、まだまだ物理のハードウェア機器に触れる機会もあると思います。
そしてそれらの監視実装の中心にSNMPがいます。この記事がこれからSNMPを触れる方の一助となれば幸いです。

以上