- BrainTools - https://www.braintools.ru -
Меня зовут Паша Пилькевич, и я работаю инженером-разработчиком в команде разработки программного обеспечения STEP LOGIC Security Data Lake (SDL).
Эта статья будет полезна для тех, кто работает в центре кибербезопасности (Security Operation Center, SOC) или планирует его построить. Я расскажу о том, как мы решили нетривиальные задачи контент-менеджмента и какие технологии для этого применялись.

Наша платформа предоставляет руководителям и специалистам центров кибербезопасности набор инструментов анализа больших массивов машинных данных для наблюдения за состоянием защищённости вычислительной сети и управления инцидентами информационной безопасности. SDL реализует принцип единого окна доступа к данным о событиях, активах, угрозах и инцидентах. Он обеспечивает их наглядное представление и корреляцию с использованием единого конструктора визуализаций, языков поисковых запросов и описания алгоритмов. Особенности продукта – полноценная мультитенантность, гибкость и встроенная функциональность сразу нескольких классов решений, таких как SIEM и IRP/SOAR.
В SIEM и SOAR системах присутствует набор настроек и алгоритмов анализа данных, которые можно назвать одним словом – контент. К нему относятся дашборды, визуализации, алгоритмы синтаксического анализа и нормализации данных, правила обнаружения инцидентов, правила хранения данных, настройки модели данных и другие сущности. Этот контент необходимо разрабатывать, изменять, переносить между инсталляциями, обновлять, тестировать, контролировать и т. д.
В активно используемых инсталляциях, а особенно, когда система функционирует в мультитенантном режиме, проблема обеспечения актуальности и качества контента становится одной из важнейших. Например, в публичных коммерческих SOC количество сущностей контента и их параметров под одного клиента исчисляется трёхзначными цифрами.
Анализ существующих продуктов подобного класса показал, что эффективное централизованное управление контентом в SOC – нерешённая и острая проблема.
На начальном этапе разработки мы проанализировали проблемные вопросы и определили главные требования к итоговому компоненту.
Определение конфигурации всего контента SDL в удобном формате в одном месте для наглядного анализа и контроля внесения изменений.
Задание эталонного контента с возможностью самостоятельной шаблонизации и параметризации сущностей в формате jinja2 для задания собственных изменяемых параметров и их групп в любом месте.
Поддержка управления конфигурацией как кодом через центральный репозиторий для совместной разработки и бесшовной передачи изменений контента между инсталляциями SDL (встраивание в CI/CD).
Валидация контента на соответствие заданным спецификациям для снижения количества ошибок при его разработке и внесении изменений.
Возможность контроля целостности инсталляции для обеспечения целостности и уверенности, что в production-инсталляции содержится только работоспособный, протестированный и согласованный между собой контент.
Забегая вперёд, хочу сказать, что всё из перечисленного нам удалось. Далее рассказ пойдет о том, как мы реализовали возможность шаблонизации контента.
Шаблон – это текстовый файл, в котором может быть определена логика [1] генерации содержимого с помощью специальных операторов и переменных. Например, вы можете передавать в один и тот же файл различное значение переменной «severity» (низкая, средняя, высокая), а в шаблоне, вместо конкретной важности, обратиться к переменной: %%%severity%%%.

Наше первое концептуальное решение в вопросе контент-менеджмента заключалось в том, чтобы предоставить пользователю не файлы контента, а шаблоны контента.
На выходе пользователь может кастомизировать сущности абсолютно так, как он хочет, опираясь на свои нужды и специфику системы. Особенно полезны возможности использования условных операторов, обычного проброса переменных и, в некоторых случаях, циклов. Это также позволяет предоставлять пользователю автоматически тиражируемый контент. Теперь не нужно беспокоиться о том, что какой-либо префикс не был заменён или что после очередного обновления появилось новое дополнительное тиражируемое поле, которое необходимо добавлять в существовавший до этого модуль тиражирования. То есть операция тиражирования теперь в принципе не является головной болью [2] пользователя, так как она совершается каждый раз автоматически при генерации фактического контента из шаблонов.
В качестве шаблонизатора была выбрана ныне известная библиотека jinja2 ввиду её широкого распространения, удобства использования и наличия всего необходимого функционала.

