Привет, HABR!
Все те кто пользуются системой мониторинга Zabbix, с большой вероятностью, уже использовали UserParameter. Это, безусловно, очень полезный инструмент позволяющий значительно расширить базовые возможности Zabbix и поставить на мониторинг что-то такое эдакое. Но, к сожалению, у данного подхода есть свои минусы:
Необходимость распространение файлов конфигураций UserParameter
Необходимость перезапуска zabbix-agent после добавления UserParameter
Не нулевой шанс, что zabbix-agent не запустится после добавления некорректного файла конфигурации UserParameter
Проблему под пунктом 1 затрагивать не будем и перейдем к оставшимся двум, т.к. решив проблему 2 и 3 пунктов, та что под №1 станет чуть менее проблемной потому-что мы не будем бояться сломать запуск zabbix-agent при распространении файлов UserParameter.
Не так давно Zabbix в своем Release Notes for Zabbix 6.0.0 сообщил о том, что внедрил runtime команду для перечитки пользовательских параметров, без необходимости перезагрузки zabbix-agent. Но, по моему скромному мнению, что перезагрузка агента, что выполнение runtime команды (zabbix_agentd -R userparameter_reload) - являются дополнительным шагом при распространении UserParameter. А так как проблема с возможной поломкой запуска zabbix-agent не решена, то по прежнему распространение UserParameter остается не совсем безопасным этапом.
Запуск zabbix-agent достаточно просто сломать, не аккуратно работая с файлами пользовательских параметров. Добавьте агенту zabbix некорректный файл пользовательских параметров (дублирующие ключи, опечатки, лишние непечатаемые символы) и выполнив его перезагрузку, он пожалуется на конфиг и не запуститься. В случае если "плохой" UserParameter уже распространили на несколько тысяч или десятков тысяч серверов, то это очень неприятно исправлять. При большом парке серверов, большого разнообразия продуктов, нескольких десятков инженеров, разрабатывающих мониторинг, и нескольких сотен различных UserParameter, данная ситуация нет-нет, да и случится. Конечно же надо тестировать UserParameter перед распространением, но человеческий фактор никто не отменял.
Именно возможность сломать zabbix-agent, я считаю, основой опасностью UserParameter, и, поэтому, в первую очередь надо решать именно эту проблему.
Как же не стать параноиком и при этом не сломать zabbix-agent?
Не хочется мириться с потенциальным риском сломать zabbix-agent на большом количестве серверов практически одномоментно, но при этом хочется продолжать пользоваться пользовательскими параметрами, расширяя возможности мониторинга Zabbix.
Решение, которое можно предложить - это использовать один стандартный UserParameter (в связке со скриптом), который нам добавит возможность использования безопасно и динамически(как бонус) загружаемых пользовательских параметров.
Взаимодействие zabbix-agent с динамическими пользовательскими параметрами будет выглядеть следующим образом
Основные тезисы данного подхода:
Мы используем классические файлы UserParameter, т.е. переписывать ничего не придется.
Если UserParameter параметр не корректный, то сломается сбор данных только для данного UserParameter и только для ключа/ключей, где закралась ошибка
Если UserParameter попадает в директорию динамически загружаемых, то сбор метрик по нему начнется моментально.
Пример настройки на Linux
1. Создадим в /etc/zabbix/zabbix_agentd.d/ директорию dyn_up
для динамических UserParameter:
2. Создадим в директории /etc/zabbix/zabbix_agentd.d/ скрипт dyn_up.sh со следующим содержимым:
#!/bin/bash
#Укажем расположение директории динамических UserParameter
dyn_up_dir="/etc/zabbix/zabbix_agentd.d/dyn_up"
#Получим ключ команды и имя UserParameter
read -r up_key up_name <<< $(echo "$1" | tr '@' ' ')
#Получи команду из ключе в динамическом UserParameter
up_cmd=`perl -ne "print if s/^UserParameter\s?=\s?\S+,\s?(.*)/\1/" "$dyn_up_dir/$up_name"`
#Пройдемся по всем полученным скриптом параметрам и заменим соответствующие ссылки на позиции
for ((i=1; i<=${#*}; i++))
do
up_cmd=$(echo "$up_cmd" | perl -pe 's/(?<!\$)\${1}'$(( i - 1 ))'/'"${!i}"'/g')
done
#$$ меняем на $
up_cmd=$(echo "$up_cmd" | perl -pe 's/\$\$/\$/g')
#Выполняем команду
/bin/bash -c "$up_cmd"
3. Создадим в директории /etc/zabbix/zabbix_agentd.d/ наш единственный обычный UserParameter userparameter_dyn_up.conf со следующим содержимым:
UserParameter=dyn.up[*], ./dyn_up.sh "$1" "$2" "$3" "$4" "$5" "$6" "$7" "$8" "$9"
4. Запуск проверки будет выглядеть следующим образом:
dyn.up["item_key@userparameter","param1","param2","param3","param4","param5","param6"]
P.S. Вашему вниманию представлен концепт, который опробован только на zabbix-агентах под Linux.
Скрипт для Windows может выглядеть следующим образом
$dir_path = 'D:\zabbix\zabbix_agentd.d\dyn_up'
$up_key, $up_name = $args[0].split('@')
$up_name = Join-Path -Path $dir_path -ChildPath $up_name
$up_cmd = (Select-String -Path $up_name -Pattern "^UserParameter\s?=\s?$up_key(\[\*\])?,").Line.Split(',') | Select-Object -Skip 1
for($i=1; $i -lt $args.Count; $i++){
$str = '(?<!\$)\${1}'+$i
$up_cmd = $up_cmd -replace $str, $args[$i]
}
$up_cmd = $up_cmd -replace '\${2}', '$'
Invoke-Expression "$up_cmd"
Спасибо за внимание!
Комментарии (5)
bpof
11.06.2022 13:56А как же агент2 и плагины на Go?
azk Автор
11.06.2022 14:09+1Можно, конечно, сделать и плагин, но постоянно пересобирать агент, что бы добавить свой плагин как-то не очень хочется. Так же в нашем случае из-за отсутствии рута проще использовать скрипт, т.к. скрипт можно разлить своими руками, а обновлять агентов, надо напрягать админов, и этап распространения растянется надолго.
Если бы можно было написав плагин отдать его Zabbix, то это был бы интересный вариант, но тут нужно что бы сообщество поддержало соответствующий ZBX-NEXT.
kvazimoda24
А почему тогда не воспользоваться system.run?
AlexGluck
Если мне не изменяет память, раньше он был ограничен 255 символами. А сейчас описано, что ограничен возврат данных в 512кб. Плюс его надо отдельно включать и тогда можно будет любую команду на сервере выполнить, а не только то что запланировано. Свободное выполнение команд, это точно к вопросам о безопасности.
azk Автор
AlexGluck написал основные моменты с использованием system.run, немного дополню. Ключ элемента данных ограничен в последних версиях 2048 символами. Так же сталкивались с тем, что не любую команду можно запихнуть в system.ru(возможно что-то недосмотрел, утверждать не буду). С безопасниками можно договориться на использовании system.run с ведением списка AllowKey, но это доставляет примерно туже головную боль, что и распространение UserParameter, а ввиду вышеописанных ограничений system run, то выбрали для себя использование UserParameter