Перейти к содержанию

Журнал аудита

Журнал аудита в разделе Администрирование → Настройки → Журнал аудита (/admin/settings?tab=audit-log) отвечает на два вопроса, которые проверка безопасности задаёт экземпляру, хранящему карту всего ИТ-ландшафта: что в нём изменилось и кто и как входил в систему. Он разделён на две вложенные вкладки:

Вкладка URL Что она фиксирует
Изменения /admin/settings?tab=audit-log Каждую запись в ландшафт — карточки, связи, риски, теги, роли заинтересованных сторон, черновики решений, — сгруппированную в пакеты мутаций, с пособытийным диффом и Откатом
Безопасность и администрирование /admin/settings?tab=audit-log&view=security Входы и выходы, неудачные попытки, блокировки, сеансы SSO и прокси, события паролей, работа от имени роли и каждое административное действие

Они разделены намеренно. Изменения — рабочий инструмент: он нужен, чтобы увидеть и отменить ошибочную запись, и хранит короткую историю. Безопасность и администрирование — доказательный след: его записи нельзя ни изменить, ни удалить, а по умолчанию он хранится год.

Кто может его просматривать

Обе вкладки требуют разрешения admin.events («Просмотр журнала аудита и потока событий»), которым по умолчанию обладает только роль Admin. Чтобы дать специалисту по безопасности или комплаенсу доступ на чтение, не делая его администратором, создайте роль с admin.events в разделе Пользователи и роли и назначьте её ему.

Изменения

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

Источник Значение
Веб Веб-интерфейс Turbo EA
API Прямой вызов REST API (скрипт, интеграция)
ИИ-инструмент ИИ-ассистент, подключённый через сервер MCP
Расширение Установленное расширение, фиксируется как пакет ext:<key>

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

Пакеты хранятся MUTATION_BATCH_RETENTION_DAYS дней (переменная окружения, по умолчанию 15), после чего удаляются автоматически. Сами события остаются на вкладке История каждой карточки и после удаления пакета.

Безопасность и администрирование

Журнал безопасности и администрирования

Вкладка Безопасность и администрирование показывает по одной записи на каждое значимое для безопасности действие, сначала самые новые:

  • входы и выходы по паролю, через SSO или через доверенный обратный прокси;
  • неудачные попытки входа, каждая с кодом причины, объясняющим, почему она не удалась;
  • блокировки учётных записей после повторных неудач;
  • регистрации, а также установка, сброс и смена паролей;
  • имперсонация роли — администратор начинает и завершает режим Просмотр от имени роли…;
  • административные действия — изменения пользователей, ролей, настроек, метамодели, тегов, вычислений, расширений, импортов, интеграций, публичных порталов и опубликованных диаграмм, опросов и доступа оператора (см. Административные действия);
  • экспорт данных — экспорт карточек в CSV и JSON, экспорт рабочей области и экспорт для другой EA-платформы (см. Экспорт данных), — а также экспорт самого этого журнала.

Столбцы

Столбец Описание
Когда Дата и время действия
Категория auth (аутентификация), admin (административные действия) или access (экспорт и другой доступ к данным)
Действие Что произошло, например auth.login.failed — см. каталог действий
Результат Успех или Неудача
Исполнитель Вошедший в систему пользователь, выполнивший действие. Пусто, если никто не был в системе — например, при неудачном входе
Субъект Учётная запись, которой касалось действие, — адрес электронной почты, введённый при неудачном входе, или пользователь, чей пароль был сброшен
Цель Объект действия, если он есть, — например, роль, выбранная при начале имперсонации
IP IP-адрес клиента (см. IP-адрес клиента)
Источник Откуда пришёл запрос: веб, API, ИИ-инструмент, расширение, ops или система
Роль имперсонации Если администратор просматривал приложение от имени другой роли — эта роль. Исполнителем остаётся настоящий администратор

Столбцы можно показывать, скрывать, переставлять и закреплять, как в любой другой таблице данных; Когда и Действие отображаются всегда.

Фильтры

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

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

Как читать запись