Как я упомянул ранее, одна из самых важных задач, решаемых с помощью шаблонов, – простая передача переменных в шаблон файла сущности, когда пользователь, например, хочет изменить поведение [3] правила корреляции в зависимости от клиента, к которому оно относится.
Но где объявлять переменные, применяемые к шаблону? Ранее мы формировали файл, содержащий в себе перечень всех имеющихся рабочих пространств, объектов защиты и контента, который относится к ним. Такое решение позволяло открыть один конфигурационный файл и получить представление о состоянии инсталляции, но функциональной составляющей в нем не было.
Мы развили эту идею и теперь предлагаем централизованно управлять инсталляцией, редактируя только один файл конфигурации SDL. В нём по-прежнему находится перечень всех клиентов и спейсов/теннантов, нетиражируемых шаблонов контента. При этом присутствует возможность передавать любые переменные в конкретный шаблон, добавление или удаление строк с сущностями в конфиге влияет на поведение [4] модуля SCM (добавление/удаление фактических сущностей из инсталляции).
Помимо перечисленного, мы приняли решение сделать центральный конфигурационный файл шаблоном jinja2, чтобы пользователи могли определять статические переменные в нём для сокращения объёма файла конфига. Теперь подробнее о самом файле конфигурации.
Файл имеет название installation.yml.j2 и в него входит
Секция рабочих пространств (spaces)
Секция объектов защиты (clients)
Секция нетиражируемого контента (common)
Тиражируемые секции представляют собой массивы объектов, в каждом из них определены следующие поля
Идентификатор спейса или клиента (строка)
Перечень типов сущностей, имеющихся в инсталляции для заданного спейса/клиента (объект)
В объекте типа сущности храним информацию следующего характера
Путь до файла или папки (если сущность является составной) в специальной директории для хранения пользовательского контента (строка)
Перечень кастомных переменных, относящихся к конкретному шаблону сущностей. Внутри секции variables можно указать любой тип, который поддерживается YAML
Нетиражируемая секция common имеет такую же структуру, за исключением того, что в ней хранится не массив объектов, а объекты в чистом виде, так как они являются общими для всех клиентов и спейсов.
installation.yml.j2
spaces:
- space_id: <идентификатор спейса>
<тип сущности>:
- path: <путь до файла/папки сущности в каталоге sdl_content>
variables:
<имя переменной для сущности>: <значение переменной>
clients:
- client_id: <идентификатор клиента>
<тип сущности>:
- path: <путь до файла/папки сущности в каталоге sdl_content>
variables:
<имя переменной для сущности>: <значение переменной>
common:
<тип сущности>:
- path: <путь до файла/папки сущности в каталоге sdl_content>
variables:
<имя переменной для сущности>: <значение переменной>
Путь до самих сущностей необходимо указать в формате относительного пути от директории, содержащей весь пользовательский контент. Такое решение обусловлено нашим желанием дать возможность пользователю группировать контент на свой вкус [5]. Это также облегчает фактическое ориентирование по конфигурации, так как понятно, на какой именно файл ссылается та или иная строка в конфиге.
Сам конфигурационный файл, как и контент, с которым работает пользователь, представлен в формате .j2, что позволяет применять шаблонизацию прямо внутри конфигурации.
Например, у вас есть набор корреляционных правил, которые нужно распространить на всех имеющихся клиентов. В таком случае вы можете определить статическую переменную со списком правил, а ниже, в фактической конфигурации инсталляции, обращаться к этой переменной.

Помимо работы с переменными, арсенал уверенного конфигуратора инсталляций можно пополнить условными операторами и циклами, которые позволяют сократить объём конфигурации, что актуально в производственных масштабах, когда вы настраиваете инсталляцию для, скажем, 40, 100 и более клиентов.
А теперь самое время рассмотреть некоторые из возможных сценариев управления контентом, которые возникают в SOC.
В первом случае у нас есть учётные данные и адрес (и ничего более, никаких конфигурационных файлов, никаких файлов контента) инсталляции SDL, контент которой нужно тиражировать для нового клиента. Что будем делать?
Открываем дистрибутив SCMи с помощью операции синхронизации автоматически получаем текущее состояние конфигурации. После выполнения данной операции открываем центральный конфигурационный файл и видим, что в инсталляции сейчас присутствует одно рабочее пространство и один клиент:
spaces:
- space_id: first_space
clients:
- client_id: first_client
common: {}
Для добавления нового клиента нужно всего лишь указать его в данном файле и запустить операцию по внесению изменений.
spaces:
- space_id: first_space
clients:
- client_id: first_client
- client_id: second_client
common: {}
Таким образом, мы всегда можем получить текущее состояние конфигурации от неё самой, нам не нужно задаваться вопросом о получении конфига и его актуальности. При этом само управление контентом стало значительно быстрее, ведь полный набор контента для объекта защиты загружается в инсталляцию с помощью написания одной строчки и запуска двух операций.
Нам необходимо добавить в инсталляцию новое правило обнаружения для двух клиентов, но поведение при срабатывании правила различается.
В данном случае за описанное требование к поведению отвечает системное поле result_type: для первого клиента нам необходимо значение «Writable», а для второго «Notable».
Необходимо сложить шаблон пользовательского правила в папку для кастомного контента и указать это правило для двух клиентов. Для гибкого управления поведением правила в зависимости от клиента нужно создать переменную с любым наименованием и необходимым значением для добавленного правила:
spaces:
- space_id: first_space
clients:
- client_id: first_client
sdl-detection-rules:
- path: rules/windows_account_added_to_privileged_group
variables:
result_type: Writable
- client_id: second_client
sdl-detection-rules:
- path: rules/windows_account_added_to_privileged_group
variables:
result_type: Notable
common: {}
В самом шаблоне пользовательского правила обнаружения обращение к переменной будет по тому же имени, которое было задано в центральном конфигурационном файле:

Благодаря такому функционалу пользователь может централизованно хранить и передавать абсолютно любые параметры любого типа для своего контента, тем самым гибко управлять поведением сущностей для каждого отдельного объекта защиты и рабочего пространства.
Часто возникает потребность [6] реализовать поведение, когда пользователь может либо задать параметр, который бы подставился в необходимом месте в шаблоне, либо не задавать его и использовать значение по умолчанию.
Для реализации такого поведения необходимо применить условный оператор в шаблоне сущности:

В центральном конфигурационном файле же необходимо определить переменную «url» для тех клиентов, где мы бы хотели подставить своё значение адреса:
spaces:
- space_id: first_space
clients:
- client_id: first_client
sdl-detection-rules:
- path: rules/windows_account_added_to_privileged_group
variables:
result_type: Writable
- client_id: second_client
sdl-detection-rules:
- path: rules/windows_account_added_to_privileged_group
variables:
result_type: Notable
url: https://192.168.1.100:9562/api/new/address
common: {}
Расширенное использование функций шаблонизации позволяет значительно упростить работу с контентом, уменьшить объём шаблонов сущностей и динамически определять содержимое итоговых файлов.
Часто можно встретить сущности, содержимое которых зависит, например, от присутствующих объектов защиты в инсталляции. Каждый раз, когда добавляется новый объект защиты, возникает необходимость добавлять однотипный элемент в файл сущности. Но благодаря возможностям шаблонизации теперь можно определить переменную с перечнем всех имеющихся клиентов, а в шаблоне использовать цикл, который бы автоматически генерировал те однотипные элементы за нас:

Центральный конфигурационный файл необходимо дополнить переменными списка клиентов, для которых будет генерироваться данная конструкция:
spaces:
- space_id: first_space
clients:
- client_id: first_client
sdl-detection-rules:
- path: rules/windows_account_added_to_privileged_group
variables:
result_type: Writable
rule_clients:
- first_client
- second_client
- client_id: second_client
sdl-detection-rules:
- path: rules/windows_account_added_to_privileged_group
variables:
result_type: Notable
url: https://192.168.1.100:9562/api/new/address
rule_clients:
- first_client
- second_client
common: {}
В инсталляции присутствует несколько клиентов и множество правил обнаружения, причём, часть правил должны относиться ко всем объектам защиты, а часть – подобраны под конкретного клиента и не должны быть задействованы в других. Как заполнить конфигурационный файл, чтобы не повторять [7] множество строк с обязательными правилами обнаружения и при этом оставить возможность индивидуального управления клиентами? Использовать шаблоны, конечно.
Мы можем представить объект клиента как переменную шаблона, объявить списки с общими и индивидуальными правилами и объединить их средствами jinja2:
{% set default_rules = [{"path": "default-rule"}] %}
{% set client1_rules = [{"path": "rule1"}, {"path": "rule2"}] %}
{% set client2_rules = [{"path": "rule3"}, {"path": "rule4"}] %}
{%
set client1 = {
"client_id": "client1",
"sdl-detection-rules": default_rules + client1_rules
}
%}
{%
set client2 = {
"client_id": "client2",
"sdl-detection-rules": default_rules + client2_rules
}
%}
spaces: []
clients:
- %%% client1 %%%
- %%% client2 %%%
common: {}
В результате получим следующий конфигурационный файл:
spaces: []
clients:
- client_id: client1
sdl-detection-rules:
- path: default-rule
- path: rule1
- path: rule2
- client_id: client2
sdl-detection-rules:
- path: default-rule
- path: rule3
- path: rule4
common: {}
Проблема управления изменяемым контентом в системах мониторинга и анализа машинных данных обостряется по мере развития и масштабирования SOC. SDL Content Manager позволяет централизованно и гибко управлять всем аналитическим контентом SOC, отслеживая при этом каждое принятое изменение.
Основным нововведением стало применение эталонного контента в виде шаблонов с возможностью параметризации любых значений или целых разделов под отдельные группы тенантов (объектов защиты, рабочие пространства). При этом дополнительное удобство управления конфигурацией обеспечивается за счёт встраивания SDL Content Manager в процедуры непрерывной сборки/развертывания контента, с контролем и согласованием изменений при их переносе из среды разработки в production-среду.
Рассказ о других функциях STEP LOGIC Security Data Lake (SDL), таких как адаптивные действия, дерево процессов, цепочки инцидентов, сводный перечень активов и другие, продолжу в следующих статьях. Оставайтесь на связи.
Автор: Delonce
Источник [8]
Сайт-источник BrainTools: https://www.braintools.ru
Путь до страницы источника: https://www.braintools.ru/article/13007
URLs in this post:
[1] логика: http://www.braintools.ru/article/7640
[2] болью: http://www.braintools.ru/article/9901
[3] поведение: http://www.braintools.ru/article/9372
[4] поведение: http://www.braintools.ru/article/5593
[5] вкус: http://www.braintools.ru/article/6291
[6] потребность: http://www.braintools.ru/article/9534
[7] повторять: http://www.braintools.ru/article/4012
[8] Источник: https://habr.com/ru/companies/step_logic/articles/889702/?utm_campaign=889702&utm_source=habrahabr&utm_medium=rss
Нажмите здесь для печати.