Инженерия

Единое окно: что это значит технически (и почему большинство вендоров промахивается)

Большинство презентаций «единого окна» заканчивается на дашборде. Но дашборд — простая часть. Реальная работа в том, чтобы под ним договорились общая модель активов, шина событий, поверхность поиска и слой идентификации. Вот как выглядит единая SOC-платформа, если относиться к термину серьёзно.

Автор Krasper Engineering 3 июня 2026 г. 9 мин чтения
Single Pane of Glass — hero

Коротко: «единое окно» продают как функцию интерфейса, но на деле это контракт между четырьмя подсистемами (общая модель активов, шина событий, поисковый индекс и федеративный слой идентификации), которые должны сходиться в том, что такое объект, кто им владеет, что с ним произошло и кому разрешено об этом знать. Когда эти четверо расходятся, получается портал, а не платформа; когда сходятся, дашборд становится почти второстепенной деталью.

О едином окне заявляет каждый SOC-вендор. Фраза затёрта до блеска. На практике за ней обычно стоит портал с встроенными фреймами: вкладка EDR, вкладка сканера уязвимостей, вкладка инвентаря активов, каждая рисует свой родной интерфейс внутри обёртки, у которой общий с остальными только логотип. Пользователь видит один адрес. Данные не объединены никак.

Этот материал — о том, что на самом деле требуется на уровне архитектуры, чтобы построить другое единое окно: такое, где оповещение агента конечной точки, запись об активе из CMDB, уязвимость от сканера и тикет инцидента, заведённый аналитиком SOC, — это ссылки на одну и ту же сущность, запрашиваемые одним синтаксисом и управляемые одной ролью.

Это суть Krasper Suite и та часть, которую более старые вендоры обычно пропускают: достроить её поверх федерации купленных продуктов труднее, чем обойти в презентации.

Содержание

  1. Маркетинговая версия против инженерной
  2. Общая модель активов: почему канонический идентификатор решает всё
  3. Шина событий: хореография вместо оркестрации
  4. Поверхность поиска: когда полнотекстовый поиск действительно важен
  5. Федерация идентификации через OIDC: один пользователь, много подсистем
  6. Гексагональная архитектура: что держит всё вместе
  7. Как эксплуатировать больше десятка сервисов и не потерять нить
  8. Чек-лист: как проверить заявление любого вендора

1. Маркетинговая версия против инженерной

Маркетинговая версия единого окна звучит так:

«Все ваши средства защиты в одном месте».

То же самое можно сказать про любой браузер с папкой закладок.

Инженерная версия хуже помещается на слайд:

Для любой сущности платформы (актива, находки, инцидента, пользователя, политики) каждая наблюдающая её подсистема должна соглашаться с её идентичностью, публиковать изменения состояния в общий таймлайн, отдавать свои данные через общую поверхность запросов и делегировать авторизацию общему слою идентификации.

В этой фразе описаны четыре контракта. Большинство платформ выполняет один, обычно слой дашборда, и на этом останавливается. Остальное склеено ночными пакетными задачами и надеждой, что никто не заметит, что ключи связывания не совсем совпадают.

Соблюдайте эти контракты — и дашборд станет тонким слоем отображения поверх согласованных данных. Отпустите их — и тот же дашборд превратится в камуфляж поверх четырёх несогласованных хранилищ, где любой сквозной вопрос — «покажи все хосты с критической CVE, активным оповещением EDR и непропатченной ОС, принадлежащие финансовому отделу» — требует человека, который сделает четыре поиска и вручную сошьёт результаты.

2. Общая модель активов: почему канонический идентификатор решает всё

Самая трудная задача такой платформы — не объём оповещений и не дашборды. Это разрешение сущностей. Агент конечной точки называет машину LAPTOP-7HD23-NEW. Сканер уязвимостей называет ту же машину по IP, который меняется каждую неделю. В CMDB она значится как asset-id-44219. Тикет-система ссылается на серийный номер. Облачное обнаружение видит её как идентификатор инстанса EC2.

Если эти идентификаторы не сходятся, любой «кросс-инструментальный» запрос — гадание.

