Когда у компании сотни серверов, а на них — тысячи сайтов клиентов, атаки идут постоянно: перебор паролей, сканирование, попытки загрузить веб-шелл, эксплуатация уязвимостей CMS. Без централизованного мониторинга о взломе узнаёшь от клиента или от абузы. Я пришёл в ИБ из системного администрирования и строил SOC-контур в хостинг-компании с нуля. В этой статье — что получилось, как это устроено и на какие грабли я наступил.

Все имена серверов, IP-адреса, учётные записи и внутренние детали в статье заменены на условные. Цифры округлены.

Почему Wazuh

Требования были простые: open source, без лицензий за каждый агент, агенты под Linux и Windows, готовые правила детектирования и возможность расти до нескольких сотен узлов. Wazuh закрывает это из коробки:

  • SIEM — сбор и корреляция событий, тысячи готовых правил и декодеров;
  • XDR-функции — контроль целостности файлов (FIM), аудит конфигурации (SCA), инвентаризация ПО и поиск уязвимостей, активный ответ;
  • агенты для Linux, Windows, macOS, плюс приём syslog с сетевых устройств;
  • кластеризация серверной части и индексатора на базе OpenSearch.

Wazuh состоит из четырёх компонентов: агенты на хостах, сервер (анализирует события декодерами и правилами), индексатор (хранит и ищет алерты) и панель (веб-интерфейс).

Архитектура

Один сервер «всё в одном» подходит для теста, но не для сотен агентов: упираешься в CPU на анализе и в диск на индексации, а падение одной машины выключает весь мониторинг. Поэтому сразу закладывал кластер:

Агенты (300+)
     │  1514/tcp события, 1515/tcp регистрация
     ▼
wazuh-lb ── HAProxy, leastconn
     │
     ├── wazuh-master   master-сервер + панель
     ├── wazuh-node1    worker + индексатор
     ├── wazuh-node2    worker + индексатор
     └── wazuh-node3    worker + индексатор

Пользователи ──► edge-nginx (TLS + allow-list) ──► панель Wazuh, панель триажа, OpenCVE

Ключевые решения:

  • Агенты ходят только на балансировщик, а не на конкретный сервер. Можно добавлять и выводить узлы, не трогая агентов.
  • Три узла индексатора — кворум и реплики шардов: выход одного узла из строя не теряет данные.
  • Вся межузловая связь — по приватной сети. Наружу смотрят только балансировщик (для агентов) и edge-прокси (для людей).

Ориентир по ресурсам, который сработал у меня: около 100 агентов на узел при 8 vCPU, 8 ГБ RAM и 200 ГБ диска для хранения 90 дней. Реальная нагрузка сильно зависит от шумности источников — об этом ниже.

Установка кластера

Wazuh даёт установочный скрипт и файл конфигурации, в котором описываются все узлы:

curl -sO https://packages.wazuh.com/4.11/wazuh-install.sh
curl -sO https://packages.wazuh.com/4.11/config.yml
nodes:
  indexer:
    - name: wazuh-in1
      ip: "10.0.0.5"
    - name: wazuh-in2
      ip: "10.0.0.6"
    - name: wazuh-in3
      ip: "10.0.0.8"
  server:
    - name: wazuh-master
      ip: "10.0.0.4"
      node_type: master
    - name: wazuh-worker1
      ip: "10.0.0.5"
      node_type: worker
    - name: wazuh-worker2
      ip: "10.0.0.6"
      node_type: worker
  dashboard:
    - name: dashboard
      ip: "10.0.0.4"

Дальше скрипт генерирует сертификаты и пароли для всего кластера (wazuh-install.sh --generate-config-files), архив раскладывается на все узлы, и компоненты ставятся по очереди: индексаторы, инициализация кластера индексатора, серверы, панель. Совет: сохраните сгенерированный архив с сертификатами в надёжном месте — он понадобится при добавлении новых узлов.

Балансировка агентов через HAProxy

Агенты используют два порта: 1515/tcp для регистрации и 1514/tcp для отправки событий. Оба балансируются в TCP-режиме:

frontend wazuh_register
    mode tcp
    bind :1515
    default_backend wazuh_register

