TLS PSK для Mamonsu: как мы добавили защищённую передачу метрик PostgreSQL в Zabbix
Мониторинг обычно не требует написания собственного кода. Как правило, достаточно установить готовый агент, подключить его к существующей системе, проверить поступление данных и перейти к следующим задачам. Однако при подключении нового пилотного контура PostgreSQL у нас возникла ситуация, в которой стандартной конфигурации оказалось недостаточно.
Для сбора специализированных показателей использовался Mamonsu - инструмент с открытым исходным кодом, предназначенный для мониторинга PostgreSQL и развиваемый Postgres Professional. Агент успешно подключался к базе, выполнял запросы и формировал метрики. Локальные проверки подтверждали, что сбор данных работает корректно. Но в Zabbix значения не появлялись.
Поначалу проблему искали в типичных местах: проверяли имя узла, адрес сервера, порт, права доступа, ключ элемента данных и параметры конфигурации. Постепенно стало понятно, что PostgreSQL здесь ни при чём. Mamonsu видел базу, получал результаты запросов и подготавливал данные, однако они не доходили до Zabbix Server.
Где возникла проблема
Анализ исходного кода Mamonsu 3.5.17 показал, что встроенный механизм отправки создавал обычное TCP-соединение. Шифрование канала с помощью TLS PSK в нём не поддерживалось.
На пилотном контуре Zabbix был настроен так, чтобы принимать соединения от узла только по защищённому каналу. Поэтому стандартный sender Mamonsu не мог завершить передачу: сервер ожидал TLS, а агент инициировал обычный TCP-сеанс.
Чтобы исключить ошибку в настройках Zabbix и окончательно локализовать причину, ту же метрику отправили штатной утилитой `zabbix_sender`. В командной строке явно указали:
- параметры подключения к серверу;
- идентификатор PSK;
- файл с предварительно общим ключом;
- режим TLS PSK.
Передача прошла успешно. Это подтвердило сразу несколько фактов: Zabbix Server доступен, узел существует, ключ корректен, идентификатор совпадает, а сервер принимает данные по TLS PSK. Разница была только в отправителе: `zabbix_sender` умел устанавливать защищённое соединение, а Mamonsu - нет.
Почему нельзя было просто оставить zabbix_sender
Первый вариант решения выглядел очевидно: запускать внешний `zabbix_sender`, передавая ему подготовленные значения. Такой подход действительно позволил бы обойти ограничение, но создавал дополнительные проблемы.
Потребовались бы отдельный процесс, временный файл или дополнительный канал передачи данных, обработка кодов возврата, контроль таймаутов и синхронизация с основным агентом. Кроме того, часть логики оказалась бы вынесена за пределы Mamonsu, а сопровождение такой схемы стало бы сложнее.
Другой путь - ослабить настройки Zabbix и разрешить обычные TCP-соединения. Однако это противоречило требованиям пилотного контура и снижало уровень защиты. Если инфраструктура уже настроена на шифрование, отключать его ради совместимости отдельного компонента нерационально.
Поэтому было принято решение доработать сам Mamonsu: сохранить существующий протокол обмена с Zabbix, но заменить незащищённый транспорт на TLS.
Что именно добавили
В Zabbix формат передаваемых данных не меняется из-за использования TLS PSK. Сервер по-прежнему получает те же имена узлов, ключи элементов и значения. Изменяется только способ установления соединения.
В Mamonsu добавили поддержку двух вариантов защищённого подключения:
1. TLS PSK - с использованием идентификатора и предварительно общего ключа.
2. TLS по сертификатам - для сценариев, где применяется инфраструктура открытых ключей.
Параметры внесли не только в конфигурационный файл агента, но и в интерфейс командной строки. Это важно для диагностики: администратор может быстро проверить соединение с разными настройками, не меняя основной конфигурационный файл.
Для PSK предусмотрели отдельные параметры:
- режим TLS-подключения;
- идентификатор PSK;
- путь к файлу с ключом;
- адрес и порт Zabbix Server;
- параметры таймаута соединения.
При этом старый сценарий работы без TLS сохранили. Существующие установки Mamonsu не должны были перестать работать после обновления.
Особенности реализации на Python
На уровне Python задача оказалась сложнее, чем простое включение флага в модуле `ssl`. Современные версии Python уже поддерживают работу с PSK через стандартные средства. Однако такая возможность появилась только начиная с Python 3.13.
Mamonsu используется в инфраструктурах с разными версиями интерпретатора. Если реализовать PSK исключительно через новый API, старые системы потеряют совместимость. Поэтому для прежних версий Python потребовался другой механизм.
В качестве слоя совместимости использовали `ctypes`. Он позволил обратиться к функциям TLS-библиотеки напрямую, не реализуя собственный криптографический протокол. Это принципиальный момент: Mamonsu не стал самостоятельно выполнять шифрование, проверку ключей или формирование TLS-пакетов. Эти операции по-прежнему выполняет системная библиотека.
Такой подход позволил разделить реализацию на два варианта:
- в новых версиях Python использовать стандартную поддержку PSK;
- в старых версиях обращаться к функциям TLS-библиотеки через совместимый слой.
В результате удалось сохранить поддержку широкого набора окружений и не привязать Mamonsu к одной версии Python.
Почему сначала ограничились TLS 1.2
На первом этапе поддержка PSK была ограничена TLS 1.2. Это связано не с принципиальным отказом от новых версий протокола, а с особенностями доступных API и библиотек.
В TLS 1.2 PSK-сценарии реализованы предсказуемо и хорошо поддерживаются используемыми библиотеками. Для TLS 1.3 требования к обработчикам, наборам шифров и callback-функциям отличаются. Универсальная реализация для разных версий Python и OpenSSL потребовала бы отдельной проработки и дополнительного набора тестов.
Для пилотного контура TLS 1.2 соответствовал требованиям безопасности и обеспечивал необходимую совместимость. Поэтому было разумнее сначала реализовать устойчивый рабочий вариант, а поддержку TLS 1.3 рассматривать как отдельное направление развития.
Важная ошибка: нельзя молча отключать TLS
Отдельное внимание уделили обработке ошибок. Защищённое соединение не должно незаметно превращаться в обычный TCP-сеанс, если TLS не удалось запустить.
Например, ошибка в PSK, несовпадение идентификатора, отсутствие файла ключа или неподдерживаемая функция библиотеки должны приводить к явному завершению передачи. В противном случае администратор может считать данные защищёнными, хотя фактически агент отправляет их по нешифрованному каналу или вообще не передаёт.
Поэтому были предусмотрены:
- проверка корректности параметров до подключения;
- явная фиксация режима TLS;
- сообщения об ошибках в журнале;
- отказ от незащищённого fallback при включённом TLS;
- различение ошибок сети и ошибок аутентификации.
Такой подход особенно важен для мониторинга: сбой должен быть заметен, а не скрыт за внешне успешным запуском процесса.
Как хранился PSK
Сам предварительно общий ключ не стали помещать в `agent.conf`. Вместо этого Mamonsu получает путь к отдельному файлу с секретом.
Это решение позволяет:
- ограничить права доступа к ключу;
- не смешивать параметры подключения и секретные данные;
- менять PSK без редактирования основной конфигурации;
- использовать стандартные политики управления секретами;
- снизить риск случайной публикации ключа вместе с конфигурацией.
Файл должен принадлежать пользователю, от имени которого работает Mamonsu, и быть недоступен посторонним учетным записям. В эксплуатационной документации важно отдельно описать права на этот файл и порядок его замены.
Сам PSK необходимо проверять как секрет: нельзя передавать его в аргументах командной строки, если этого можно избежать, поскольку параметры процесса иногда доступны другим пользователям системы.
Проверка настоящим TLS-соединением
Тестирование выполняли не только на уровне результата в Zabbix. Было важно убедиться, что данные действительно идут через TLS, а не проходят по случайно разрешённому обычному TCP-каналу.
Проверка включала несколько этапов:
1. Отправка тестовой метрики с корректным PSK.
2. Проверка отказа при неверном ключе.
3. Проверка отказа при неправильном идентификаторе.
4. Проверка поведения при отсутствии файла ключа.
5. Проверка невозможности незашифрованного fallback.
6. Проверка работы на разных версиях Python.
7. Сравнение результата Mamonsu со штатным `zabbix_sender`.
8. Проверка появления значений в Zabbix и корректности журналов.
Отдельно проверяли перезапуск агента, временную недоступность сервера и восстановление соединения. Для мониторинга важно не только установить TLS один раз, но и корректно переживать сетевые сбои.
Результат на пилотном контуре
После внесения изменений Mamonsu подключался к PostgreSQL, собирал метрики и передавал их в Zabbix Server через TLS PSK. Данные стали отображаться в элементах мониторинга без изменения схемы метрик и без запуска внешнего `zabbix_sender`.
При этом сохранились прежние варианты работы:
- подключение без шифрования для старых конфигураций;
- передача через TLS PSK;
- использование сертификатной аутентификации;
- запуск с параметрами из конфигурационного файла;
- ручная проверка через аргументы командной строки.
Таким образом, доработка не изменила назначение Mamonsu, а закрыла конкретный пробел в сетевой совместимости.
От локальной доработки к upstream
После проверки на пилотном окружении изменения подготовили для передачи разработчикам Mamonsu в upstream. Это важный этап: локальный патч решает проблему одной команды, но только включение в основной проект позволяет получить полноценную поддержку, документацию и дальнейшее сопровождение.
При подготовке изменений особое внимание уделили обратной совместимости, читаемости кода и отсутствию обязательной зависимости от Python 3.13. Кроме того, нужно было описать ограничения TLS 1.2, требования к системной TLS-библиотеке и порядок настройки ключей.
До принятия изменений разработчиками остаются вопросы ревью, тестирования на разных операционных системах и проверки взаимодействия с различными версиями OpenSSL и Zabbix. Поэтому локально рабочая реализация ещё не означает немедленного появления функции во всех официальных версиях Mamonsu.
Что можно улучшить дальше
Следующим шагом может стать полноценная поддержка TLS 1.3 для PSK. Для этого потребуется проверить совместимость callback-механизмов и наборов шифров, а также поведение разных комбинаций Python и OpenSSL.
Полезным развитием станет расширение автоматических тестов. В них следует включить проверки успешной аутентификации, неверного PSK, отсутствующего файла, повреждённых параметров и разрыва соединения во время передачи.
Ещё одно направление - более подробная диагностика. В журнале полезно разделять ошибки DNS, TCP, TLS handshake, проверки PSK и отказ Zabbix Server. Это сокращает время поиска неисправности и помогает отличить проблему сети от ошибки секретов.
Для крупных инфраструктур может понадобиться интеграция с менеджерами секретов. В таком сценарии Mamonsu не обязан напрямую хранить ключи: файл или временное представление PSK может подготавливаться средствами операционной системы и регулярно заменяться по установленной политике.
Итоги
Проблема возникла не в PostgreSQL и не в сборе метрик. Mamonsu корректно работал с базой данных, но его встроенный sender не умел устанавливать защищённое TLS PSK-соединение с Zabbix Server.
Проверка через `zabbix_sender` позволила быстро подтвердить, что сервер, узел и ключ настроены правильно. Вместо отключения TLS или построения внешней обходной схемы был доработан сам Mamonsu. В результате появились поддержка PSK и сертификатов, параметры командной строки, совместимость с разными версиями Python и безопасная обработка ошибок.
Главный практический вывод прост: если инфраструктура требует шифрования, лучше расширять используемый компонент, чем ослаблять защиту или маскировать проблему дополнительными процессами. Такой подход сохраняет архитектуру мониторинга, снижает эксплуатационные риски и делает решение пригодным не только для одного пилотного контура, но и для дальнейшего развития.
