воскресенье, 25 сентября 2016 г.

Стандарт SNMPv3 и суровая действительность USM_TIME_WINDOW

В прошлой статье Zabbix и проблемы с опросом по SNMPv3 при дублировании EngineID я описал решение первой проблемы, возникшей при внедрении SNMP третьей версии. После этого я столкнулся с ещё одной проблемой, которую исправлял в два подхода.

D-Link не соблюдает стандарт RFC3414

Дело в том, что даже после исправления EngineID на всех коммутаторах, на некоторых коммутаторах проблема повторялась. После перезагрузки коммутатора, Zabbix считал коммутатор недоступным по SNMP. Если разбираться глубже, с помощью приведённых в прошлой заметке OID'ов, то оказывается, что на коммутаторе после перезагрузки значение EngineBoots остаётся прежним или даже уменьшается! Первым делом были проверены версии прошивок - возможно эта проблема уже была исправлена и надо только обновить прошивку. Но оказалось, что прошивки на проблемных коммутаторах были самые свежие. Поискал в интернете, сталкивался ли кто-нибудь с подобной проблемой, и нашёл аж три темы, в которых открытым текстом утверждается, что эта проблема известна производителю и исправлять он её не собирается:
Поразмыслив, я решил, что можно было бы отключить проверку монотонности возрастания EngineBoots. В конце концов, лучше использовать SNMP третьей версии без защиты от повторного воспроизведения запросов, но зато с более безопасной аутентификацией и с защитой информации от подслушивания, чем вернуться к использованию SNMP второй или первой версии и передавать по сети в открытом виде и строку сообщества и сами запросы и ответы. Решено - будем править библиотеку.

Подготовка к пересборке Net-SNMP

Для начала отредактируем файл /etc/apt/sources.list и добавим строчки с репозиториями deb-src с исходными текстами:
deb http://mirror.ufanet.ru/debian/ wheezy main contrib non-free
deb http://mirror.ufanet.ru/debian/ wheezy-updates main contrib non-free
deb http://mirror.ufanet.ru/debian/ wheezy-proposed-updates main contrib non-free
deb http://mirror.ufanet.ru/debian-security wheezy/updates main contrib non-free

deb-src http://mirror.ufanet.ru/debian/ wheezy main contrib non-free
deb-src http://mirror.ufanet.ru/debian/ wheezy-updates main contrib non-free
deb-src http://mirror.ufanet.ru/debian/ wheezy-proposed-updates main contrib non-free
deb-src http://mirror.ufanet.ru/debian-security wheezy/updates main contrib non-free
Обновим список доступных пакетов, чтобы можно было скачать из вновь подключенных репозиториев пакеты с исходными текстами:
# apt-get update
Скачаем и распакуем исходные тексты, а затем перейдём в каталог с распакованными исходными текстами:
$ apt-get source snmp
$ cd net-snmp-5.4.3~dfsg/
Описание исправлений, внесённых в Net-SNMP

