
Долгие годы вендоры работали над тем, чтобы сделать UI в SIEM удобным, эффективным и простыми для аналитиков SOC, а теперь аналитики хотят код, git, vim. Упс.
Привет! Меня зовут Павел Таратынов, я лид аналитиков L3 в VK SOC, и в этой статье я расскажу, почему и зачем мы перешли на Detection as code, какие бенефиты от этого получили и стоит ли игра свеч. Поехали!
Как мы докатились до жизни такой
Жили мы себе, поживали, проблем не знали, как и многие, на елке (она же Elastic Stack). Пилили контент в UI, алерты разбирали там же (сейчас уже в SOAR, но это другая история), описание правил и источников вели в Confluence. Казалось бы — все работает, процессы налажены, все довольны. Но как говорит лид нашей разработки: «Есть нюанс» ©.

Со временем у нас накопилось более 1К правил, и управлять такой огромной базой с помощью стандартных средств UI и описания в Confluence стало невозможно. К тому же, все чаще возникал вопрос с правами на создание или редактирование правил: с одной стороны, за детектирующую логику и ее качество полностью отвечает L3, а с другой — L1 необходимо делать простые фильтрации правил круглосуточно (то есть в нерабочее для L3 время, которые работают 8×5), и поэтому им тоже нужны права на правку правил. Еще были запросы от безопасников из соседних бизнес‑юнитов, которые хотели создавать свои кастомные правила для себя напрямую. И таких нюансов становилось все больше и больше.
Постоянно возникали следующие вопросы и задачи:
как контролировать качество вносимых изменений?
кто, когда, зачем и как именно изменил конкретное правило? А если автор изменений забыл, заболел, в отпуске?
как контролировать качество детектирующей логики?
как убедиться, что никто при правках случайно не сломает правило корреляции?
как убедиться, что при создания тяжелого правила, нагрузка на SIEM не будет слишком большой?
какие источники данных и политики логирования требуются для работы правил?
какие TTP мы закрываем и как именно?
как провести массовые изменения во всех правилах?
и так далее, и так далее...
Священный Грааль
И тут мы обратили свое внимание на концепцию Detection as code (DaC).

Я, кстати, был уверен, что про подход Detection as code на Хабре написано уже немало, но, обнаружил, что статей на эту тему практически нет. Точнее есть, но они все в основном про Infrastructure as code или Documentation as code. Разве что, вот тут коллеги описали свой опыт на эту тему. Что ж давайте все же коротко вспомним, что это за концепция Detection as code (DaC) и чем она может пригодиться нам, разработчикам детектирующей логики.
Основная идея DaC заключается в том, чтобы взять зрелые, отработанные подходы по разработке ПО, ревью, тестированию и деплою кода, и применить их к разработке детектирующей логики (правил корреляции, в нашем случае).

Чтобы это сработало, правила корреляции должны полностью описываться текстом, «кодом» — обычно с помощью DSL, а не языка программирования, но возможны разные варианты. Описание правил кодом в теории дает нам широкие возможности по контролю изменений, тестированию кода перед деплоем и автоматизации всего и вся. Посмотрим, что у нас получилось на практике.
Про попытки перехода
Хотя мы и находились в процессе миграции с елки (elk) на другой SIEM, первый подход мы все же решили сделать именно к елке. Почему? Во‑первых, у нас была надежда, что это позволит существенно упростить и автоматизировать процесс анализа и миграции правил. Во‑вторых, для елки существуют хорошие гайды, статьи, документированный API, тулзы от разработчиков для перехода на DaC (репозиторий с правилами, скриптами для конвертации, тестирования, и тд.).
Но «есть нюанс». Чтобы в моменте не сломать устоявшиеся процессы, было необходимо сохранить возможность редактирования и через UI, в том числе. А это сильно усложняет схему, ведет к потенциальным конфликтам и неопределенности. С учетом того, что миграция на другой SIEM была в процессе, мы, оценив затраты и риски после первых тестов, решили просто не тратить на это ресурсы. Но в целом, это вполне рабочее решения для применения DaC.
Позже при миграции на новый SIEM мы обнаружили, что там нет официально поддерживаемого API и DSL, чтобы с уверенностью использовать DaC. В общем, это и многое другое окончательно убедило нас в том, что ни одно из «коробочных» решений, присутствующих на рынке, нам не подходит.
Новая надежда

