В работе с публичными облаками много плюсов, но с точки зрения ИБ — есть свои риски по сравнению с on‑premises. Минимизировать их помогает выделенный Security Operation Center (SOC). При этом создать его у себя не так просто: для эффективной работы SOC в Yandex Cloud понадобилось несколько лет разработки, а также технологии и мощности Яндекса, которые развивались годами.
Поскольку у клиентов облака не всегда есть ресурсы и экспертиза, чтобы создать подобный SOC у себя, мы не только строили свой центр, но и параллельно делали на его основе управляемый сервис Yandex Cloud Detection & Response (YCDR). В процессе разработки мы должны были позаботиться о том, чтобы даже привилегированные учётные записи не могли обойти семь слоёв облачной безопасности, — и в итоге многие компоненты написали самостоятельно.
Меня зовут Евгений Грязнов, я работаю в группе Security & Compliance в Yandex Cloud. Сегодня вместе с архитектором Владиславом Архиповым, а также директором аналитической платформы YDB Алексеем Дмитриевым @SloNN расскажем о скрытых за кулисами деталях разработки:
Первая часть для тех, кому важны механизмы безопасной изоляции ресурсов. Покажем, как мы строили SOC c учётом особенностей облачной защиты.
Вторая часть для тех, кто интересуется большими данными. Продемонстрируем, что скрывает под капотом сервис, обрабатывающий более полумиллиона событий в секунду. А также расскажем, почему нам потребовалось создать для него собственную SIEM‑систему.
О каких особенностях публичного облака важно помнить
В частной инфраструктуре у нас есть периметр — сетевое пространство, где размещены ресурсы, а также файрвол, ограничивающий наш контур от внешнего. У специалиста по ИБ понятные доступы к ресурсам и понимание маршрутизации всех сервисов.
В публичных облаках всё иначе.
Набор DevOps‑инструментов отличается от тех, что есть в частных сетях. Например, мы активно применяем Terraform. С его помощью можно описать целевую архитектуру, которую хочется получить, и задеплоить несколькими командами.
Пользователи могут управлять параметрами облака через публичные API.
Ответственность за безопасность несёт и провайдер, и клиент — иногда это называют разделяемой ответственностью, но мы предпочитаем говорить о совместной ответственности. Облачный провайдер отвечает за общую безопасность облака. Если клиент работает по модели IaaS или PaaS, то за защиту верхнеуровневых сущностей он несёт ответственность самостоятельно.
Всё публичное облако завязано на сервисах, которые централизованно обеспечивают доступ. Так, Identity and Access Management (IAM) позволяет описать роли в облаке при помощи заданного набора прав.
С помощью IAM пользователь может разграничивать доступы точечно. У Yandex Cloud IAM достаточно гибкий, со множеством гранулярных ролей, и мы уже рассказывали, как это устроено.
Наглядный пример
Так, можно настроить права только на изменение параметров виртуальной машины или на возможность запустить или остановить ВМ, но не изменять её настройки.

При этом для работы с облаком средствами автоматизации у пользователей есть сервисные аккаунты. Если ключ от такого аккаунта скомпрометирован, злоумышленник сможет сделать с облаком клиента много всего. Подробно о способах таких атак, а также о том, как их можно предотвратить, мы уже рассказывали в этой и в этой статье на Хабре.
По этой причине ИБ‑специалисты максимально ограничивают привилегии, выдаваемые конкретным учётным записям. Но это не исчерпывает все возможные риски, которые могут возникать сразу на нескольких уровнях.
Чтобы угрозы и их комбинации были более видимыми, мы ведём постоянный процесс логирования в облачной платформе, а данные из логов попадают в Audit Trails — этот сервис хранит облачные журналы и помогает расследовать инциденты. В Yandex Cloud логи содержат два разных типа событий: уровня конфигурации и уровня сервисов.
События уровня конфигурации — действия, связанные с конфигурированием ресурсов.
События уровня сервисов — изменения и действия, которые происходят с данными и ресурсами внутри сервисов.

