Wazuh на прод: как развернуть SIEM правильно

DESCRIPTION
Практический гайд по боевому развёртыванию Wazuh — архитектура, сбор событий, правила, тюнинг ложняков и подводные камни, на которые наступают все.
DATE
· 10 min read
Wazuh на прод: как развернуть SIEM правильно

Развернуть Wazuh по гайду из документации — полчаса. Сделать так, чтобы он реально ловил атаки, не захлёбывался и не топил дежурного ложняками — месяцы. Эта статья про второе: что я вынес из боевого внедрения на сотни Windows-хостов. Без «установите пакет и наслаждайтесь» — только то, на чём спотыкаешься.

TL;DR списком в конце.


1. Архитектура: не экономь на разделении ролей

Соблазн поставить всё на один сервер велик, и для лабы он оправдан. На проде — нет.

  • Indexer (OpenSearch) — отдельно, в кластере из 3 нод. Это не про «надёжность на бумаге», а про то, что при реальном потоке одна нода уходит в GC-паузы и теряет события.
  • Manager (analysisd + remoted) — отдельно. Именно он декодирует и прогоняет правила по каждому событию. Это главный лимит по нагрузке (см. раздел 10), и делить его с индексером — значит ловить деградацию обоих под пиком.
  • Dashboard — можно рядом с менеджером, он лёгкий.

Сайзинг считай по EPS (events per second), а не по числу агентов. 100 тихих файл-серверов дают меньше потока, чем 10 нагруженных DC с Sysmon. Диск при этом почти никогда не узкое место: алерты весят мало, индексятся только события с уровнем правила > 0 (об этом ниже). Упрёшься в CPU/RAM менеджера и heap индексера раньше, чем в диск.


2. Сбор, а не firehose — правило №1

Самая частая ошибка — «соберём всё, разберёмся потом». Всё — это терабайты шума, которые кладут analysisd и превращают дашборд в болото. Но и обратная крайность (собирать слишком узко) создаёт слепые зоны, о которых ты узнаёшь во время инцидента.

Фильтруй на источнике, в конфиге сбора. На Windows это localfile с запросом по каналу:

<localfile>
  <location>Security</location>
  <log_format>eventchannel</log_format>
  <query>Event/System[EventID=4625 or EventID=4672 or EventID=4720 or
    EventID=4728 or EventID=4732 or EventID=4740 or EventID=4697 or
    EventID=1102]</query>
</localfile>

Что собирать всегда: неудачные входы (4625), спец-привилегии (4672), жизненный цикл учёток (4720/4722/4725/4726), изменения групп (4728/4732/4756), установка служб (4697), очистка журнала (1102), политика аудита (4719), PowerShell ScriptBlock (4104).

Подводный камень — что ты осознанно теряешь. Чтобы сбить объём, многие (и я) выкидывают из сбора 4624 (успешный вход) и 4768/4769 (Kerberos). Это разумно для нагрузки, но запомни цену:

  • без 4624 ты не подтвердишь успех после серии неудачных входов — видишь брут, но не видишь, вошёл ли он;
  • без 4768/4769 ты слеп к golden/silver ticket и Kerberoasting.

Это не повод собирать их firehose'ом. Это повод собирать точечно: 4624 только по Logon Type 10 (RDP) или по привилегированным учёткам; 4769 только с типом шифрования RC4 (0x17) на DC. Решение осознанное, а не «по умолчанию выключено и забыли».


3. Агенты: группы и централизованный конфиг

Не настраивай агентов поштучно. Используй группы и общий agent.conf на менеджере — конфиг разъезжается сам, рестарт не нужен.

# создать/назначить группу
/var/ossec/bin/agent_groups -a -i <ID> -g windows_servers
# что в группе
/var/ossec/bin/agent_groups -l -g windows_servers

Разные профили сбора — разным группам: на рядовых серверах один набор EventID, на контроллерах домена — расширенный (там живут 4771/4776, Kerberos, изменения AD). Новый агент ставишь сразу с нужной группой (WAZUH_AGENT_GROUP в MSI) — и он с первой секунды получает правильный конфиг.

Подводный камень — массовая установка падает не там, где кажется. Когда раскатка агентов валится с «нет сети», первый рефлекс — винить скрипт. Почти всегда это сегментация сети, а не скрипт:

  • установка пушем (PsExec/WMI) требует 445 с install-хоста до цели — а между пользовательским и серверным сегментом он часто закрыт;
  • сам агент требует 1514/1515 от цели до менеджера — проверь, что цель видит менеджер, иначе агент встанет, но на связь не выйдет.