В итоге мы решили создать свой собственный SIEM, который будет отвечать следующим требованиям:
высокая производительность (до 3М+ EPS, при разумном потреблении ресурсов, и c возможностью дальнейшего масштабирования);
горизонтальная масштабируемость и отказоустойчивость всех компонентов;
возможность быстрого внесения изменений, короткий цикл разработки;
отсутствие vendor‑lock для ключевого компонента SOC;
ну и, конечно же, поддержка Detection as code из коробки!
Рассказ про VK SIEM не в формате этой статьи, но если интересны подробности, то посмотрите вот этот доклад. Скажу только то, что мы получили все, что хотели и даже немного больше. К тому же, разработчики «сидят с нами за соседними столами», а это всегда отличная возможность для быстрого внедрения нужных нам фич.
Наш workflow
Итак, как же устроена наша работа с применением DaC? Сразу скажу, что на данный момент мы пришли к такой схеме, но мы все еще в процессе улучшений.
У нас есть продовый (prod) и стейдж (stage) кластеры коррелятора, что позволяет нам проверить работу правил в динамике, снять метрики, поработать с фолзами на реальных логах еще до деплоя правил в прод.
На стейдж кластер льется порядка 10% реальных логов с инфры, продовый кластер естественно обрабатывает все, что на данный момент составляет порядка 1.2М EPS.
-
Плюс у нас есть лаба (TTP Lab на схеме), где мы можем сгенерировать нужные нам события.
В качестве CI/CD инфраструктуры мы используем Bitbucket, Gitlab, Teamcity и Nexus. Bitbucket выступает в качестве единого источника истины в части правил корреляции и конфигов SIEM.
-
За настройку и эксплуатацию всей CI/CD инфраструктуры и автоматизацию отвечает выделенная команда DevOps, c этим нам повезло. Аналитики L3 здесь больше играют роль «внутренних заказчиков».
Каждому кластеру (stage и prod) соответствует своя ветка в git (соответственно stage и prod). При работе с правилом, аналитик сначала отводит локальную ветку от stage и работает с ней, натравливает локальные тесты, и т. д. Да, unit тесты можно запускать локально, чтобы отловить ошибки еще до мерджа.
Затем, уже по готовности, аналитик мерджит локальную ветку в stage — здесь уже запускаются тесты и валидация на pipeline gitlab.
-
Тесты проверяют корректность заполнения meta‑информации правил, корректность синтаксиса, сработку правил на тестовые события. Ну и в целом, что коррелятор не упадет при деплое.
-
Для этого на pipeline собирается и запускается актуальная стабильная версия коррелятора и прогоняются тестируемые правила.
Если тесты прошли успешно, правила деплоятся на stage кластер, где аналитик уже может поработать с реальными логами, фолзами, отследить метрики работы правил, погенерить события с лабы.
-
Метрикам работы правил мы уделяем особое внимание, ведь на нашем потоке (1,2М+ ЕPS) и довольно легко забрать очень много ресурсов одним неудачным тяжелым правилом. Поэтому мониторим время запуска в контексте каждого правила и фильтра, время задержек в обработке событий, количество ошибок, потребляемые ресурсы и многое другое.
Если все хорошо, аналитик мерджит ветку в master. При мердже опять и снова запускаются те же тесты, плюс требуется ревью, если автор не относится к команде аналитиков L3.
Надо отдельно сказать, что правилом нейминга веток является имя‑id правила + id задачи в JIRA. Так легче находить изменения и соответствующую им задачу.
В качестве инструмента разработки мы используем обычный VS Code, но с кастомным расширением — для подсветки синтаксиса, автодополнений, автоматической генерации стандартных элементов (типа метаинформации) и запуска тестов.
The Rules!

Если вам интересно, то вот как выглядят правила вживую. Мы разработали свой DSL на базе S‑expressions. Возможно, в дальнейшем мы перейдем на что‑то более массовое, но мы уже вполне привыкли к тому, что есть.

