Журнал аудита¶
Журнал аудита в разделе Администрирование → Настройки → Журнал аудита (/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.