Прежде чем гнать пачку — прогони быструю проверку 445 по списку и раздели на «доступно» и «нет сети». Второй список идёт сетевикам заявкой, а не в бесконечные ретраи.


4. Правила: три ловушки, которые съедят твоё время

Здесь живёт больше всего «почему оно не работает».

Ловушка 1: level-0, или «событие собирается, но его нигде нет»

Wazuh индексирует и алертит только события, чьё сработавшее правило имеет уровень > 0. Классика: включаешь аудит установки служб, видишь 4697 в сыром журнале Windows, а в дашборде — ноль. Паникуешь, что сбор не работает. На деле 4697 матчит встроенное правило с level 0 — событие декодируется и молча отбрасывается из индекса.

Лечится своим правилом, которое поднимает уровень:

<rule id="100300" level="12">
  <if_group>windows</if_group>
  <field name="win.system.eventID">^4697$</field>
  <field name="win.eventdata.serviceName" type="pcre2">(?i)(PSEXESVC|PAExec|RemCom)</field>
  <description>Lateral movement: установлена служба удалённого выполнения</description>
</rule>

Если считаешь, что слеп — сначала проверь, не level-0 ли это. Очень часто «слепота» — это просто неподнятый уровень.

Ловушка 2: shadowing, или «моё правило не срабатывает»

Пишешь кастомное правило через decoded_as, а оно молчит, хотя событие приходит. Причина — его перехватывает встроенное leaf-правило, которое оказывается «выше» в дереве и забирает событие себе. Одно событие = одно правило (срабатывает одно, не все подходящие).

Лечится привязкой своего правила как дочернего к встроенному — через if_sid/if_group, а не decoded_as. Так оно попадает в то же дерево и выигрывает по уровню. Для Sysmon, например, цепляешься к группе события:

<rule id="100421" level="14">
  <if_group>sysmon_event1</if_group>
  <field name="win.eventdata.commandLine" type="pcre2">(?i)(comsvcs\.dll.{0,20}minidump|procdump.{0,30}lsass|mimikatz)</field>
  <description>Возможный дамп памяти LSASS</description>
</rule>

Ловушка 3: шумные встроенные правила

Часть встроенных правил дублирует твою корреляцию грубее и без фильтров — и генерит основной объём алертов. Их не надо терпеть: переопредели уровень через overwrite="yes", оставив свою точную корреляцию работать:

<rule id="60204" level="10" frequency="8" timeframe="240" overwrite="yes">
  <if_matched_group>authentication_failed</if_matched_group>
  <same_field>win.eventdata.ipAddress</same_field>
  <field name="win.eventdata.targetUserName" type="pcre2" negate="yes">\$$</field>
  <description>Множественные отказы входа (машинные учётки исключены)</description>
</rule>

5. Тюнинг ложняков: чини источник, не глуши вслепую

Правило не должно молчать «потому что шумит». Разбирайся, почему шумит.

  • Концентраторы аутентификации. Почтовый сервер, VPN, RD Gateway пропускают через себя входы многих пользователей → «один IP, много учёток» → правило password spraying срабатывает ложно. Нельзя просто внести IP в исключения — ослепнешь к реальному спрею через этот же узел (а почта/OWA — любимый вектор). Правильно: подними порог для этого IP, а брут-по-одной-учётке оставь. И почини настоящие источники шума — обычно это пара учёток с протухшим паролем в почтовом клиенте.
  • Машинные и сервисные учётки. Отключённые машинные аккаунты (ИМЯ$) и личные учётки, прописанные как сервисные, дают постоянный фон отказов. Машинные — исключай (targetUserName на $). Сервисные — это не задача SIEM, а организационная: учётки используются не по назначению, их надо переносить на выделенные/gMSA.
  • Платформенные процессы читают lsass. VMware Tools (плагин appInfo), антивирус, бэкап-агенты легитимно обращаются к памяти lsass — и твоё правило на дамп кредов срабатывает на них. Исключай по полному пути процесса (не по имени — переименуют), а при разборе читай callTrace: легитимный источник — стек из своих подписанных DLL; дамп — стек через dbghelp.dll/comsvcs.dll/MiniDumpWriteDump.

Главное правило тюнинга: подавление — всегда с комментарием «почему» и, если временное, с датой снятия. Это и аудитору доказательство, что шум убран осмысленно, и тебе через полгода напоминание.


6. Sysmon — отдельный зверь, разворачивай последним и аккуратно