backend wazuh_register
    mode tcp
    balance leastconn
    server master  10.0.0.4:1515 check
    server worker1 10.0.0.5:1515 check
    server worker2 10.0.0.6:1515 check

frontend wazuh_reporting
    mode tcp
    bind :1514
    default_backend wazuh_reporting

backend wazuh_reporting
    mode tcp
    balance leastconn
    server master  10.0.0.4:1514 check
    server worker1 10.0.0.5:1514 check
    server worker2 10.0.0.6:1514 check

leastconn отправляет новое соединение на узел с наименьшим числом активных подключений — агенты держат долгие соединения, поэтому round-robin распределял бы их неравномерно. Для автоматического добавления и удаления узлов в бэкенде пригодится HAProxy Dataplane API (helper от Wazuh), но его API стоит слушать только на локальном адресе.

Защита самого SOC

SIEM — лакомая цель: в нём видно всю инфраструктуру, а агенты на сотнях серверов. Поэтому кластер закрыт по принципу «запрещено всё, что не разрешено»:

  • Файрвол на каждом узле (у меня CSF): входящие порты закрыты, исключения только для приватной подсети кластера и адресов корпоративного VPN. Исходящий трафик — только нужные порты (DNS, NTP, HTTPS для обновлений).
  • SSH только по ключам, вход по паролю отключён.
  • Веб-интерфейсы не торчат наружу напрямую. Панель Wazuh, панель триажа и OpenCVE опубликованы через отдельный edge-nginx, который завершает TLS и пускает только разрешённые IP. Бэкенды слушают приватные адреса.
  • Регистрация агентов по паролю. Без этого любой, кто знает адрес балансировщика, может зарегистрировать «свой» агент и засорить данные:
<auth>
  <use_password>yes</use_password>
</auth>

Пароль кладётся в /var/ossec/etc/authd.pass на всех узлах сервера с правами 640 и владельцем root:wazuh.

Группы агентов

Серверы в хостинге очень разные: shared-хостинг, внутренние веб-приложения, сетевые устройства, офисные рабочие станции. Им нужны разные правила сбора и разный уровень шума. Wazuh позволяет объединять агентов в группы и раздавать каждой группе свой agent.conf. Агент может состоять в нескольких группах, и его можно перенести между группами без переустановки:

/var/ossec/bin/agent_groups -a -i <AGENT_ID> -g webapp -q      # добавить в группу
/var/ossec/bin/agent_groups -r -i <AGENT_ID> -g shared-hosting -q  # убрать из старой
/var/ossec/bin/agent_groups -S -i <AGENT_ID>                    # проверить синхронизацию

Урок, который я усвоил: «агент подключён» не значит «нужные события приходят». На RHEL-подобных системах (CloudLinux, AlmaLinux) успешные SSH-входы пишутся в /var/log/secure, и в стандартной конфигурации этот файл не собирался — Wazuh видел события аудита, но не видел сами входы. Исправилось одним блоком в групповой конфигурации:

<localfile>
  <log_format>syslog</log_format>
  <location>/var/log/secure</location>
</localfile>

После изменения групповых конфигов проверяйте их утилитой verify-agent-conf и выборочно смотрите активную конфигурацию на агентах. И всегда делайте тест: выполните действие, которое должно породить алерт, и убедитесь, что он пришёл.

Интеграции и учёт уязвимостей

Wazuh хорош как центр, но не закрывает всё сам. Что я пробовал и к чему пришёл:

  • Suricata (сетевой IDS). Поднимал и тестировал: агент Wazuh читает eve.json, и сетевые алерты попадают в ту же панель, что и события хостов. Как это настроить, я описал в отдельной статье про Suricata + ELK. Но мой вывод после тестов: для защиты периметра компании практичнее хороший NGFW — он и видит трафик, и сразу его блокирует, а самописная связка IDS требует постоянного внимания. Мы протестировали NGFW практически всех вендоров, представленных на рынке, и больше всего мне понравился Palo Alto Networks.
  • DefectDojo — учёт уязвимостей. Wazuh находит уязвимое ПО на агентах, а вести по нему работу (кто исправляет, что принято как риск, что закрыто) удобнее в отдельной системе. Для переноса находок я написал скрипт wazuh-to-dojo. DefectDojo проработал какое-то время, но для нашего объёма оказался слишком тяжёлым: при импорте сотен тысяч находок падал по памяти. В итоге я заменил его собственной панелью триажа — об этом ниже.
  • OpenCVE — отслеживание новых CVE по продуктам, которые реально используются в инфраструктуре.

