Wazuh на прод: как развернуть SIEM правильно
- DESCRIPTION
- Практический гайд по боевому развёртыванию Wazuh — архитектура, сбор событий, правила, тюнинг ложняков и подводные камни, на которые наступают все.
- DATE
- · 10 min read
Развернуть 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 на старте ловит мало и честно показывает, где слеп. Неправильно развёрнутый — ловит «много» и врёт, что всё под контролем. Выбирай первое.