Решение — каноническая модель активов, принадлежащая платформе, а не отдельной интеграции. Каждая интеграция обязана привести свой родной идентификатор к каноническому в момент приёма данных, а не в момент запроса:

   ┌────────────────────────┐
   │  Endpoint integration  │──┐
   └────────────────────────┘  │
                               │   ┌──────────────────────────────┐
   ┌────────────────────────┐  │   │  Asset resolver              │
   │  CMDB integration      │──┼──▶│  - lookup by serial          │
   └────────────────────────┘  │   │  - lookup by MAC             │
                               │   │  - lookup by cloud ID        │
   ┌────────────────────────┐  │   │  - lookup by hostname        │
   │  Cloud asset discovery │──┘   │                              │
   └────────────────────────┘      │  → returns canonical_asset_id│
                                   └──────────────┬───────────────┘
                                                  │
                                                  ▼
                                   ┌──────────────────────────────┐
                                   │  Canonical asset record      │
                                   │  + every observation tagged  │
                                   │    with canonical_asset_id   │
                                   └──────────────────────────────┘
Родные идентификаторы → canonical_asset_id при приёме

Как только каждое наблюдение несёт один и тот же canonical_asset_id, любой вопрос превращается в один запрос к одному индексу, независимо от того, какая подсистема породила данные. Актив становится ключом связывания для всей платформы.

Невзрачная правда в том, что бóльшая часть инженерной работы в единой SOC-платформе уходит именно на этот резолвер: правила, цепочки запасных вариантов, разбор конфликтов, когда две интеграции расходятся, логика слияния, когда ранее неизвестный актив позже опознан. Срезать здесь углы нельзя, и вендоры, которые это пропускают, получают параллельные вселенные активов, оставляя сведение данных на голову аналитика заказчика.

3. Шина событий: хореография вместо оркестрации

Второй контракт — шина событий. Каждое изменение состояния в каждой подсистеме (новое оповещение, закрытая находка, появившийся в сети актив, обновлённая политика, комментарий к инциденту) публикуется как событие в общую шину. Остальные подсистемы подписываются на то, что им нужно.

Архитектурный выбор, который мы сделали рано, — хореография вместо оркестрации. Нет центрального движка процессов, который говорит системе инцидентов: «теперь подожди, пока сканер закончит». Каждый сервис реагирует на события в своём темпе, в своём ограниченном контексте, и публикует собственные события при изменении состояния. Шина — единственная связность.

Выигрыш:

  • Новую подсистему можно добавить, не меняя существующие. Она просто подписывается на нужные события и публикует свои.
  • Переигрывание тривиально. Любой потребитель может отмотать к точке во времени и пересобрать своё производное состояние из потока событий — полезно для дозаливки данных, исправления ошибок и восстановления после аварий.
  • Аудиторский след — побочный эффект архитектуры, а не функция, прикрученная позже. Все изменения состояния уже сериализованы в хронологическом порядке.

Цена в том, что согласованность становится итоговой, а не транзакционной. Новое оповещение может дойти до дашборда на пару сотен миллисекунд раньше, чем подтянется обогащение по активу. Платформа должна корректно отображаться в этом окне. Дисциплина, к которой это принуждает, полезна: она заставляет проектировать интерфейсы, показывающие то, что известно на сейчас, а не блокирующиеся до всего, что вообще может быть известно.

Конкретная форма события, очищенная от внутренних названий, выглядит так:

json
{
  "event_id": "01J5K3...",
  "event_type": "vuln.finding.created",
  "occurred_at": "2026-06-03T07:14:22Z",
  "canonical_asset_id": "asset_94c1...",
  "tenant_id": "tenant_42",
  "payload": {
    "cve": "CVE-2026-NNNNN",
    "cvss": 9.8,
    "scanner": "scanner-integration-v2",
    "first_seen": "2026-06-03T07:13:11Z"
  },
  "source": {
    "integration": "vuln-scanner-adapter",
    "version": "2.4.1"
  }
}
Конкретная форма события в общей шине

Обратите внимание на три вещи: канонический идентификатор актива — поле первого класса, арендатор указан явно (никакого неявного контекста), а полезная нагрузка привязана к пространству имён типа события. Эти три привычки убирают примерно 80 процентов будущей боли интеграции.

4. Поверхность поиска: когда полнотекстовый поиск действительно важен

Когда события и активы объединены, следующий вопрос — как аналитики их запрашивают. Часто встречаются два режима отказа:

  1. Платформа даёт отдельную строку поиска на каждую подсистему. Аналитики гадают, куда вводить запрос. Ошиблись — пустой результат, хотя ответ был двумя строками правее.
  2. Платформа даёт одну строку поиска, но с точным совпадением только по каноническим полям. Аналитик вводит error 504 nginx finance-team и не получает ничего, хотя эти слова встречаются в трёх разных полезных нагрузках оповещений.