Главная боль: шум алертов

Через несколько месяцев работы я сделал срез и понял, что SIEM превратился в «пожарный шланг», а не в очередь инцидентов:

  • миллионы алертов в сутки, десятки в секунду;
  • два правила давали около трёх четвертей всего недельного объёма, три правила — почти 90%;
  • даже алерты высокого уровня (level >= 10) почти целиком состояли из веб-корреляций на shared-хостинге: сканеры и боты бьют по сайтам клиентов круглосуточно.

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

  1. Сбор и нормализация. Источники разделены по типам (веб-хостинг, базы данных, приложения, сетевое оборудование, рабочие станции), для каждого известен ожидаемый уровень шума.
  2. Подавление. Малоценные правила переводятся в level=0 или исключаются; из контроля целостности убираются пути кэшей, логов и временных файлов; общие веб-правила на shared-хостинге приглушаются. Телеметрия при этом остаётся в индексе для поиска.
  3. Корреляция в «кандидаты в инциденты». Алерт становится кандидатом только при сочетании условий: например, перебор паролей + необычная учётка + внешний источник + критичный актив; или изменение файла в критичном пути + неожиданный процесс + продуктивный сервер.
  4. Обогащение только кандидатов: критичность актива, владелец, GeoIP/ASN и репутация, контекст уязвимостей, связанные события.
  5. Кейсы в системе реагирования — только то, что прошло все фильтры.

Главный вывод: ценность SIEM определяется не количеством собранных событий, а качеством того, что доходит до человека. Настройка шума — не разовая задача, а постоянная работа.

Что показала эксплуатация

Через год работы у меня накопились претензии к самому Wazuh, о которых стоит знать заранее:

  • Конфликт с Imunify360. На серверах хостинга, где стоит Imunify360, агент Wazuh с ним конфликтует. Для хостинг-компании, где Imunify360 — один из основных инструментов защиты серверов, это серьёзная проблема.
  • Устаревшие уязвимости в панели. Модуль поиска уязвимостей иногда не снимает находку после обновления пакета: пакет уже обновлён, а уязвимость продолжает висеть в панели. Для триажа это означает ложную работу — каждую находку приходится перепроверять.

Поэтому сейчас я рассматриваю переход на Elastic Security. Архитектурные принципы из этой статьи — балансировка, защита самого SOC, группы источников, борьба с шумом — от выбора продукта не зависят и переносятся как есть.

Что дальше

Учёт уязвимостей уже переехал в собственную панель триажа Qalqan: она собирает уязвимости с серверов, обогащает их данными CVSS, EPSS и CISA KEV и отсекает ложные срабатывания, когда уязвимость уже закрыта бэкпортом вендора. Следующий шаг — автоматизация триажа и разбора SOC-инцидентов с помощью ИИ: при тысячах серверов ручной разбор уязвимостей — это сотни человеко-дней, и без автоматизации небольшой команде его не осилить.

Итоги

  • Кластер Wazuh с балансировщиком перед агентами масштабируется добавлением узлов и переживает падение одного из них.
  • Сам SOC нужно защищать не хуже остальной инфраструктуры: закрытые порты, VPN, TLS, пароль на регистрацию агентов.
  • Группы агентов позволяют держать разные правила для разных типов серверов — и обязательно проверяйте, что нужные события действительно приходят.
  • Учёт уязвимостей нужен отдельно от SIEM — и инструмент должен выдерживать ваш объём; когда DefectDojo перестал справляться, помогла своя панель.
  • Проверяйте совместимость SIEM-агента с остальной защитой серверов до массового развёртывания.
  • Самое сложное — не поставить SIEM, а сделать так, чтобы он показывал инциденты, а не шум.

Если строите что-то похожее и хотите обсудить архитектуру — пишите в Telegram.