Поиск показал, что константа USM_TIME_WINDOW со значением 150 используется только в файле snmplib/snmpusm.c. Первым делом я нашёл строчку, в которой проверяется, что значение EngineBoots должно быть больше или равно значению из кэша:
if (theirBoots == ENGINEBOOT_MAX || theirBoots > boots_uint) {
Если значение EngineBoots не изменилось, то используются значение EngineTime, сохранённое в кэше. Если значение стало больше, то новые значения EngineBoots и EngineTime сохраняются в кэш. Если значение уменьшилось, то запрос завершается ошибкой SNMPERR_USM_NOTINTIMEWINDOW.

Это строчку я исправил следующим образом:
if (theirBoots == ENGINEBOOT_MAX) {
То есть при любом изменении значения EngineBoots новое значение будет сохранено в кэш для дальнейшего использования.

После этого я проделал описанные ниже процедуры по сборке пакета, установил исправленный пакет в систему и перезапустил Zabbix. Прошла пара дней, после чего стало понятно, что это исправление учитывает не все возможные случаи. Некоторые коммутаторы после перезагрузки всё-таки переставали опрашиваться.

Детальное изучение проблемы показало, что при перезагрузке значение EngineBoots у них не изменилось, зато EngineTime становилось меньше прошлого, т.к. отсчёт времени после перезагрузки начинался с нуля. В этом случае вступал в силу другой фрагмент кода, который при равенстве полученного значения EngineBoots и имеющегося в кэше проверяет соответствие времени. Если время из ответа больше расчётного, то библиотека запоминает новое значение времени в кэше и принимает ответ. Если время из ответа отстаёт от расчётного менее чем на 150 секунд, то такой ответ тоже принимается. Если же время из ответа отстаёт от расчётного более чем на 150 секунд, то ответ отбрасывается, а запрос завершается всё той же ошибкой SNMPERR_USM_NOTINTIMEWINDOW. Этот фрагмент кода выглядит следующим образом:
/*
 * Boots is ok, see if the boots is the same but the time
 * is old.
 */
if (theirBoots == boots_uint && time_uint < theirLastTime) {
        if (time_difference > USM_TIME_WINDOW) {
                DEBUGMSGTL(("usm", "%s\n", "Message too old."));
                *error = SNMPERR_USM_NOTINTIMEWINDOW;
                return -1;
        }
        else {              /* Old, but acceptable */
                *error = SNMPERR_SUCCESS;
                return 0;
        }
}
Его я исправил следующим образом:
/*
 * Boots is ok, see if the boots is the same but the time
 * is acceptable old.
 */
if (theirBoots == boots_uint && time_uint < theirLastTime && time_difference < USM_TIME_WINDOW) {
        *error = SNMPERR_SUCCESS;
        return 0;
}
Снова собрал пакет, установил его в систему и перезапустил Zabbix. Через несколько дней стало понятно, что это исправление помогло и опрос по SNMP третьей версии теперь продолжает работать даже после перезагрузок коммутаторов, когда значение EngineBoots не меняется или меняется в меньшую сторону. Был достигнут неприятный компромисс, на который пришлось пойти ради общего увеличения безопасности системы.

Сборка исправленных пакетов Net-SNMP

Теперь уже, когда в деталях раскрыта подноготная исправлений, опишу до конца процесс сборки пакета.

Скачиваем и устанавливаем пакеты, которые используются в процессе сборки Net-SNMP:
# apt-get build-dep snmp
Скачиваем патч:
$ wget http://stupin.su/files/netsnmp543_snmpv3.diff
Тут же, если вы используете библиотеку Net-SNMP из Python, можно скачать ещё один патч, описанный в заметке Исправление Python-прослойки библиотеки Net-SNMP:
$ wget http://stupin.su/files/netsnmp543_python_client.diff
Теперь перейдём в каталог с исходными текстами и наложим наши патчи:
# cd net-snmp-5.4.3~dfsg/
# patch -Np0 --ignore-whitespace < netsnmp543_snmpv3.diff
# patch -Np0 --ignore-whitespace < netsnmp543_python_client.diff
Добавим наши патчи в будущий пакет:
# dpkg-source --commit
Укажем имя патча snmpv3-python_client. В окне редактирования информации о патче введём что-нибудь подобное следующему (вплоть до двух нижних строчек, с которых начинается сам текст патча):
Description: Fixed Python bindings and SNMPv3 time window logic
Author: Vladimir Stupin <vladimir@stupin.su>
Last-Update: <2016-09-06>
--- net-snmp-5.4.3~dfsg.orig/python/netsnmp/client_intf.c
+++ net-snmp-5.4.3~dfsg/python/netsnmp/client_intf.c
Теперь отметим изменения, внесённые в пакет:
# dch -i
В окне редактирования введём информацию о нашей версии пакета:
net-snmp (5.4.3~dfsg-2.8+deb7u2) UNRELEASED; urgency=low

* Fixed Python bindings for IPv4 parameter in SET-requests
* Fixed SNMPv3 time window logic

-- Vladimir Stupin <vladimir@stupin.su>  Tue, 06 Sep 2016 16:01:20 +0500
Осталось собрать пакеты:
# dpkg-buildpackage -us -uc -rfakeroot
Теперь можно установить необходимые пакеты в систему:
# cd ..
# dpkg -i libsnmp-base_5.4.3~dfsg-2.8+deb7u2_amd64.deb
# dpkg -i libsnmp15_5.4.3~dfsg-2.8+deb7u2_amd64.deb
# dpkg -i snmp_5.4.3~dfsg-2.8+deb7u2_amd64.deb
# dpkg -i libsnmp-python_5.4.3~dfsg-2.8+deb7u2_amd64.deb
Python и SNMPv3 в Net-SNMP

Двух пересборок пакетов, на самом деле, оказалось недостаточно. Дело в том, что модуль netsnmp для Python не работает с SNMP третьей версии. Как оказалось, при попытке выполнить из программы на Python запроса SNMP с настройками третьей версии, библиотека "молчит" - в сеть не уходит ни единый пакет. В то же время я вспомнил, что на одном из серверов под управлением FreeBSD всё работало превосходно. Сразу же в глаза бросилось различие в версиях Net-SNMP во FreeBSD на том сервере и на сервере под управлением Debian Wheezy. Во FreeBSD был установлен Net-SNMP версии 5.7.2, а в Debian - 5.4.3. Чтобы проверить свои предположения о том, что этот функционал был исправлен в версии 5.7.2, я воспользовался Net-SNMP из Debian Jessie. Набросал небольшую тестовую программку на Python, запустил - всё отработало на ура.

После этого я заменил в файле /etc/apt/sources.list репозитории deb-src с релиза Wheezy на релиз Jessie и повторил проделанные выше операции, получив таким образом пропатченный бэкпорт Net-SNMP из Jessie для Wheezy. Дело, однако, этим не ограничилось. В бэкпорте вместо библиотеки libsnmp15 была библиотека libsnmp30, а пакет libsnmp-python был переименован в python-netsnmp. К библиотеке libsnmp15 были привязаны Zabbix и PHP5. Пришлось пересобрать и их, в том числе с использованием моих патчей Zabbix, описанных в заметке Установка и настройка Zabbix 2.2.0 в Debian Wheezy.

Патчи, адаптированные для Net-SNMP версии 5.7.2.1 из Jessie, можно взять по следующим ссылкам:
Мне невероятно "везёт" с программами, которыми я пользуюсь. Или просто я слишком часто стал заходить на никем ещё не топтанные дорожки?

воскресенье, 18 сентября 2016 г.

Zabbix и проблемы с опросом по SNMPv3 при дублировании EngineID

В прошлой заметке Системы мониторинга, SNMPv3 и engineID я опубликовал перевод статьи Михаэля Шварцкопфа Monitoring Systems, SNMPv3 and the engineID. В этой заметке я поделюсь своим пониманием проблемы, с которой столкнулся автор, а затем расскажу о своём опыте решения подобных проблем с коммутаторами D-Link.

Обсуждение статьи

В SNMPv3 у каждого агента имеется свой уникальный идентификатор. При первом обращении к агенту станция управления выполняет так называемую процедуру обнаружения - отправляет ему пустой запрос. Агент отвечает на этот запрос, сообщая свой уникальный идентификатор - EngineID, количество перезагрузок агента - EngineBoots и время, прошедшее с момента последней перезагрузки агента - BootTime. Станция управления запоминает количество перезагрузок агента - EngineBoots и время, прошедшее с момента последней перезагрузки агента - EngineTime, в специальном кэше. В качестве ключа для поиска по этому кэшу используется идентификатор агента - EngineID.

Этот кэш нужен во-первых для того, чтобы уменьшить количество паразитных процедур обнаружения. В следующий раз можно будет взять хранящиеся в кэше значения, посчитать текущее время на агенте и отправить ему запрос. Во-вторых, приходящие ответы будут проверяться на соответствие значениям, хранящимся в кэше. Это позволяет защититься от атак повторного воспроизведения запросов, когда некто может попытаться сохранить запрос от системы управления и отправить агенту этот запрос позже. Было бы неприятно, если бы кто-то смог перехватить, например, команду SNMP SET, которая отключает порт на коммутаторе, и потом мог бы применять её впоследствии в любое время и любое количество раз. Проверка своевременности не позволит такому злоумышленнику развлекаться этой командой дольше 150 секунд.

Что произойдёт, если у нескольких устройств настроены одинаковые EngineID? В кэше будут сохраняться значения EngineBoots и EngineTime от одного устройства, а потом эти же значения будут использоваться для отправки запросов к другому устройству. Другое устройство обнаружит, что значения EngineBoots и EngineTime из полученного им запроса не его, и в соответствии с принципами защиты от атак повторного воспроизведения запросов отправит в ответ OID .1.3.6.1.6.3.15.1.1.2.0 - usmStatsNotInTimeWindows, сообщающий о том, что время из запроса не попало в приемлемое окно времени. Станция управления выполнит процедуру обнаружения и если EngineBoots из ответа второго устройства оказалось больше, то обновит значения в кэше. Если EngineBoots окажется равным хранящемуся в кэше, то сравнит EngineTime из кэша и из ответа - если EngineTime окажется больше, то обновит значение в кэше. Теперь на запросы будет отвечать только то устройство, которое больше раз перезагружалось или, при равных значениях, у которого с момента загрузки прошло больше времени. На всех остальных устройствах будет постоянно срабатывать защита от повторного воспроизведения запросов.

В случае Zabbix ситуация немного усугубляется ещё и тем, что библиотека NET-SNMP - однопоточная и не предусматривает возможность сохранения и восстановления контекста библиотеки. Возможно именно поэтому Zabbix был сделан не многопоточным, а многопроцессным. В результате у каждого процесса Poller, занимающегося пассивными проверками, имеется собственный кэш библиотеки SNMP. Каждый процесс поэтому выполняет собственную процедуру обнаружения, хотя в одном из соседних процессов в кэше уже могут быть нужные актуальные данные.

Поэтому не надо удивляться тому, что утилиты командной строки snmpget и snmpwalk работают без ошибок при каждом запуске, даже если у двух устройств одинаковый EngineID. Эти утилиты при каждом запуске выполняют процедуру обнаружения, наполняют кэш полученными значениями, выполняют запрос и тут же завершаются. При завершении утилиты пропадает и её кэш.

Проблема автора, видимо, заключалась в том, что у него на двух разных устройствах оказался одинаковый EngineID. После указания опции engineIDType 3 на устройствах были установлены EngineID, сгенерированные из MAC-адресов устройств. MAC-адреса должны быть уникальными (хотя на практике иногда случаются исключения), поэтому опция решила проблему. Приведённый же в статье протокол сниффера скорее всего отобразил два разных запроса от двух разных процессов Poller, с разными кэшами библиотеки SNMP. Один процесс имел пустой кэш и отправил запрос обнаружения, а второй процесс уже обладал ранее наполненным кэшем и отправил запрос используя старые значения из кэша. Автор же статьи, скорее всего, просто не разобрался в происходящем. Во всяком случае то, что проблема исправилась после переназначения EngineID свидетельствует именно в пользу версии о двух одинаковых EngineID на разных устройствах.

Замена EngineID на коммутаторах D-Link

Лично мне пришлось столкнуться с проблемой одинаковых EngineID на коммутаторах. Дело в том, что идентификатор сохраняется в файле конфигурации коммутатора. Если при настройке нового коммутатора за основу взять файл конфигурации с имеющегося коммутатора, то EngineID продублируется. Для просмотра текущего значения EngineID на коммутаторах D-Link можно воспользоваться такой командой:
show snmp engineID
Для замены EngineID на коммутаторах D-Link используется такая команда:
config snmp engineID <snmp_engineID 10-64>
Некоторые модели коммутаторов D-Link поддерживают такую команду:
config snmp engineID default
Наконец, после замены нужно сохранить изменённый файл конфигурации:
save config

Как сгенерировать EngineID из MAC-адреса

Если посмотреть в RFC5343, 4. IANA Considerations, то можно прочитать, по какому принципу следует формировать EngineID из MAC-адреса. Чтобы сформировать EngineID на основе MAC-адреса, нам потребуется дополнительно IANA-номер, закреплённый за производителем устройств. Определить номер IANA можно запросив у устройства OID SNMPv2-MIB::sysObjectID.0 - 1.3.6.1.2.1.1.2.0 при помощи такой команды:
$ snmpget -On -v 2c -c public 192.168.0.2 1.3.6.1.2.1.1.2.0
.1.3.6.1.2.1.1.2.0 = OID: .1.3.6.1.4.1.171.10.101.1
В выводе команды я подсветил IANA-номер, закреплённый за производителем D-Link. Если перевести число 171 в шестнадцатеричную систему счисления, то получим число AB. Первые четыре октета представляют собой именно это число, но с единичным старшим битом:
80 00 00 AB
Дальше следует один октет, в котором закодирован тип остальной части идентификатора. Если EngineID формируется на основе MAC-адреса, то этот октет будет иметь такое значение:
03
Наконец, оставшиеся 6 октетов будут соответствовать октетам MAC-адреса. Например:
28 10 7B 01 2B 7B
Итак, коммутатору D-Link с MAC-адресом 28:10:7B:01:2B:7B будет соответствовать следующий EngineID:
80 00 00 AB 03 28 10 7B 01 2B 7B

Диагностика проблем

Для диагностики подобных проблем можно просмотреть ветку 1.3.6.1.6.3.10.2.1:
$ snmpwalk -v 2c -c public 127.0.0.1 1.3.6.1.6.3.10.2.1
SNMP-FRAMEWORK-MIB::snmpEngineID.0 = Hex-STRING: 80 00 1F 88 80 F3 F2 FA 22 48 AF 91 54 00 00 00 00 
SNMP-FRAMEWORK-MIB::snmpEngineBoots.0 = INTEGER: 72
SNMP-FRAMEWORK-MIB::snmpEngineTime.0 = INTEGER: 6 seconds
SNMP-FRAMEWORK-MIB::snmpEngineMaxMessageSize.0 = INTEGER: 1500
В выводе команды можно увидеть текущие значения EngineID, EngineBoots и EngineTime.

Вот так поменялся EngineID после добавления опции engineIDType 3 в /etc/snmp/snmpd.conf:
$ snmpwalk -v 2c -c public 127.0.0.1 1.3.6.1.6.3.10.2.1
SNMP-FRAMEWORK-MIB::snmpEngineID.0 = Hex-STRING: 80 00 1F 88 03 00 1D 60 01 2B 7B 
SNMP-FRAMEWORK-MIB::snmpEngineBoots.0 = INTEGER: 1
SNMP-FRAMEWORK-MIB::snmpEngineTime.0 = INTEGER: 3 seconds
SNMP-FRAMEWORK-MIB::snmpEngineMaxMessageSize.0 = INTEGER: 1500
Как можно заметить, количество загрузок агента EngineBoots уменьшилось - это произошло потому что изменился EngineID и отсчёт был начат с начала.

Дополнительно в диагностике может помочь ветка 1.3.6.1.6.3.15.1.1:
$ snmpwalk -v 2c -c public 127.0.0.1 1.3.6.1.6.3.15.1.1
SNMP-USER-BASED-SM-MIB::usmStatsUnsupportedSecLevels.0 = Counter32: 0
SNMP-USER-BASED-SM-MIB::usmStatsNotInTimeWindows.0 = Counter32: 0
SNMP-USER-BASED-SM-MIB::usmStatsUnknownUserNames.0 = Counter32: 0
SNMP-USER-BASED-SM-MIB::usmStatsUnknownEngineIDs.0 = Counter32: 0
SNMP-USER-BASED-SM-MIB::usmStatsWrongDigests.0 = Counter32: 0
SNMP-USER-BASED-SM-MIB::usmStatsDecryptionErrors.0 = Counter32: 0
Здесь можно увидеть, сколько раз к агенту обращались с неподдерживаемым уровнем безопасности, в скольких запросах встречалось неприемлемое время, сколько раз обращались с неизвестными именами пользователя или чужими значениями EngineID, сколько раз происходили ошибки аутентификации и сколько раз не удавалось расшифровать данные из запроса.

В следующей заметке я расскажу о более глубоких проблемах, возникших при внедрении SNMPv3.

воскресенье, 11 сентября 2016 г.

Системы мониторинга, SNMPv3 и engineID

Перевод: Monitoring Systems, SNMPv3 and the engineID
Автор: Михаэль Шварцкопф (Michael Schwartzkopff)

Иногда шифрованные запросы SNMPv3 от системы сетевого мониторинга (NMS - Network Monitoring Systems) к устройствам совершенно неожиданно перестают работать. Нет никаких видимых причин, объясняющих это поведение. В этой статье я опишу проблему, с которой я столкнулся в Zabbix, поразмышляю о причинах и покажу обходной путь (или решение, если вам так угодно). Решение помогло мне, но я не уверен, что нашёл настоящую причину проблемы. По крайней мере, решение устраняет проблему, демонстрирующую странное поведение сервера Zabbix и наблюдаемого устройства. Но проблема встречается не только в системе сетевого мониторинга Zabbix - я также замечал её и в системе CA Spectrum.

SNMPv3

Более 10 лет SNMPv3 - единственный актуальный стандарт SNMP. Старые версии - SNMPv1 и v2c - считаются устаревшими, однако эти версии по-прежнему используются для управления большинством сетевых устройств.

SNMPv3 предоставляет полный комплект средств для обеспечения безопасности на основе пользователей (USM - User-based Security Model) и для управления доступом на основе представлений (VACM - View Access Control Model). Эти средства позволяют ограничить доступ аутентифицированных пользователей к информации, которую они авторизованы видеть. И конечно, все запросы от станции управления к агенту могут быть аутентифицированы и, если нужно, зашифрованы. В большинстве случаев достаточно аутентифицировать трафик мониторинга во внутренней сети, но если трафик проходит через внешнюю сеть (то есть интернет), его стоит также зашифровать. SNMPv3 предоставляет все эти возможности.

engineID

Каждая сущность SNMPv3 имеет собственный идентификатор - так называемый engineID. Это уникальный номер каждого контекста, с которым работают агенты. Но в большинстве устройств запущен только один SNMP-агент, поэтому каждое устройство имеет единственный engineID. В RFC 3411 имеется раздел snmpModules.10 (страница 40), в котором описывается способ формирования engineID. Если трафик шифруется, то engineID используется алгоритмом шифрования, поэтому зашифрованные данные разных устройств отличаются друг от друга.

Поскольку изначально станция управления не знает значения engineID агента на управляемом устройстве, в RFC 5343 описан способ первоначального обнаружения engineID.

Защита от повторного воспроизведения

Стандарт SNMPv3 также защищает обмен информацией от атак повторного воспроизведения, когда злоумышленник записывает пакеты и позже отправляет их повторно в сторону станции-получателя, чтобы спровоцировать какую-то реакцию. Для защиты станция управления сначала спрашивает у агента, сколько раз он уже перезагружался (snmpEngineBoots) и как много времени прошло с момента последней перезагрузки (snmpEngineTime). Станция управления шифрует данные вместе с количеством загрузок и временем, прошедшим с момента последней загрузки агента. Агент может правильно расшифровать пакет только если его время сочетается со временем поступления запроса. Отметим, что в SNMPv3 используется не абсолютное время, а относительное время кадра. Станция управления может принять информацию от контролируемого устройства, даже если время на обеих системах не совпадает.

Обмен информацией

Обмен информацией при включенном шифровании SNMPv3 выглядит следующим образом:
Станция управления -> агенту: Какой у тебя engineID?
Агент -> станции управления: Мой engineID равен ... Мой SNMP-агент перезагружался x раз и с момента последней загрузки прошло y секунд.
Станция управления -> агенту: Какая у тебя загрузка процессора, зашифрованная вместе с engineID, snmpEngineBoots и snmpEngineTime?
Агент -> станции управления: Загрузка процессора равна x, зашифровано вместе с engineID, snmpEngineBoots и snmpEngineTime.
Как можно видеть, любая проблема с интерпретацией engineID, snmpEngineBoots или snmpEngineTime приводит к ошибке обмена зашифрованными данными.

Zabbix

Zabbix - это система мониторинга, поддерживающая протокол SNMP. И разумеется, она поддерживает протокол версии 3. В Zabbix нужно просто настроить пользователя SNMP, пароль для аутентификации и пароль для шифрования. Имя пользователя и пароли можно настроить через макросы в определении сетевого узла. Использование макросов облегчает повторное использование шаблонов узлов, параметры которых могут различаться.

Симптомы

Проблемы начинаются с того, что внезапно обнаруживается устройство, не отвечающее на зашифрованные запросы SNMPv3 от системы Zabbix. При проверке настроек SNMP при помощи snmpget или snmpwalk из командной строки сервера мониторинга проблем не обнаруживается. Все запросы из командной строки завершаются успешно.

Теперь запустим tcpdump, чтобы проверить обмен данными построчно. В первом пакете станция управления запрашивает у агента его engineID:
07.406643 IP (tos 0x0, ttl 53, id 0, offset 0, flags [DF], proto UDP (17), length 92)
  manager.37780 > agent.161: [udp sum ok] { SNMPv3 { F=r } { USM B=0 T=0 U= }
  { ScopedPDU E= C= { GetRequest(14) R=537447614 } } }
Как можно увидеть, в запрос не включается имя пользователя (U=), количество загрузок равно нулю (B=0), как и время с момента последней загрузки (T=0). В следующем пакете агент предоставляет станции управления необходимую информацию:
07.408916 IP (tos 0x0, ttl 64, id 0, offset 0, flags [DF], proto UDP (17), length 143)
  agent.161 > manager.37780: [udp sum ok] { SNMPv3 { F= } { USM B=28 T=27 U= }
  { ScopedPDU E= 0x800x000x1F0x880x800x8E0xE50xD80x7B0x120x0C0x330x520x000x000x000x00
    C= { Report(31) R=537447614 .1.3.6.1.6.3.15.1.1.4.0=1 } } }
Агент сообщает станции управления свой engineID, что он загружался уже 28 раз, а с момента последней загрузки прошло 27 секунд. И теперь станция управления ведёт себя совершенно странно. В следующей строке можно увидеть такой пакет:
07.427289 IP (tos 0x0, ttl 53, id 0, offset 0, flags [DF], proto UDP (17), length 177)
  manager.37780 > agent.161: [udp sum ok] { SNMPv3 { F=apr } { USM B=27 T=178 U=user }
  { ScopedPDU [!scoped PDU] (encrypted data) } }
Можно увидеть, что станция управления отправляет в запросе 27 загрузок и 178 секунд с момента последней загрузки, что не соответствует их текущим значениям. Агент сообщил о 28 загрузках и 27 секундах, что в два раз меньше прошлого значения. И конечно, агент отвечает следующим образом:
07.429382 IP (tos 0x0, ttl 64, id 0, offset 0, flags [DF], proto UDP (17), length 163)
  agent.161 > manager.37780: [udp sum ok] { SNMPv3 { F=a } { USM B=28 T=27 U=user }
  { ScopedPDU E= 0x800x000x1F0x880x800x8E0xE50xD80x7B0x120x0C0x330x520x000x000x000x00
    C= { Report(28) R=0 .1.3.6.1.6.3.15.1.1.2.0=1 } } }
Этим OID'ом агент сообщает станции управления, что запрошенный PDU не может быть расшифрован, потому что окно приемлемого времени уже прошло.

Как я написал выше, тот же SNMP-запрос из командной строки работает отлично. SNMP-запрос с аутентификацией, но без шифрования тоже работает. Я встречал эту проблему в Zabbix, установленном на сервере Linux и на Spectrum-сервере в Windows-окружении. Со стороны агента были Cisco IOS, Cisco Nexus или Linux-компьютер с установленным net-snmp.

Причина

Похоже, Zabbix-сервер неправильно интерпретирует snmpEngineBoots и snmpEngineTime. Но разработчики Zabbix клятвенно заверяют, что они используют библиотеку snmp из net-snmp. Те же библиотеки используются в командной строке. Так что расследование, видимо, зашло в тупик.

С другой стороны, имеется несколько отчётов об ошибках на сайте Zabbix, которые указывают на не уникальные значения engineID у агентов. За подробностями можно обратиться к отчёту об ошибке ZBX-2152.

Лечение

Поскольку понять причину проблемы не удалось, я поменял engineID у агента:
engineIDType 3
Эта строка в файле конфигурации snmpd.conf агента изменяет идентификатор со случайного значения, предоставленного net-snmp, на MAC-адрес интерфейса eth0, который каким-то образом должен оказаться и правда уникальным. Конечно, только после перезагрузки. И правда, Zabbix восстановил обмен данными с агентом и начал собирать данные. Проблема решена.

Если у вас есть какие-то дополнительные вопросы, свяжитесь со мной по электронной почте ms@sys4.de (примечание переводчика: автор не понимает по-русски, пишите на английском или немецком).

воскресенье, 4 сентября 2016 г.

Концепции SNMP версии 3

Перевод: SNMP Version 3 Concepts
Автор: msinadinovic

SNMP версии 3 предоставляет три значительных новых улучшения в безопасности по сравнению с предыдущими версиями протокола. Это:
  1. Своевременность
  2. Аутентификация
  3. Конфиденциальность
Перед тем как рассмотреть, что они собой представляют, нужно пояснить один термин. Авторитетный агент SNMP - это агент, который поддерживает информацию, используемую для обеспечения своевременности, аутентификации и конфиденциальности. В большинстве случаев агент SNMP - это агент, содержащий информацию, которую запрашивают станции управления. Единственное исключение - это отправка агентом уведомлений Inform. В таких случаях станция управления выступает авторитетным агентом и поддерживает информацию SNMP, используемую для обеспечения перечисленных выше средств безопасности.

Своевременность - это возможность, позволяющая авторитетному агенту SNMP проверить, что информация поступила своевременно и что она не была перехвачена, сохранена и передана повторно по истечении приемлемого окна времени с момента её отправки.

Это может звучать сложно, но на самом деле это не так. Для этого используются два значения из пакета SNMP версии 3. Они называются engine boots - количество загрузок агента и engine time - время, прошедшее с последней загрузки агента.

Количество загрузок агента - это количество раз, которое авторитетный агент SNMP был запущен, загружен, выполнен, инициализирован или перешёл в любое другое состояние, которое соответствует смыслу слова "загружен". Время, прошедшее с последней загрузки - это количество секунд, прошедшее с того момента, когда авторитетный агент SNMP перешёл в состояние "загружен". Эти два значения совместно используются для проверки своевременности.

Проверка своевременности производится сравнением количества загрузок агента из пакета с сохранённым значением авторитетного агента SNMP и сравнением времени, прошедшего с последней загрузки, которое должно отличаться не более чем на 150 секунд от значения авторитетного агента SNMP. Другими словами, если количество загрузок агента в полученном пакете не равно сохранённому локально значению, авторитетный агент SNMP отклонит пакет.

Аутентификация - это метод проверки, позволяющий получателю удостовериться, что пакет не был изменён в процессе передачи. Это делается путём расчёта хэша всего пакета и (в сочетании с секретным паролем, известным агенту и станции управления, участвующим в обмене) гарантирует, что только авторизованные стороны могут изменить пакет.

Конфиденциальность - это шифрование части данных пакета SNMP. Часть данных - это Protocol Data Unit в пакете SNMP. Шифрование проводится с использованием секрета (пароля), который известен агенту и станции управления.

Поскольку авторитетный агент SNMP использует информацию для обеспечения своевременности, аутентификации и конфиденциальности, должен быть способ получить эти значения не авторитетным агентам. Этот процесс называется процессом обнаружения.

Перед выполнением запросов SNMP к авторитетному агенту SNMP, нужно отправить к нему пакет обнаружения (обычно это пустой пакет SNMP версии 3) и подождать ответного сообщения REPORT. Полученное сообщение REPORT будет содержать следующие значения: engine ID - идентификатор авторитетного агента SNMP, engine boots - количество загрузок агента SNMP и engine time - время, прошедшее с последней загрузки. Эти значения нужно будет использовать в последующих запросах.

Заполучив информацию авторитетного агента SNMP, можно начать отправлять запросы в соответствии с настройками аутентификации и конфиденциальности, которые использует запрашиваемый агент.

Теперь немого подробностей о реализации SNMP версии 3 в SnmpSharpNet. Вся функциональность собрана в классе SnmpV3Packet. Этот класс позволяет выбрать нужный уровень безопасности, алгоритм аутентификации и значение секрета, протокол шифрования и значение секрета, имя пользователя и т.п. Чтобы узнать, какие алгоритмы проверки подлинности поддерживаются в библиотеке используемой вами версии, обратитесь к перечисляемому типу SecurityDigests, в котором перечислены поддерживаемые алгоритмы аутентификации. Чтобы найти поддерживаемые протоколы шифрования, обратитесь к перечисляемому типу PrivacyProtocols.

За примерами использования SNMPv3 обратитесь к веб-сайту проекта.