Всем привет. Меня зовут Игорь, я Tech Lead команды DevOps-инженеров и активно развиваю направления мониторинга в компании. В продолжение статьи своего коллеги по цеху @EvgenNet хочу познакомить вас с шаблоном для Zabbix и дашбордом в Grafana для визуализации активности пользователей OpenVPN. Возьмите вкусняшек, чайку и присаживайтесь поудобнее. Далеко в 2019 году появилась потребность смотреть статистику по пользователям не только в реальном времени, но и за определённый промежуток. Есть такой инструмент https://github.com/furlongm/openvpn-monitor, он позволяет в реальном времени смотреть из какой страны подключён пользователь, с какими IP-адресами и какой трафик через него проходит. Как раз в это время мы активно использовали Influx и все бизнес-метрики были именно там. Недолго думая, я решил немного переделать скрипт под вывод метрик в формате Influx для Telegraf-агента и накидать небольшой дашборд для Grafana. Кому интересен скрипт и дашборд — велком в личку.   Всё это великолепие работало и радовало своих потребителей до тех пор, пока мы не начали переезжать на новую архитектуру OpenVPN и не стали отказываться от Influx. Теперь необходимо было затащить всё под Zabbix, а @EvgenNetдоблестно вызвался написать скрипт. Всё, от чего мы пляшем — это ограничения текстовых данных (массив, который мы будем предварительно обрабатывать и создавать метрики на основе прототипов). Text data limits depend on the database backend. Before storing text values in the database they get truncated to match the database value type limit. Database Type of information  Character Log Text MySQL 255 characters 65536 bytes 65536 bytes PostgreSQL 255 characters 65536 characters 65536 characters Oracle 255 characters 65536 characters 65536 characters Так как мы используем PostgreSQL и упираемся в 65 536 символов, то решили разделить сотрудников по их ролям/профилям: Админы; Бизнес; Разработка; Мобилки; Безопасность. Для сбора данных нам необходимо раскидать UserParameter и скрипт на серверы с OpenVPN: userparameter_openvpn.conf UserParameter=discovery.openvpn[*], /usr/bin/openvpn-mon.py $1 Скрипт принимает на вход один аргумент из списка: admin; bs; dev; mobile; sec. Приступаем к созданию самого шаблона, нам необходимо создать мастер-элементы (Items) для каждой пользовательской роли: Name Key Interval Type of information Type Get openvpn admin users discovery.openvpn[admin] 5m Text Zabbix agent Get openvpn business users discovery.openvpn[bs] 5m Text Zabbix agent Get openvpn develop users discovery.openvpn[dev] 5m Text Zabbix agent Get openvpn mobile users discovery.openvpn[mobile] 5m Text Zabbix agent Get openvpn security users discovery.openvpn[sec] 5m Text Zabbix agent Теперь необходимо создать правила обнаружения (Discovery rules) с зависимыми элементами: Name Key Type Get openvpn admin users: Discovery admin stats get.openvpn.admin.stats Dependent item Get openvpn business users: Discovery business stats get.openvpn.business.stats Dependent item Get openvpn develop users: Discovery develop stats get.openvpn.develop.stats Dependent item Get openvpn mobile users: Discovery mobile stats get.openvpn.mobile.stats Dependent item Get openvpn security users: Discovery security stats get.openvpn.security.stats Dependent item Тут остановимся и разберём подробнее на примере Discovery admin stats: Discovery rule Name: Discovery admin stats. Type: Dependent item. Key: get.openvpn.admin.stats. Master item: Get openvpn admin users — выбираем из выпадающего списка элемент, с которым будем работать. Keep lost resources period: 90d. Preprocessing — не используем. LLD Macros (LLD macro : JSONPath) — вытаскиваем в макросы необходимую на в будущем информацию. {#OVPN_CODE} : $..code.first() {#OVPN_ENV} : $..env.first() {#OVPN_USER} : $..user.first() Filters — не используем. Overrides — не используем. Теперь необходимо создать прототипы элементов (Item prototypes), на их основе будут автоматически создаваться элементы (Items) под каждого нового пользователя. Разберу на примере одного из 9 элементов, а остальные сведу в таблицу: Item prototype Name: OpenVPN bytes received by {#OVPN_USER}. Type: Dependent item. Key: bytes_r.openvpn[{#OVPN_USER},admin]. Type of information: Numeric (unsigned). Master item: Get openvpn admin users — выбираем из выпадающего списка элемент, с которым будем работать. Units: B. Tags Application: OpenVPN. Country: {#OVPN_CODE}. Department: {#OVPN_ENV}. User: {#OVPN_USER}. Preprocessing 1: JSONPath: $.data.[?(@.user=='{#OVPN_USER}')].bytes_r.first(). 2: Simple change. Для примера я взял роль/профиль админов: Name Key Type of information Units Preprocessing OpenVPN bytes received by {#OVPN_USER} bytes_r.openvpn[{#OVPN_USER},admin] Numeric (unsigned) B 1: JSONPath: $.data.[?(@.user=='{#OVPN_USER}')].bytes_r.first() 2: Simple change OpenVPN bytes sent by {#OVPN_USER} bytes_s.openvpn[{#OVPN_USER},admin] Numeric (unsigned) B 1: JSONPath: $.data.[?(@.user=='{#OVPN_USER}')].bytes_s.first() 2: Simple change OpenVPN connected since by {#OVPN_USER} unix_time.openvpn[{#OVPN_USER},admin] Numeric (unsigned) unixtime 1: JSONPath: $.data.[?(@.user=='{#OVPN_USER}')].unix_time.first() OpenVPN connected since by {#OVPN_USER} con_time.openvpn[{#OVPN_USER},admin] Character  1: JSONPath: $.data.[?(@.user=='{#OVPN_USER}')].con_time.first() OpenVPN country of connection by {#OVPN_USER} code.openvpn[{#OVPN_USER},admin] Character  1: JSONPath: $.data.[?(@.user=='{#OVPN_USER}')].code.first() OpenVPN department of connection by {#OVPN_USER} env.openvpn[{#OVPN_USER},admin] Character  1: JSONPath: $.data.[?(@.user=='{#OVPN_USER}')].env.first() OpenVPN real ip gotten by {#OVPN_USER} real_ip.openvpn[{#OVPN_USER},admin] Character  1: JSONPath: $.data.[?(@.user=='{#OVPN_USER}')].real_ip.first() OpenVPN total online by {#OVPN_USER} duration.openvpn[{#OVPN_USER},admin] Numeric (unsigned) s 1: JSONPath: $.data.[?(@.user=='{#OVPN_USER}')].duration.first() OpenVPN vpn ip gotten by {#OVPN_USER} vpn_ip.openvpn[{#OVPN_USER},admin] Character  1: JSONPath: $.data.[?(@.user=='{#OVPN_USER}')].vpn_ip.first() И так для каждой пользовательской роли/профиля. Получается 5 правил обнаружения, и в каждом правиле по 9 прототипов элементов. Почему же две OpenVPN connected since by {#OVPN_USER}? unixtime конвертирует сам Zabbix и отображает корректную дату подключения. Строка с датой для Grafana, ибо она не умеет в unixtime, а когда научится — мы её удалим. Под спойлером сам шаблон, надеюсь, он вам пригодится.  Что мы можем в нём увидеть: Получено трафика от пользователя. Отправлено трафика пользователю. Статистика подключений: Время проверки Zabbix'ом. Регион подключения. Внешний IP. Внутренний IP. Роль/профиль. Длительность текущего подключения. Поиск пользователей: По внешнему IP. По внутреннему IP. По роли/профилю VPN. Под спойлером JSON для экспорта в Grafana.  На этом у меня всё, всем спасибо за внимание, и вступайте в Zabbix Community!  Tech Lead/DevOps