Синтаксис позволяет:
задать фильтры интересующих событий (filter), с использованием логических конструкций or, not, and, регэкспов и других функций;
паттерны событий, объединяющие фильтры в цепочки событий, а также задать корреляционное окно;
действия (actions) при попадании событий в паттерн — алерт, отправка в мессенджер, шаблон сообщения, трешхолды, и тд;
задавать переменные;
использовать заготовки‑шаблоны, чтобы не переписывать каждый раз однотипные фильтры (например, стандартные пути к шеллам, имена процессов, и тд);
приведение к различным типам, типам регистров, операции сравнения, и многое другое.
Кроме того, для каждого правила в обязательном порядке заполняется метаинформация в отдельном yml-файлике, который описывает:
уникальный id правила,
привязку к use case,
привязку к MITRE TTP,
привязку к источнику событий, политике логирования,
ссылку на гайд по расследованию (investigation guide),
и многое другое, очевидное из скрина.
Эта информация помогает нам анализировать правила, строить взаимосвязи и вести статистику. Например, мы можем быстро ответить на вопросы — какие правила есть для конкретного источника, и наоборот, какие правила написаны под конкретный бизнес‑юнит, как мы закрываем различные TTP и так далее.
Корректность и полнота заполнение метаинформации проверяется на pipeline и является обязательным условием успешного мерджа.

В метаинформации есть как обязательные поля, которые мы хотим видеть всегда, так и опциональные.
Поначалу мы хранили все в одном файле, но в итоге пришли к структуре, когда каждое правило хранится в отдельной директории, где расположены: сам код правила (.cpat), метаинформация (.yml), юнит‑тесты для правила (tests) и эталонные события для проверки сработки правила (raw). Так получается гораздо удобнее с точки зрения автоматизации и парсинга этих файлов.

В чем сила, брат?
Выглядит все это очень хорошо, но в чем профит? Выделю то, что мы получили на практике прямо сейчас:
контроль изменений и разграничение прав к правилам теперь можно делать стандартными средствами git;
версионирование, быстрое сравнение изменений и возможность быстро их откатить;
легко посмотреть кто, когда и как изменил правило;
валидация и авто‑тестирование правил еще до внедрения в прод;
массовые изменения правил;
быстрая аналитика правил и построение статистики — на какой источник политики логирования завязаны, что есть по конкретной ТТР, к какому бизнес юниту применимо, и тд.
автоматизация всего и вся (тут насколько хватит фантазии). Ведь теперь правила — это просто текст. А значит, вся мощь стандартных тулзов типа sed/awk, плюс возможности обработки скриптами и пайплайны CI/CD в наших руках.
А есть ли минусы?
Было бы нечестно говорить, что совсем нет (есть определенный оверхед). Во‑первых, понадобятся усилия и ресурсы DevOps (или аналогичной роли), чтобы внедрить, настроить и поддерживать инфраструктуру CI/CD. Во‑вторых, все же работа в концепции Detection as code требует от аналитиков чуть большей дисциплины, культуры работы с git и компетенций. Но на мой взгляд, это все решаемо и сравнительно быстро нарабатывается даже с небольшими ресурсами, а полученный профит существенно превышает дополнительные усилия.

Выводы и планы
Резюмирую, что мы поняли для себя из опыта по внедрению Detection as code в нашем SOC.
Это не просто красивая теоретическая концепция, а рабочий практический инструмент.
Несет множество плюсов, о них писал выше.
Требует определенных дополнительных затрат ресурсов на начальном этапе, но они быстро окупаются.
Ваш SIEM или другой security control должен поддерживать DaC хотя бы на уровне документированного и официально поддерживаемого API, а лучше DSL, иначе внедрение будет невозможным, либо кратно «дороже» с точки зрения ресурсов. Вам придется разрабатывать и поддерживать всю обвязку самим.
Нужны автотесты на каждом этапе.
Мы же не планируем останавливаться на достигнутом и в дальнейшем хотим:
Сделать весь процесс более юзер‑френдли — вывод ошибок, подсказок, шаблоны типовых элементов в инструментах разработки и так далее.
Вывести часть операций в UI SIEM, сохраняя при этом подход DaC и возможность работы напрямую через git для более продвинутых пользователей. Опять же для снижения порога входа и облегчения работы.
Прикрутить Copilot для ассиста в написании правил.
Больше автоматизаций и авто‑тестов.
Распространить подход Everything‑as‑code на описание use case, playbook, источников.
Вот, пожалуй, все, что я хотел рассказать про наш опыт перехода на Detection as code, и надеюсь, что в следующей статье уже сможем поделиться результатами наших нововведений. Stay tuned.
PS: Буду рад, если в комментариях к статье поделитесь вашим опытом перехода и использования DaC внутри SOC.