Базово Audit Trails регистрирует события уровня конфигурации: они проходят через системный инстанс этого сервиса.
Однако журналы уровня сервисов передают более детализированные логи, которые могут быть интересны для расследования. Например, для сервиса управляемой базы данных типа MySQL это могут быть журналы входа/выхода, журналы конкретных SQL‑запросов, а для Kubernetes — аудитный лог.
Казалось бы, информации в облачной платформе собирается много. Тем не менее, это не значит, что специалисты по безопасности облачной платформы могут «дотянуться до всего».
Сам SOC тоже не должен стать источником уязвимости
Yandex Cloud с точки зрения ресурсной модели — это набор облаков и организаций. И при разработке SOC нам было важно позаботиться, что на него распространяются те же правила безопасности, по которым работает облачная платформа.
Поэтому все компоненты SOC находятся в системной организации в рамках системного облака. А у аналитиков по информационной безопасности нет привилегированного прямого доступа, скажем, в клиентские базы данных, специалисты действуют строго в рамках выданных им ролей.
На уровне общей схемы выглядит так:

Как это работает на уровне конкретных механизмов. Все субъекты в облаке
одинаковы — и сервисные аккаунты, и сотрудники облака, и внешние пользователи. Важны только доступы. Даже для поставки событий Audit Trails из Control Plane и Data Plane необходимо делегировать доступ — предоставить аналитикам разрешения на чтение логов соответствующего уровня. У пользователя есть возможность видеть все предоставленные доступы сервисным аккаунтам и внешним пользователям и при необходимости их отобрать.

У команды разработки доступ к продакшн‑ресурсам также ограничен. Если возникает необходимость регулярного обслуживания систем, то дежурные инженеры получают урезанный временный доступ на выполнение конкретных операций.
Такие механизмы безопасности соответствуют принятой модели изоляции ресурсов по слоям согласно стандарту по защите облачной инфраструктуры. Но одновременно это добавляет сложностей при эксплуатации системы.
Яркий пример: иногда клиенты облачной платформы просят специалистов SOC защищать конечные устройства или собирать события из конкретных СЗИ, которые развёрнуты в их облаке.
Какие инструменты мы используем для этих задач:
агенты osquery и Tetragon для сбора событий с виртуальных машин;
механизмы интеграции с политиками для сбора событий с AppArmor/seccomp;
всё тот же Tetragon для защиты Kubernetes, а для защиты сетевых соединений в K8s — интеграция с сетевыми политиками, например, Kyverno;
syslog и http(s) для сбора со сторонних СЗИ.
Однако для сбора данных с СЗИ и агентов на виртуальных машинах требуется более плотное участие со стороны пользователя облачной платформы, так как мы переходим в его зону ответственности.
Поэтому для того чтобы из SOC появился доступ к пользовательским данным:
пользователь должен явно делегировать свои доступы сервисным аккаунтам на время конкретной операции;
клиенту необходимо самостоятельно развернуть на своей стороне специальный коллектор, имеющий выход во внешнюю сеть, поскольку специалисты облака не могут забирать трафик из клиентской сети.
Мы разработали несколько вариантов исполнения такого коллектора:
Полностью отказоустойчивый вариант на основе Managed Kubernetes. Он использует сетевые балансировщики и позволяет масштабировать рабочую нагрузку, если она повышается, в том числе реализовать геораспределённую схему на несколько дата‑центров.
Простой вариант, часто используемый на этапе пилота или в сценариях без высоких требований к отказоустойчивости, — применение простых Docker‑контейнеров, которые клиент может развернуть у себя и использовать для сбора событий.
В общем случае схема использования коллектора выглядит так:

Как устроен выход коллектора во внешнюю сеть: формально данные отправляются на внешний endpoint, но этот endpoint также расположен в облаке. Поэтому информация от коллектора по‑прежнему перемещается внутри облачной платформы, без необходимости строить сложный туннель: данные закрыты TLS и отправляются в системное облако в рамках того же дата‑центра. Передача организована без использования сетей общего доступа на уровне внутреннего Cloud Router:

Если же используется конфигурация с резервированием между дата‑центрами, то связь между площадками реализуется с применением dark fiber, то есть тоже по приватным каналам.
Как анализировать события безопасности быстро, и для чего нам свой SIEM
Требования к системе. Ещё три года назад анализ данных для нашего SOC в команде безопасности превратился в особый челлендж:
уже тогда нам нужно было обрабатывать 600 тысяч событий в секунду, и мы понимали, что поток кратно вырастет;
хранить события безопасности нужно не менее трёх лет в соответствии с различными требованиями регуляторов;
необходимо, чтобы специалисты SOC могли обратиться к этим данным и найти нужную информацию на всей глубине хранения;
время обнаружения инцидента должно было составлять считанные секунды.
Для решения этих задач предназначены SIEM‑системы, однако на рынке не было подходящих решений для таких требований. Традиционные системы безопасности на тот момент обычно работали так: получали определённый объём данных, накапливали у себя внутри в БД, а потом по расписанию раз в 10–15 минут обращались к ним в поисках проблем. В этом случае время реакции системы исчислялось этими минутами, но никак не секундами.
Хорошим решением задачи была бы потоковая обработка данных, и за реализацией мы обратились в команду YDB, где уже был накоплен значительный опыт. В итоге получилось так, что мы создали собственную SIEM‑систему потоковой корреляции, построенную на технологиях Яндекса. Вдобавок это позволяло быстро внедрять изменения на уровне собственных конструкций в язык запросов и тем самым обеспечивать большую гибкость.
Общая схема многопользовательского решения:

При разработке мы не стали использовать multitenant‑модель: для каждого пользователя выделяется свой изолированный контур — получается такой dedicated SIEM, со своими балансировщиками, виртуальными машинами и БД. Контур каждого клиента изолирован с точки зрения как сети, так и ресурсной модели облака, то есть права на контур разных клиентов назначаются по‑разному, и они никак не наследуются и не пересекаются. Когда пользователь только заходит, системе необходимо понять, в какой именно инстанс его нужно отправить. Для этого существуют специализированные точки входа:
Единая точка входа Control Plane — это SIEM Router, который стоит на границе облачной инфраструктуры для роутинга запросов.
Единая точка входа Data Plane SIEM — это стрим Yandex Data Streams (YDS), сервиса для управления потоками данных в режиме реального времени на базе шины данных YDB Topics. Он также позволяет не смешивать сами потоки данных, и разграничивать доступ к событиям на основе прав.
Наиболее интересная часть в системе — это работа с данными. Сам по себе подход потоковой обработки данных не новый, ведь есть большое количество систем, которые это умеют. Например Apache Flink или Apache Spark. Они предоставляют SQL‑подобный синтаксис.
Пример синтаксиса из Flink
INSERT INTO buy_cnt_per_hour
SELECT
HOUR(TUMBLE_START(ts, INTERVAL '1' HOUR)),
COUNT(*)
FROM
user_behavior
WHERE
behavior = 'buy’
GROUP BY TUMBLE(ts, INTERVAL '1' HOUR);
Здесь добавлены специальные потоковые команды TUMBLE_START и TUMBLE, но в остальном привычный вид SQL-запроса.
Мы также думали о том, чтобы реализовать что‑то подобное.
В случае с собственной системой было в первую очередь важно воплотить в жизнь схему со множеством источников данных:

Данные из источников поступают в сервис нормализации. Когда на вход поступает очень разная информация, важно привести её к одному виду: например, определить IP‑адрес, откуда пришло событие, и задать все адреса в одном формате, или выделить из потока логин аккаунта, с которого совершается действие.
Все сырые данные сохраняются для долговременного хранения в объектном хранилище (поскольку это самый дешёвый способ хранения в облаке, а данных нам нужно держать много).
Нормализованные данные отправляются для горячего хранения в аналитическую БД, куда может прийти аналитик с конкретной задачей и выполнить запрос.
Эти же нормализованные данные отправляются в стриминг для обогащения и выполнения правил корреляции, которые позволяют определить инциденты.
С учётом объёмов данных эта схема выглядела уже так:

Реализованная система по сути раскладывается на три взаимодействующих компонента:

Долгосрочное хранилище S3 Parquet, где сохраняются все сырые события с метаданными.
Сам SIEM обеспечивает координацию процессов и управление конфигурациями.
А весь процессинг сосредоточен в YDB, где также сохраняются все нормализованные события.
Из чего состоит процессинг