Sysmon даёт поведенческий слой (процессы, доступ к памяти, сеть, пайпы), без которого половина детектов мертва. Но он же — главный источник нагрузки.

  • Объём. Популярный конфиг SwiftOnSecurity в ProcessCreate работает в режиме exclude — то есть логирует почти все запуски процессов. На нагруженном сервере это тысячи событий в секунду. Умножь на парк — и упрёшься в analysisd.
  • Раскатывай волнами. Сначала 2–3 хоста, смотришь нагрузку, потом расширяешь. Не вся сотня разом.
  • Выгреби платформенные ложняки ДО массы. Все виртуалки дадут один и тот же FP (тот же VMware, читающий lsass). Поймай его на пилоте и внеси исключение один раз — иначе получишь сотню одинаковых критичных алертов в первый же час раскатки.

И да — Sysmon не требует аудита Windows, он независим. Это его плюс: можно получить телеметрию процессов там, где политику аудита править долго.


7. Оповещения: порог, а не спам

Интеграция в мессенджер (Telegram через n8n, почта, что угодно) должна слать только то, что требует реакции человека. Поставь порог по уровню (например, уровень ≥ 10 — в Telegram, остальное живёт в дашборде). Если дежурный начинает игнорировать канал — ты уже проиграл: настоящий алерт утонет в шуме. Alert fatigue убивает SIEM вернее, чем отсутствие правил.


8. Retention и комплаенс: дефолт слишком короткий

Wazuh из коробки хранит алерты ~ недели. Для PCI DSS нужно минимум год, из них 3 месяца в немедленном доступе. Диск это легко тянет (алерты весят мало), так что:

  • управляй сроком через ISM-политики OpenSearch (Index State Management), а не руками;
  • онлайн держи ≥ 90 дней, полный год — через снапшоты в отдельный репозиторий (NFS/S3-совместимый).

Подводный камень: правка ISM-политики не применяется задним числом к уже управляемым индексам — они доигрывают старую версию. После изменения срока переприменяй политику к существующим индексам, иначе новый retention подхватят только новые.


9. Мониторь сам SIEM

SIEM, который молча теряет события, хуже отсутствующего — он даёт ложное чувство защиты. Главный датчик здоровья — состояние analysisd на менеджере:

grep -E 'events_received|events_dropped|event_queue_usage|rule_matching_queue_usage' \
  /var/ossec/var/run/wazuh-analysisd.state

events_dropped должен быть 0, очереди — далеко от 1.0. Если dropped растёт или очередь近 к единице — менеджер захлёбывается: либо туже фильтруй сбор, либо добавляй ресурсов. Проверяй это после каждой волны подключения агентов и особенно после раскатки Sysmon. Heap индексера держи < 75%.


10. Карта покрытия: что ты реально видишь, а не что написал

Финальный и самый отрезвляющий шаг. Сматчи свои правила на MITRE ATT&CK (ATT&CK Navigator), а источники сбора — через DeTT&CT. Получишь две карты: детект (что ловишь) и видимость (что физически способен увидеть).

Самое ценное — наложить одно на другое и найти технику, которая зелёная в детекте, но красная в видимости: правило написано, а данных под него нет. Классика — весь Sysmon-набор, пока Sysmon стоит на одном пилотном хосте: на бумаге ловишь, по факту слеп на 99% парка. Это переводит разговор с руководством из «дайте денег на SIEM» в «вот карта, вот конкретные дыры, вот что их закроет».


Чеклист

  • Роли разнесены: indexer-кластер / manager / dashboard. Сайзинг по EPS, не по числу агентов.
  • Сбор отфильтрован на источнике. Зафиксировано, что осознанно НЕ собираешь (4624/4768) и почему.
  • Агенты — через группы и общий agent.conf, не поштучно.
  • Перед массовой установкой проверена связность: 445 до цели, 1514/1515 до менеджера.
  • Проверено, что ключевые события не теряются на level-0 (подними уровень своим правилом).
  • Кастомные правила привязаны через if_sid/if_group, а не decoded_as (иначе shadowing).
  • Шумные встроенные правила переопределены (overwrite), не оставлены как есть.
  • Ложняки убраны с пониманием причины: концентраторы — порогом, не исключением IP; платформенные процессы — по полному пути.
  • Sysmon раскатан волнами, платформенные FP выгреблены на пилоте.
  • Оповещения — по порогу уровня. Канал не спамит.
  • Retention под комплаенс (ISM + снапшоты). Политика переприменена к старым индексам.
  • events_dropped = 0, очереди в норме. Мониторится после каждой волны.
  • Покрытие сматчено на ATT&CK. Найдены «детект без видимости».

SIEM — это не продукт, который «внедрил и готово», а процесс. Правильно развёрнутый Wazuh на старте ловит мало и честно показывает, где слеп. Неправильно развёрнутый — ловит «много» и врёт, что всё под контролем. Выбирай первое.