Задача пришла в формулировке, знакомой многим: «Wazuh работает, но сигналов столько, что не разобрать, где ложные срабатывания, а где реальные атаки. Надо что-то с этим сделать».
Для контекста: Wazuh – это open-source SIEM, который собирает логи, детектирует подозрительную активность и умеет на неё реагировать. Инструмент хороший, но дефолтный набор правил – как швейцарский нож: вроде и режет, и открывает, а под конкретную задачу всё равно приходится подтачивать. Он рассчитан на «среднюю» инфраструктуру и без адаптации генерирует много шума.

Моя задача сводилась к тому, чтобы отделить этот шум от значимых событий, не потеряв при этом сами атаки. Ниже – методология и грабли, на которые я наступил. Будет полезно тем, кто настраивает Wazuh впервые, и тем, кто хочет разгрузить аналитиков от потока ложных тревог.
Знакомство с правилами
Дефолтные правила Wazuh лежат в /var/ossec/ruleset/rules/ – тысячи строк XML. Да, XML в 2026 году. Формат многословный (готовьтесь к закрывающим тегам в промышленных количествах), но к нему быстро привыкаешь, а главное – менять эти файлы напрямую не нужно.
Все локальные правки выносятся в local_rules.xml и в дополнительно загружаемые файлы. Удобнее работать через веб-интерфейс: он проверяет структуру XML на лету (парные теги, корректность вложенности) и не даст случайно сломать рабочую конфигурацию – наломать дров можно только в своей «песочнице».
Типовые ложные срабатывания
Чаще всего нас будили три сценария:
SSH-брутфорс с localhost. Ansible выполняет
ssh localhostв ходе provisioning, а Wazuh уверенно трактует это как попытку перебора. Кажется, что атака, а на деле штатный провижининг.curl на самого себя. Healthcheck'и мониторинга обращаются к эндпоинтам раз в 30 секунд – для правила это выглядит как подозрительная HTTP-активность. На практике это просто Prometheus занимается своим делом.
Изменения файлов в /tmp. CI/CD оставляет там артефакты вроде
wget-log.42, а FIM-модуль реагирует на каждое изменение как на потенциальную компрометацию – и тревожит дежурного инженера в три ночи ради лога wget.
Все три – классический фоновый шум, который маскирует реальные инциденты.
Как пишутся локальные правила
Минимальное правило выглядит так:
<group name="ssh"> <rule id="100002" level="0"> <if_group>ssh</if_group> <match>127.0.0.1|localhost</match> <description>SSH с localhost — провижининг Ansible, не атака</description> </rule> </group>
Разберём по элементам:
id — уникальный номер правила. Диапазон 100000+ зарезервирован под локальные правила, так что коллизий с дефолтными не будет – можно не стесняться.
level — уровень критичности от 0 до 16.
level="0"полностью подавляет алерт, высокие значения эскалируют событие (15 – это уже «будите дежурного»).if_group — группа правил, к которой привязывается логика.
match — шаблон поиска по содержимому лога.
description — текст, который увидит дежурный аналитик. Здесь стоит писать по делу и понятно: не «SSH auth from loopback», а явное указание, что это за событие и почему оно безопасно. В три часа ночи коллега скажет спасибо.
Оптимизация и профилирование
После первого набора правил имеет смысл замерить, как изменилась нагрузка и не появились ли побочные эффекты.
wazuh-logtest
Основной инструмент отладки – утилита wazuh-logtest. Она принимает строку лога и показывает, какое правило сработало, с каким уровнем и по какой причине:
# wazuh-logtest 2026 May 15 10:42:00 sshd[12345]: Failed password for root from 127.0.0.1 port 22 ssh2
С ней процесс настройки правил становится гораздо предсказуемей. По сути это try/catch: прогнал лог, увидел результат, поправил.
Что дало наибольший эффект:
-
Замена regex на match там, где это возможно
Регулярные выражения красивы, но дороги по производительности. На больших объёмах логов простое сопоставление по подстроке заметно экономит ресурсы.
-
Корректная настройка frequency и timeframe
frequencyзадаёт число срабатываний заtimeframeсекунд. Стандартный порог детекта брутфорса – 10 попыток за 60 секунд – не подходит для localhost, где Ansible легко генерирует сотню обращений за десяток секунд. Порог пришлось пересмотреть, а для localhost вынести отдельное правило-исключение. -
Правила-исключения через
if_sidВместо переписывания дефолтного правила добавляется исключение, которое подавляет срабатывание в конкретном случае:
<rule id="100003" level="0"> <if_sid>5710</if_sid> <match>127.0.0.1</match> <description>Исключаем localhost из детекта брутфорса</description> </rule> Группировка правил. Локальные правки логично разнести по группам (
sshd,fim,apache), а не размазывать по конфигу. Это упрощает поддержку и аудит – и вам, и тем, кто полезет в конфиг после вас.
Грабли, на которые стоит обратить внимание
Один показательный случай. Я написал правило, детектирующее wget к определённому URL. Через неделю аналитик сообщил о срабатывании каждые пять минут – оказалось, под правило попадал наш собственный мониторинг, скачивающий обновления. Решилось добавлением if_sid на событие мониторинга.
Так что прежде чем включать правило в продакшен, убедитесь, что не станете его первой жертвой сами. Здесь снова выручает wazuh-logtest – прогон реальных логов до выкатки экономит много времени и нервов.
Результат. После настройки поток ложных алертов снизился до уровня, при котором аналитики перестали их игнорировать. А значимые события – например, реальные попытки доступа – стали заметны на чистом фоне. Один из коллег прокомментировал это так: «Я впервые за месяц увидел реальную атаку, а не Ansible».
Выводы
Писать правила несложно – сложно не навредить. Каждый
level="0"потенциально скрывает атаку, а неаккуратныйmatchспособен отсечь важное событие. Любое подавляющее правило стоит проверять на боевых логах.Исключения важнее переопределений. Не переписывайте дефолтные правила – добавляйте исключения поверх них. По сути это паттерн Decorator: расширяем поведение, не меняя исходное.
Документируйте описания.
descriptionчитают дежурные аналитики, в том числе ночью. Понятная формулировка ускоряет разбор и снижает число эскалаций.XML не страшен. Формат многословный, но предсказуемый и вполне рабочий, если соблюдать структуру и держать правки в отдельных файлах.
Грамотно настроенный Wazuh из источника шума превращается в рабочий инструмент мониторинга. Главное – относиться к набору правил как к живой конфигурации: её нужно поддерживать и пересматривать по мере того, как меняется инфраструктура.
Описанная история – про то, сколько ресурсов уходит, чтобы мониторинг приносил пользу, а не будил инженера среди ночи из-за
wget-log.42. Настройка правил, отсев ложных срабатываний, разбор логов и реакция на инциденты требуют рук и экспертизы, которых у небольшой команды часто не хватает.Эту нагрузку можно делегировать. Cloud4Y предоставляет мониторинг в администрировании: анализ логов, умные оповещения с уведомлениями в Telegram и единая панель, где видны метрики и узкие места инфраструктуры. Алерты настраиваются только по значимым событиям. Тонкую настройку и развёртывание берут на себя инженеры провайдера.
А для новых клиентов с Хабра действует скидка 20% по промокоду HABR20 на услуги Cloud4Y, подробности на странице акции.
Granulex
local_rules.xml – правильный слой для исключений. Есть более ранний и эффективный уровень: ossec.conf на самих агентах. События, отфильтрованные там, не достигают менеджера вообще – ни трафик, ни CPU на парсинг. Wazuh часто начинают тюнить с правил, тогда как дефолтные настройки syscheck мониторят /tmp, /dev и всё подряд. Половину шума можно убрать ещё до написания первого XML-правила.