Единому SOC нужен полнотекстовый поиск по всем типам сущностей (активы, оповещения, находки, инциденты, комментарии, тикеты), который одновременно уважает структурные фильтры в том же запросе.

Здесь выделенный поисковый индекс окупается. Мы индексируем каждую сущность в момент попадания её события в шину: канонический идентификатор актива — как фасет, арендатор — как жёсткий фильтр, свободные текстовые поля полезной нагрузки — как искомое содержимое. Язык запросов поддерживает и то и другое:

text
status:open AND severity:critical AND
  asset.owner.team:"finance" AND
  ("error 504" OR "nginx timeout")
Кросс-сущностный запрос со структурными фильтрами и полнотекстом

Этот запрос одновременно достаёт инциденты, оповещения и находки, уважает ролевую модель по полю владельца актива и возвращает ранжированные результаты по разным типам сущностей. Аналитику не нужно знать, какая подсистема владеет каким полем. Вот что на практике означает «единое окно».

Урок в том, чтобы считать поиск возможностью платформы, а не функцией каждого сервиса. Единый индекс — множитель эффективности; поисковые строки на каждый сервис — налог на каждое расследование.

5. Федерация идентификации через OIDC: один пользователь, много подсистем

Четвёртый контракт — идентификация. Если аналитик входит в дашборд, но каждая подсистема ведёт свою таблицу пользователей, у вас в лучшем случае единый вход, а не единая идентичность.

OIDC с выделенным брокером идентификации перед каждой подсистемой — прямолинейный способ это решить:

   Analyst's browser
         │
         │ 1. SSO login
         ▼
   ┌─────────────────────┐
   │ Identity broker      │── federates to corporate IdP
   │ (OIDC provider)      │
   └─────────┬───────────┘
             │ 2. Issues access token
             │    with roles + tenant claim
             ▼
   ┌─────────────────────────────────────────────┐
   │ API gateway                                  │
   │ - validates token                            │
   │ - injects roles + tenant into request ctx    │
   └─────────┬───────────────────────────────────┘
             │
   ┌─────────┴───────────┐
   │                     │
   ▼                     ▼
  Asset service     Alert service     ...  (all consume the same ctx)
Поток токенов OIDC: одна идентичность, все подсистемы

Одно назначение роли в брокере распространяется на все подсистемы при следующем обновлении токена. Никакого управления пользователями в каждом сервисе. Никакой внеполосной синхронизации, которая расходится. Когда сотрудник уходит и провайдер идентификации его отключает, все подсистемы теряют доступ одновременно, потому что все требуют один и тот же токен, токен требует ту же идентичность, а идентичности больше нет.

OIDC даёт и изоляцию арендаторов на уровне токена: клейм tenant_id входит в токен доступа, каждый запрос к API ограничивается этим арендатором на шлюзе, а сервис, который это игнорирует, не пройдёт ревью, потому что упадут интеграционные тесты.

Ничего нового здесь нет — это стандартный шаблон. Важно применять его единообразно во всех подсистемах, без исключений вида «интеграцию X мы купили, и у неё до сих пор своя модель пользователей». Исключения — ровно то место, где единое окно перестаёт быть единым.

6. Гексагональная архитектура: что держит всё вместе

Архитектурный стиль, который делает эти четыре контракта поддерживаемыми годами, а не месяцами, известен как гексагональная архитектура, порты и адаптеры или чистая архитектура. Форма всегда одна: доменное ядро, знающее сущности и бизнес-правила, вокруг него порты (интерфейсы), описывающие, как оно общается с внешним миром, и адаптеры (реализации), связывающие эти порты с конкретными технологиями.

Конкретно: домен активов не знает, лежат ли данные об активах в PostgreSQL, приходят ли из REST-интеграции, поступают ли по шине событий или ищутся во внешнем индексе. Он знает лишь, что AssetRepository, AssetEventPublisher и AssetSearchIndexer — порты, которые можно вызвать. Слой адаптеров связывает их с реальной инфраструктурой.

Выигрыш проявляется ровно тогда, когда он нужнее всего:

  • Смена поискового бэкенда — правка одного адаптера, а не переписывание домена.
  • Добавление интеграции — адаптер с другой стороны, а не хирургия по всему стеку.
  • Тестировать домен просто: у каждого порта есть in-memory заглушка. Никаких мокнутых HTTP-вызовов и тестовых контейнеров для юнит-тестов.
  • Онбординг новых инженеров сводится к «выучи язык домена; инфраструктура — сменная деталь».