Щёлкните строку, чтобы открыть панель записи. Она показывает каждое поле записи — когда, кто, с какого IP-адреса и из какого браузера — а в разделе Подробности то, что запись зафиксировала, изложенное простым языком, а не хранимыми ключами:

  • Изменения — одно предложение на каждое изменение. Например, правка типа карточки читается как Поле «Критичность для бизнеса» (Одиночный выбор) добавлено в раздел «Управление» или Вариант «Высокая» поля «Критичность для бизнеса» переименован в «Критическая». Поля, разделы, варианты, роли и порталы называются по своим меткам, разрешения — по описанию, языки — по названию.
  • До / После — таблица изменённых значений, по одной строке на поле, каждое поле названо своей меткой. Значения отформатированы: Да или Нет, даты в формате даты рабочей области, цвета в виде образца, размеры файлов в КБ или МБ. Секреты никогда не сохраняются: пароль, токен или секрет клиента заменяется до записи и отображается как Секретное значение.
  • Контекст — сведения, которые поясняют изменение, но не являются его частью: текущий адрес портала и опубликован ли он, были ли заменены учётные данные подключения, сколько строк затронул импорт.

Для неудачного входа над подробностями показана Причина — неверный пароль, неизвестная учётная запись, временно заблокированная учётная запись.

Записи, сделанные до версии 2.161.0, показывают подробности в том виде, в каком они были записаны: старые и новые значения по-прежнему отображаются в таблице, а то, что панель не может прочитать, показывается как необработанный JSON.

На панели нет действий. Записи нельзя изменить или удалить.

Экспорт в CSV

Кнопка Экспорт в CSV на панели инструментов скачивает записи, соответствующие текущим фильтрам, в виде CSV-файла — до 50 000 строк. Сам экспорт тоже фиксируется как access.audit_log.exported, так что экспорт журнала безопасности всегда оставляет в нём след.

Каталог действий

Действие Фиксируется, когда
auth.login.succeeded пользователь входит по адресу электронной почты и паролю
auth.login.failed вход по паролю отклонён. Код причины объясняет почему (см. ниже)
auth.login.locked пятая подряд неудачная попытка блокирует учётную запись на 15 минут. В подробностях указано время окончания блокировки
auth.logout вошедший пользователь выходит из системы. Выход без действительного сеанса ничего не фиксирует
auth.sso.succeeded пользователь входит через поставщика SSO. В подробностях указаны поставщик, субъект у поставщика удостоверений и то, была ли учётная запись создана этим входом
auth.sso.failed вход через SSO отклонён — недопустимый домен, отсутствующий адрес электронной почты, локальная учётная запись с тем же адресом, неактивная учётная запись. В подробностях указаны поставщик и причина
auth.proxy_session.succeeded пользователь входит через доверенный обратный прокси
auth.proxy_session.failed вход через обратный прокси отклонён
auth.register пользователь создаёт учётную запись через самостоятельную регистрацию
auth.password.set приглашённый пользователь задаёт свой первый пароль
auth.password.reset_requested Кто-то запрашивает письмо для сброса пароля. Всегда записывается как успех с введённым адресом, чтобы ответ ничего не раскрывал; в деталях указано, найдена ли учётная запись и было ли отправлено письмо
auth.password.reset пароль изменён по ссылке для сброса
auth.password.changed вошедший пользователь меняет собственный пароль
auth.impersonation.started администратор включает Просмотр от имени роли…. Цель — выбранная роль
auth.impersonation.stopped администратор возвращается к своей роли

Коды причин для auth.login.failed:

Причина Значение
unknown_user Нет учётной записи с таким адресом электронной почты
sso_account Учётная запись входит через SSO и не имеет пароля
no_password У учётной записи ещё нет пароля — приглашение так и не было принято
locked Учётная запись заблокирована после повторных неудач
bad_password Неверный пароль
inactive Учётная запись деактивирована

Коды причин для auth.sso.failed, auth.proxy_session.failed, auth.password.set и auth.password.reset:

Причина Значение
expired Срок ограниченного по времени доступа учётной записи истёк
hd_mismatch Учётная запись Google принадлежит недопустимому домену
no_email Поставщик удостоверений не вернул адрес e-mail
no_subject Поставщик удостоверений не вернул идентификатор субъекта
local_account Локальная учётная запись с паролем уже использует этот e-mail
no_account Учётной записи нет, и учётные записи не создаются автоматически
exchange_failed Поставщик удостоверений не завершил вход
unauthenticated Обратный прокси не аутентифицировал запрос
identity_rejected Переданная личность отклонена (домен или неподтверждённый e-mail)
invalid_token Ссылка приглашения или сброса недействительна или истекла