Самый важный модуль — это Streaming Engine, или модуль потоковой обработки. Именно он позволяет выполнять те правила корреляции, по которым служба безопасности обнаруживает инциденты. Для реализации этой части у разработчиков было несколько вариантов, в том числе создание собственного диалекта, на котором аналитики могли бы писать свои запросы (как в примере c Apache Flink). Получился бы Yet Another SQL, которому вдобавок нужно обучить пользователей
Но в итоге мы пошли другим путём: в стандарте SQL-2016 обнаружились решения для похожих проблем в области Complex Event Processing. В одноимённом разделе стандарта есть команда MATCH_RECOGNIZE
. Она позволяет на привычном SQL описывать сложные паттерны, которые можно искать в данных.
SELECT user_id, event_time, pattern_detected
FROM stream_events
MATCH_RECOGNIZE (
PARTITION BY user_id ORDER BY event_time
PATTERN (A B C)
DEFINE
A AS A.event_type = 'login',
B AS B.event_type = 'password_change',
C AS C.event_type = 'logout'
) AS T;
Фильтры и лукапы. Тем временем с объёмом данных возникала новая проблема: если 600 МБ/с данных на входе в YDB скормить в каждый запрос (а их более 100), то уже на старте получим поток в 120 ГБ/с. А если представить, что мы растём, то в перспективе двух лет рискуем перейти к терабайтам в секунду, стать крупнейшим стримингом в России, обогнать Кинопоиск... Нужно было думать о том, как уменьшить объём передаваемых данных.
Глядя на конкретные сценарии, мы поняли, что большинству правил корреляции не нужны все данные. По итогам реализовали автоматический вывод фильтров: когда аналитик вводит запрос, система понимает, какие данные ему нужны, и фильтрует их.

Для корреляции используются не только сами данные из потока. Когда входящая информация идёт через потоковый модуль, нам важно понимать, что это за информация: например, легитимен ли тот пользователь, которого мы наблюдаем в списке обращений. Поэтому для обогащения потока мы также используем справочную информацию для правил корреляции — так называемые лукапы, которые хранятся в транзакционной БД.
В этих справочниках, в частности, хранятся классы зон хостов и типы пользователей. Когда мы запустили систему, то выяснили, что выполняем каждую секунду около 50 000 запросов к таблицам справочников. А если вырастем и здесь, как эффективно с этим справиться? Для этого в YDB пригодились строковые таблицы, которые в режиме KV‑нагрузки обеспечивают миллионы событий в секунду. Одновременно с этим выяснили, что данные в справочниках важно обновлять транзакционно, в реальном времени, иначе это приводит к большому количеству ложных срабатываний.
Аналитическая база данных. Мы уже говорили, что специалистам SOC такая БД нужна, чтобы обращаться к накопленным данным на любую глубину хранения.

В этой части важными оказались две вещи:
Горизонтальное масштабирование, поскольку с текущим потоком данных и выбранной глубиной хранения мы в перспективе можем прийти к безумным объёмам. Здесь нас выручает распределённое (шардированное) хранение и обработка данных.
Умение работать с большим количеством колонок, потому что уже в момент нормализации входящих данных на старте, стало понятно, что неплохо бы иметь тысяч пять колонок. Здесь нам пригодилась поддержка разряжённых таблиц до 10 000 колонок.
К чему эти сложности? Если подытожить этот опыт, мы можем сказать, что стриминг без аналитики — деньги на ветер. Пользователю со стороны может показаться, что от видит только то, что происходит в текущий момент. Но на бэкенде за этими событиями стоит большая машинерия по обогащению данных, потому что:
Потоковый запрос по умолчанию видит только те данные, которые передаются прямо сейчас.
Новые и редкие данные могут приводить к сюрпризам, которые ломают всю систему.
Когда мы написали аналитический запрос, нам нужно затем отладить его на всём объёме данных.
Затем повторить это в виде потокового запроса.
А затем увидеть новые данные, перепроверить на исторических данных в аналитике и повторить всё это в стриминге.
Да, такой подход требует вложения ресурсов на старте. Но в результате получается гибкий SIEM, учитывающий наш специфический контекст использования.
Что дальше?
Ну и в заключение расскажем о планах. Пока мы предлагаем сервис YCDR только тем пользователям, чья инфраструктура полностью находится в Yandex Cloud. Но в дальнейшем также будут доступны:
возможность мониторинга мультиклауда;
детекты по Flow‑логам облачной платформы;
расширение возможностей поиска в сторону поиска по сырым событиям для клиентов. Это позволит пользователям не просто наблюдать алерты, а понять, почему они произошли и что с этим можно сделать.
Самые интересные подробности по направлениям развития мы раскроем чуть позже. Но в любом случае будем рады вопросам и комментариям — о чём из этого списка было бы интересно узнать больше.