Дисциплина даётся тяжелее, чем звучит. Соблазн залезть в базу прямо из контроллера, «только в этот раз, ради производительности», постоянен. Удержание границы — это то, что не даёт платформе схлопнуться в распределённый монолит под собственным весом.

7. Как эксплуатировать больше десятка сервисов и не потерять нить

Платформа, построенная так, естественно раскладывается на десяток с лишним независимо развёртываемых сервисов: каждый — ограниченный контекст, у каждого своя база данных, каждый публикует в общую шину и подписывается на неё, каждый отдаёт API за общим шлюзом идентификации.

Из эксплуатации такого количества сервисов в продуктиве выделяются несколько уроков.

Версионирование схемы событий не обсуждается. Каждый тип события несёт поле версии схемы, потребители переваривают ту версию, под которую написаны, и игнорируют неизвестные будущие поля, а ломающие изменения выходят как новые типы событий, а не переписывание на месте. Звучит очевидно, но цена одной ошибки — многонедельная миграция у всех потребителей.

Наблюдаемость должна быть возможностью платформы, а не тем, что каждый сервис изобретает заново: один формат структурированных логов на всех, один идентификатор распределённой трассы, проходящий через шину, одно пространство имён метрик. Стройте это в первый день или воюйте с этим на третий год.

Ключи идемпотентности принадлежат шине. Каждое событие несёт уникальный event_id, и каждый потребитель по нему дедуплицирует, что убирает целый класс ошибок вида «письмо ушло дважды» ещё до их появления.

В хранении предпочитайте эволюцию схемы миграции данных. Добавляйте новые поля, мягко объявляйте старые устаревшими и никогда не удаляйте; лишний столбец стоит почти ничего, а согласованная миграция с остановкой мира по десятку сервисов разорительна.

Наконец, держите одну эталонную среду интеграционных тестов с реальными сервисами. Юнит-тесты могут проходить на заглушках, но интеграционные должны идти против реальных сервисов в compose, потому что мокнутые интеграционные тесты продолжают зеленеть ровно тогда, когда продуктив падает.

8. Чек-лист: как проверить заявление любого вендора

Если вы оцениваете SOC-платформу, заявляющую о едином окне, спрашивать стоит вот о чём — в порядке того, насколько надёжно вопрос отличает суть от маркетинга.

Первое: какой у вас канонический идентификатор актива и как он выводится из родных идентификаторов интеграций? Если ответ расплывчат, идентификатора у платформы нет.

Второе: покажите запрос, который охватывает больше одной подсистемы и возвращает ранжированные результаты за один проход. Если демонстрация открывает две вкладки — это и есть ответ.

Третье: когда я отзываю пользователя в нашем провайдере идентификации, через сколько все подсистемы начнут отклонять его токен? Честный ответ: «на следующем обновлении токена, обычно меньше пяти минут». Всё, что дольше, означает внеполосную синхронизацию пользователей, а значит расхождение, а значит замечания аудита.

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

Пятое: покажите схему событий одной из ваших ключевых сущностей. Если схемы событий нет, значит нет и шины событий, а «единое окно» держится на опросах и надежде.

Платформа, которая хорошо отвечает на эти вопросы, вложилась в инженерию; та, что уходит от них, вложилась в маркетинг. Разница важнее всего в тот момент, когда реальный инцидент затрагивает три подсистемы, а у аналитика шесть минут на разбор.

Заключение

Единое окно — архитектурное обязательство, которое лишь проявляется как дашборд: под ним лежат общая модель активов, шина событий, единая поверхность поиска и федеративный слой идентификации, обёрнутые в модульные границы, позволяющие платформе развиваться без переписывания.

Дашборд видят все. А правду ли он говорит, решают эти четыре контракта под ним.

Следующий материал серии подробно разбирает один из контрактов — шину событий — и то, как на практике выглядят её схема, контракт потребителя и инструменты переигрывания.

Дополнительное чтение

  • Алистер Кокберн: Hexagonal Architecture (2005)
  • Мартин Фаулер: Event-Driven Architecture и Choreography vs. Orchestration
  • Сэм Ньюмен: Building Microservices, 2-е изд.
  • NIST SP 800-207: Zero Trust Architecture
Готовы защитить
корпоративную инфраструктуру?

Запишитесь на технический брифинг. Без продаж, только архитекторы и ваша команда.