Всплеск неудач unknown_user с одного IP-адреса — так выглядит распыление паролей (password spraying); серия bad_password против одной учётной записи, за которой следует auth.login.locked, — это попытка подобрать пароль к этой учётной записи.

Административные действия

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

  • Секреты маскируются. Пароль SMTP, секрет клиента SSO, ключ поставщика ИИ, учётные данные ServiceNow или любое другое секретное значение записывается как ***: запись показывает, что значение изменилось, но никогда — каким оно было или стало.
  • Текст лицензии и учётные данные никогда не сохраняются. Лицензия расширений идентифицируется, а не копируется, а пароль, который администратор задаёт пользователю, записывается как изменённый, но никогда — со своим значением.

Сохранение, которое ничего не меняет, не записывается, как и изменение пользователем собственного имени или языка в профиле. Объёмная конфигурация — поля, переводы или макет типа карточки, фильтры портала — описывается своим размером, а не копируется; если размер не изменился, добавляется короткий отпечаток содержимого, чтобы запись всё равно показывала, что что-то изменилось. Исключение — переопределения прав типа карточки для отдельных ролей: каждая изменённая ячейка указывается со старым и новым значением, причём пустое значение означает, что действует собственное право роли.

Область Действия Что записывается
Пользователи и роли admin.user.created, .updated, .deleted, .bulk_updated, .bulk_deleted, .unlocked; admin.user.invitation.resent, .deleted; admin.role.created, .updated, .archived, .restored; admin.stakeholder_role.created, .updated, .deleted, .archived, .restored Учётные записи, которые созданы, изменены, включены или отключены, удалены (по одной или массово) и разблокированы, с изменёнными полями — роль, электронная почта, имя, активность; повторно отправленные или отозванные приглашения; роли приложения и роли стейкхолдеров по типам, с предоставленными или отозванными разрешениями
Настройки admin.settings.updated Одна запись на каждую сохранённую настройку — электронная почта, аутентификация и SSO, регистрация, ИИ, MCP, языки, переключатели модулей, оформление, логотип и значок сайта, сроки хранения. Объект — настройка; подробности — её старое и новое значение, секреты замаскированы
Метамодель admin.metamodel.type.* (including .references_generated), admin.metamodel.relation_type.*, admin.metamodel.resource_type.*, admin.metamodel.category.* (including .reordered), admin.principle.* (including .imported), admin.regulation.* Типы карточек, типы связей и типы ресурсов, которые созданы, изменены, удалены или восстановлены, с изменёнными свойствами; ссылки карточек, сгенерированные для типа; принципы EA, включая импортированные из каталога; регламенты соответствия; категории типов карточек (архитектурные уровни), которые созданы, переименованы, перекрашены, переупорядочены или удалены
Теги и вычисления admin.tag_group.*, admin.tag.*, admin.calculation.* Группы тегов и теги; вычисляемые поля, которые созданы, изменены, удалены, включены или отключены, со старой и новой формулой, а также запуск вычисления для всех карточек (.recalculated)
Расширения admin.extension.install.uploaded, .applied, .discarded; admin.extension.store.claimed, .refreshed, .installed; admin.extension.enabled, .disabled, .uninstalled; admin.extension.license.updated, .removed Загруженные, установленные или отменённые пакеты; лицензии и загрузки из магазина расширений; включённые, отключённые и удалённые расширения; заменённая или удалённая лицензия — с расширением и его версией, но никогда с текстом лицензии
Перенос рабочей области и миграция admin.workspace.import.uploaded, .applied, .completed, .discarded; admin.migration.uploaded, .field_mappings.updated, .applied, .deleted Загруженный пакет рабочей области, запуск, завершение или отмена его импорта; загруженная миграция платформы, изменение её сопоставлений полей, её применение или удаление
Интеграции admin.servicenow.connection.*, admin.servicenow.mapping.*, admin.servicenow.sync.pulled, .pushed, .applied Подключения ServiceNow (учётные данные замаскированы) и сопоставления; каждое получение, отправка и применение подготовленных записей
Публичный доступ admin.web_portal.created, .updated, .deleted; admin.diagram.published, .unpublished Веб-порталы и опубликованные диаграммы — всё, что делает данные доступными без учётной записи
Опросы admin.survey.sent, admin.survey.closed Опрос, отправленный получателям или закрытый
Доступ оператора admin.ops.rescue_access.granted, .revoked Аварийный доступ, предоставленный или отозванный через операционный API, записывается рядом с существующими событиями ops.*

