Краткое руководство как готовить SNMPv3
Настройка v3-пользователя на агенте сервера для штатного линуксового snmpd
(пакет net-snmp
). Out of scope: snmp traps и пользователи с правом запиcи (rw).
Третья версия протокола позволяет передавать пакеты в зашифрованном виде, что даёт возможность безопасно передавать телеметрию через публичные сети без риска раскрытия как аутентификационной информации (аналог community), так и шифруя сам поток данных симметричным алгоритмом с общим ключём.
Напоминалка как настраивается v1/v2c
В версиях v1
/v2c
использовалось понятие community
. Это что-то типа парольной фразы, которую агент получает от клиента. При совпадении community
с настройками доступа (например, IP-адресом клиента из разрешённого диапазона), агент отдаёт телеметрию. Всё передаётся открытым методом, как сам community
, так и запрашиваемая телеметрия.
В tcpdump запросы выглядят так (community comminity_name
):
tcpdump: listening on br0, link-type EN10MB (Ethernet), snapshot length 262144 bytes
20:28:09.382435 IP (tos 0x48, ttl 44, id 25108, offset 0, flags [DF], proto UDP (17), length 74)
192.158.1.38.46214 > 198.51.100.1.161: { SNMPv2c C="comminity_name" { GetNextRequest(25) R=1193096294 .1.3.6.1.2.1 } }
20:28:09.414940 IP (tos 0x48, ttl 44, id 25112, offset 0, flags [DF], proto UDP (17), length 77)
192.158.1.38.46214 > 198.51.100.1.161: { SNMPv2c C="comminity_name" { GetNextRequest(28) R=1193096295 .1.3.6.1.2.1.1.1.0 } }
20:28:09.447385 IP (tos 0x48, ttl 44, id 25117, offset 0, flags [DF], proto UDP (17), length 77)
192.158.1.38.46214 > 198.51.100.1.161: { SNMPv2c C="comminity_name" { GetNextRequest(28) R=1193096296 .1.3.6.1.2.1.1.2.0 } }
20:28:09.479880 IP (tos 0x48, ttl 44, id 25125, offset 0, flags [DF], proto UDP (17), length 77)
192.158.1.38.46214 > 198.51.100.1.161: { SNMPv2c C="comminity_name" { GetNextRequest(28) R=1193096297 .1.3.6.1.2.1.1.3.0 } }
20:28:09.512357 IP (tos 0x48, ttl 44, id 25128, offset 0, flags [DF], proto UDP (17), length 77)
...
NB! В tcpdump здесь и дальше только запросы, ответов нет.
Настройка v2 community производится добавлением строки в файле /etc/snmp/snmpd.conf
, со следующим синтаксисом:
rocommunity[6] communityname [access] [-V view]
где:
6
(опционально) — признак ipv6 (он традиционно отдельно от ipv4)communityname
— названиеcommunity
, фактически общий парольaccess
(опционально) — опциональные настройки доступа клиента, варианты:default
,hostname
,network/bits
-V view
(опционально) — действующее ограничение по видимости древа oid для данного community, настраивается отдельно, out of scope
Примитивный пример:
rocommunity comminity_name
rocommunity6 comminity_name
Тут настроено одно community comminity_name
только для чтения для обоих версий протокола IP без дополнительных настроек ограничения.
Этого достаточно для понимания.
Аутентификация в SNMPv3
В версии v3
отказались от понятия community
. Ну, как отказались, переработали, но термин такой исключён. Появилось шифрование потока и аутентификационной информации. Что взамен?
имя пользователя
пароль для аутентификации
пароль для шифрования
То есть, против типичной схемы пары «логин/пароль» появилась не очень очевидная «логин/два пароля», что изначально вводит в ступор. Для каждого из паролей ещё надо задать алгоритм, с которым они будут использоваться:
пароль для аутентификации — нужно указать алгоритм хэширования, традиционно MD5 или SHA, в более поздних версиях появились вариации SHA
пароль для шифрования — нужно указать алгоритм симметричного шифрования, традиционно DES или AES, в более поздних версиях появились вариации AES
В tcpdump запросы по версии v3
выглядит примерно так:
tcpdump: listening on br0, link-type EN10MB (Ethernet), snapshot length 262144 bytes
23:28:39.753314 IP (tos 0x48, ttl 44, id 62294, offset 0, flags [DF], proto UDP (17), length 92)
192.158.1.38.48116 > 198.51.100.1.161: { SNMPv3 { F=r } { USM B=0 T=0 U="" } { ScopedPDU E= C="" { GetRequest(14) R=30306933 } } }
23:28:39.785927 IP (tos 0x48, ttl 44, id 62301, offset 0, flags [DF], proto UDP (17), length 171)
192.158.1.38.48116 > 198.51.100.1.161: { SNMPv3 { F=apr } { USM B=9 T=330 U="user_name" } { ScopedPDU [!scoped PDU]8f_6f_9f_0a_aa_3b_69_8c_02_30_66_48_52_7d_52_2b_9e_b0_a2_84_cc_60_8a_9e_d5_67_30_52_26_88_0e_68_a7_89_5d_df_78_a4_9b_4e_62_dc_f6_54_f8_16_00_02_ba_f7} }
23:28:39.818831 IP (tos 0x48, ttl 44, id 62308, offset 0, flags [DF], proto UDP (17), length 174)
192.158.1.38.48116 > 198.51.100.1.161: { SNMPv3 { F=apr } { USM B=9 T=330 U="user_name" } { ScopedPDU [!scoped PDU]f1_46_7e_ec_3a_d4_38_94_69_38_14_73_20_71_de_1a_24_b2_61_56_d9_a2_c3_20_b2_6b_6e_11_5f_23_25_f7_56_ba_09_df_09_82_79_54_ec_22_7a_f5_81_60_52_59_83_65_40_09_ac} }
23:28:39.851664 IP (tos 0x48, ttl 44, id 62310, offset 0, flags [DF], proto UDP (17), length 174)
192.158.1.38.48116 > 198.51.100.1.161: { SNMPv3 { F=apr } { USM B=9 T=330 U="user_name" } { ScopedPDU [!scoped PDU]43_30_e9_c9_7c_e2_07_9e_41_74_53_98_51_79_ff_7b_26_51_93_b2_fe_35_db_8e_a4_67_58_87_3e_de_8c_f6_5a_3e_1d_a4_47_d7_3d_f9_c8_b1_ac_2f_d2_48_3a_57_d0_f4_a8_45_9c} }
23:28:39.884478 IP (tos 0x48, ttl 44, id 62316, offset 0, flags [DF], proto UDP (17), length 174)
192.158.1.38.48116 > 198.51.100.1.161: { SNMPv3 { F=apr } { USM B=9 T=330 U="user_name" } { ScopedPDU [!scoped PDU]a0_35_d4_83_cb_6a_82_f1_bd_d7_16_58_00_ff_d7_5e_03_3a_01_c8_be_2e_6d_e5_bf_eb_7c_ce_07_12_76_fc_ee_6e_61_dc_18_d3_4b_7e_dd_f7_bc_f1_3e_de_ad_52_a2_2e_22_ea_74} }
...
Можно обратить внимание, что имя пользователя не шифруется, надо это иметь в виду, чтобы ничего лишнего на этот счёт не раскрыть на транзите.
Настройка производится чуть сложнее для понимания. Дело в том, что недостаточно закинуть в конфиг заранее подготовленную срочку (с некоторыми оговорками), так как аутентификационная информация генерируется в момент создания пользователя. Это, конечно, заметно осложняет деплой snmpd конфига с помощью типичных средств развёртывания, например, ansible.
Суммарно, и агент и его клиент должны обладать общей информацией (помимо знания клиента о хосте агента):
имя пользователя
пароль для аутентификации (типовая cli-опция для net-snmp
-a
)алгоритм аутентификации (типовая cli-опция для net-snmp
-A
)пароль для шифрования (типовая cli-опция для net-snmp
-x
)алгоритм шифрования (типовая cli-опция для net-snmp
-X
)
Помимо уже названного конфига /etc/snmp/snmpd.conf
, существует ещё по крайней мере два для динамического создания и хранения аутентификационной информации:
Даемон snmpd формирует необходимые строчки при запуске, поэтому перед созданием юзера надо погасить процесс. Специальный встроенный скрипт сообщит, что процесс запущен и не даст создать пользователя без его остановки, так как при остановке процесса один из этих файлов перезатирается in-memory значениями.
Создание пользователя на агенте производится командой (опции расписаны выше):
net-snmp-create-v3-user -ro -a 'auth_pass' -A SHA -x 'priv_pass' -X AES user_name
Так создаётся пользователь с именем user_name
с паролем аутентификации auth_pass
, алгоритмом аутентификации SHA
, паролем шифрования priv_pass
и алгоритмом шифрования AES
. Технически по результату выполнения этого скрипта, добавляется по строке в два вышеназванных конфига:
Но это не всё. При запуске даемона snmpd происходит модификация файла /var/lib/snmp/snmpd.conf
: все строчки с началом createUser
исчезают и появляются уже рабочие строки вида:
usmUser 1 3 0x80001f888052e226409c42d06300000000 "user_name" "user_name" NULL .1.3.6.1.6.3.10.1.1.3 0x018a3bb9c17caafed74347e50d918963e37e70d7 .1.3.6.1.6.3.10.1.2.4 0xcfdecd0e1bc6bf08eb7ae90e68bdb414 ""
Файл /usr/share/snmp/snmpd.conf
остаётся нетронутым. В дальнейшем возможно манипулировать аутентификационной информацией в строке usmUser
с помощью cli-утилиты snmpusm
(см. man).
SNMPv3 security level
Пару слов на счёт уровня безопасности v3. Традиционно выглядит как:
noAuthNoPriv
— передавать данные без аутентификации и шифрованияauthNoPriv
— передавать данные с успешной аутентификацией, но не шифруя ихauthPriv
— передавать данные с успешной аутентификацией и с использованием шифрования
Первый из них — малополезная экзотика, остановимся на остальных двух authNoPriv
и authPriv
.
Нагляднее будет показать пару строк tcpdump. Вот так выглядит обмен для authNoPriv
:
10:50:58.534839 IP (tos 0x48, ttl 44, id 54935, offset 0, flags [DF], proto UDP (17), length 92)
192.158.1.38.20723 > 198.51.100.1.161: { SNMPv3 { F=r } { USM B=0 T=0 U="" } { ScopedPDU E= C="" { GetRequest(14) R=1808634162 } } }
10:50:58.567563 IP (tos 0x48, ttl 44, id 54937, offset 0, flags [DF], proto UDP (17), length 162)
192.158.1.38.20723 > 198.51.100.1.161: { SNMPv3 { F=ar } { USM B=10 T=39805 U="user_name" } { ScopedPDU E=_80_00_1f_88_80_52_e2_26_40_9c_42_d0_63_00_00_00_00 C="" { GetNextRequest(25) R=1808634161 .1.3.6.1.2.1 } } }
10:50:58.600457 IP (tos 0x48, ttl 44, id 54945, offset 0, flags [DF], proto UDP (17), length 165)
192.158.1.38.20723 > 198.51.100.1.161: { SNMPv3 { F=ar } { USM B=10 T=39805 U="user_name" } { ScopedPDU E=_80_00_1f_88_80_52_e2_26_40_9c_42_d0_63_00_00_00_00 C="" { GetNextRequest(28) R=1808634163 .1.3.6.1.2.1.1.1.0 } } }
...
Вот так для authPriv
:
10:51:47.463848 IP (tos 0x48, ttl 44, id 61280, offset 0, flags [DF], proto UDP (17), length 92)
192.158.1.38.54277 > 198.51.100.1.161: { SNMPv3 { F=r } { USM B=0 T=0 U="" } { ScopedPDU E= C="" { GetRequest(14) R=1901099838 } } }
10:51:47.496541 IP (tos 0x48, ttl 44, id 61282, offset 0, flags [DF], proto UDP (17), length 172)
192.158.1.38.54277 > 198.51.100.1.161: { SNMPv3 { F=apr } { USM B=10 T=39854 U="user_name" } { ScopedPDU [!scoped PDU]f2_87_ea_15_87_25_a7_b8_44_b4_38_62_15_86_d4_4e_1a_99_34_9e_6c_4d_6a_39_ea_1c_d7_1c_6e_f6_1f_76_c0_e2_ba_91_4d_8e_d5_9c_e7_06_29_c1_47_6e_a2_9a_2b_5c} }
10:51:47.529402 IP (tos 0x48, ttl 44, id 61290, offset 0, flags [DF], proto UDP (17), length 175)
192.158.1.38.54277 > 198.51.100.1.161: { SNMPv3 { F=apr } { USM B=10 T=39854 U="user_name" } { ScopedPDU [!scoped PDU]da_e4_d6_48_f1_ea_28_7f_bf_ce_d6_e0_ef_f7_95_06_0c_d7_79_7c_f1_4b_78_75_4f_1a_e2_00_a6_83_d5_e6_c2_82_55_0f_09_a4_7d_f1_e1_f2_a0_64_d3_c3_d7_13_c3_ae_95_8b_db} }
...
В принципе, видно, что в первом случае только часть информации шифруется (например, аутентификационная), при этом можно перехватить список запрашиваемых OID. Во втором случае вся информация остаётся зашифрованной, немного увеличив размер пакета. Наверное, где-то там на шифрование ещё утилизируется больше вычислительных мощностей, но не думаю что существенно много для нашего времени, так как используется довольно быстрое симметричное шифрование с общим ключём.
Настройка клиента
Традиционно, проверяется, работает ли snmp вообще с помощью встроенной утилиты snmpwalk. Вот так можно проверить работу клиента v2c
(с community
):
snmpwalk -v 2c -c communityname hostname
где:
Вот так можно проверить работу клиента v3
(с шифрованием authPriv
):
snmpwalk -v 3 -a SHA -A auth_pass -x AES -X priv_pass -l authPriv -u user_name hostname
где:
SHA
— алгоритм аутентификацииauth_pass
— пароль для аутентификацииAES
— алгоритм шифрованияpriv_pass
— пароль для шифрованияauthPriv
— уровень безопасности «с аутентификацией и шифрованием»user_name
— имя пользователяhostname
— имя хоста агента
Если всё так работает, осталось заполнить аналогичные строки в софте мониторинга:
CC BY-SA, Vadim Rybalko. Настройка SNMPv3 в LibreNMS.
Если что-то не работает, посмотреть в правила фаерволла на обоих концах и попробовать «поволкать» с хоста системы мониторинга, посмотреть в tcpdump, попробовать как работает клиент с локалхоста агента как по внешнему IP-адресу, так и по loopback адресу, например, 127.0.0.1
или ::1
.