Экспорт данных

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

Действие Фиксируется, когда Подробности
access.export.cards Карточки экспортируются через CSV- или JSON-экспорт API (/cards/export/csv, /cards/export/json), как это делают скрипты, интеграции и ИИ-ассистенты format (csv или json), type (тип или типы карточек) и rows (число карточек). Целью является тип карточки, если экспорт охватывал ровно один тип
access.export.workspace Скачивается полный пакет рабочей области — из раздела Перенос рабочей области или плоскостью управления через операционный API, который не фиксирует исполнителя и фиксирует requested_by: ops include_archived и size_bytes
access.export.migration Рабочая область экспортируется для другой EA-платформы в разделе Администрирование → Настройки → Миграция (см. Миграция платформы) Целевая платформа, include_archived и size_bytes
access.audit_log.exported Кто-то экспортирует журнал безопасности в CSV rows

Что не фиксируется

  • Обновление токена. Веб-приложение продлевает сеанс по таймеру, поэтому каждая открытая вкладка добавляла бы записи, и ни одна из них ничего бы не значила.
  • Запросы, отклонённые из-за истёкшего или недействительного токена сеанса. Они возникают каждый раз, когда сеанс завершается естественным образом.
  • Чтение OData-фидов. Excel и Power BI опрашивают OData-фид сохранённого представления по расписанию, так что каждое обновление добавляло бы запись.
  • Таблицы и презентации, построенные в браузере. Загрузки Excel и PowerPoint из инвентаря и отчётов формируются из данных, которые страница уже загрузила, поэтому это чтение, а не экспорт с сервера.
  • Обычный доступ на чтение — открытие карточки, запуск отчёта, поиск по инвентарю.

Срок хранения

По умолчанию записи хранятся 365 дней. Измените это в разделе Администрирование → Настройки → Общие → Управление данными → Срок хранения журнала безопасности: любое число дней до 3650 или 0, чтобы хранить записи бессрочно. Задание раз в ночь удаляет записи старше этого срока и каждый раз перечитывает настройку, так что изменение вступает в силу без перезапуска.

Это задание хранения — единственное, что когда-либо удаляет запись. Ни в интерфейсе, ни в API нет действий для изменения или удаления — ни для одной роли.

Журнал намеренно не входит в Перенос workspace: это история безопасности данного экземпляра, а не содержимое workspace, и при клонировании экземпляра он не копируется.

Поток аудита в формате JSON

Каждую запись бэкенд также пишет одной строкой JSON в логгер turbo_ea.audit — в тот же момент, когда она сохраняется. Бэкенд пишет журнал в стандартный вывод, поэтому поток попадает туда же, куда уже собираются журналы ваших контейнеров, — docker compose logs backend, сбор журналов Kubernetes или любой агент доставки в SIEM — без какой-либо настройки в Turbo EA:

docker compose logs -f backend | grep turbo_ea.audit

Строка пишется в момент регистрации записи. Если транзакция запроса после этого завершится ошибкой, строка останется без записи в таблице: таблица — это реестр, поток — живая лента.

Каждая строка содержит те же поля, что и запись:

Поле Содержимое
audit_id, created_at Идентификатор записи и момент её записи
category, action, outcome Что произошло и удалось ли это
actor_user_id, actor_email Кто это сделал
subject_email Затронутая учётная запись
target_type, target_id, target_label На что было направлено действие
ip, user_agent Клиент
origin web, api, mcp, ext, ops или system
impersonator_user_id, impersonated_role Заполняются, пока администратор просматривает приложение от имени другой роли
details До четырёх ключей, секреты уже замаскированы: reason (код сбоя), changes ({field: {old, new}}), items (смысловые изменения, {kind, …} — например, field.added) и context (простые сведения)

Отправка потока в централизованное хранилище журналов сохраняет копию вне экземпляра, вне досягаемости тех, кто может его администрировать, — именно это нужно для проверки на внутренние угрозы. Как его собирать, см. в разделе Журналы и поток аудита.

IP-адрес клиента

Столбец IP фиксирует адрес клиента, а не прокси перед бэкендом. Поставляемый пограничный nginx записывает в заголовок X-Real-IP адрес, с которого он принял соединение, а бэкенд читает этот заголовок, потому что опубликованный образ бэкенда задаёт TRUST_PROXY_HEADERS=true. Значение, не являющееся корректным IP-адресом, отбрасывается, а не записывается.

  • Оставьте TRUST_PROXY_HEADERS включённым, пока каждый запрос попадает в бэкенд через поставляемый nginx, — так работают стандартный стек, Helm-чарт и шаблоны управляемых контейнеров.
  • Выключите его (TRUST_PROXY_HEADERS=false), если вы открываете контейнер бэкенда напрямую, без поставляемого nginx перед ним: тогда клиент может прислать собственный X-Real-IP и сам выбрать записываемый адрес.
  • За балансировщиком нагрузки, ingress-контроллером или CDN поставляемый nginx получает каждое соединение от этого промежуточного узла и потому сам по себе записывает для каждого пользователя адрес балансировщика. Задайте NGINX_TRUSTED_PROXIES в контейнере nginx, как описано ниже.

За балансировщиком нагрузки

NGINX_TRUSTED_PROXIES перечисляет адреса промежуточных узлов перед поставляемым nginx — IP-адреса или диапазоны CIDR через запятую или пробел. Тогда nginx берёт адрес клиента из заголовка X-Forwarded-For, который добавляют эти узлы, — но только для соединения с одного из перечисленных адресов — и пропускает в этом заголовке каждый перечисленный адрес, так что цепочка прокси сводится к первому адресу, который не принадлежит вам. Этот адрес заменяет адрес соединения, а заголовок X-Real-IP, который читает бэкенд, передаёт его без изменений. Пустое значение, значение по умолчанию, не доверяет никому.

Чтобы найти значение, посмотрите журнал доступа пограничного nginx (docker compose logs nginx, kubectl logs deployment/turbo-ea-nginx или просмотр журналов платформы): адрес в начале каждой строки — это узел, которому нужно доверять, а последнее поле в кавычках — отправленный им заголовок X-Forwarded-For.

Развёртывание Где задать Типичное значение
Docker Compose, браузеры обращаются к nginx напрямую — Оставить пустым
Docker Compose за вашим собственным обратным прокси NGINX_TRUSTED_PROXIES в .env Адрес обратного прокси, каким его видит nginx
Kubernetes за ingress-контроллером Значение чарта nginx.trustedProxies CIDR подов кластера, например 10.244.0.0/16
AWS ECS Fargate NginxTrustedProxies / Terraform nginx_trusted_proxies Диапазоны CIDR подсетей балансировщика нагрузки
Azure Container Apps nginxTrustedProxies / Terraform nginx_trusted_proxies Инфраструктурная подсеть среды
Google Cloud Run NGINX_TRUSTED_PROXIES в манифесте / Terraform nginx_trusted_proxies Адреса, которые показывает журнал доступа

Держите список таким же узким, как сами промежуточные узлы. Каждому перечисленному адресу верят, когда он называет клиента, поэтому диапазон, из которого подключаются ваши пользователи, — скажем, весь 10.0.0.0/8 во внутреннем развёртывании — позволил бы любому из них записать в журнал другой адрес. Без настройки в столбце виден балансировщик нагрузки: пользы мало, но и подделки нет.

Ограничение частоты входа считает попытки по адресу клиента из того же заголовка, поэтому за балансировщиком нагрузки эта настройка также не даёт неудачным попыткам одного человека замедлять всех остальных. Это относится ко входам, которые доходят до бэкенда через граничный nginx; сервер MCP входит в бэкенд напрямую, поэтому его собственные вызовы входа по-прежнему делят адрес контейнера MCP. Ключ для каждого клиента доверяет этому заголовку так же, как журнал аудита: он предполагает, что входы попадают в бэкенд только через пограничный nginx, что поставляемый файл compose и Helm-чарт обеспечивают, не публикуя бэкенд. Вызывающая сторона, способная обратиться к бэкенду напрямую, могла бы выбрать себе квоту, задав заголовок самостоятельно; не публикуйте бэкенд или отключите TRUST_PROXY_HEADERS.