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

Настройки хранения данных

Настройки хранения (retention) определяют, как долго AppSec.AIGate хранит различные типы данных и когда выполняет их очистку. Правильная настройка retention — это баланс между тремя требованиями:

  1. Compliance — 152-ФЗ требует хранить журнал учёта обработки ПДн минимум 3 года.
  2. Защита PII — персональные данные в промптах должны удаляться как можно раньше (минимизация хранения ПДн по принципу data minimization).
  3. Операционные нужды — события безопасности нужны для расследований инцидентов и формирования отчётов.

Ключевая идея

AppSec.AIGate использует двухфазное удаление — сначала обнуляет персональные данные (PII scrub), а потом удаляет записи целиком (hard delete). Это позволяет сохранять статистику инцидентов для аудита, при этом не храня сами ПДн дольше необходимого.

Настройки хранения управляются через страницу Settings → Retention Settings (/settings/retention) в Admin UI или через REST API. Доступ — только для пользователей с ролью admin.

Параметры retention

В этом разделе описан каждый параметр, доступный для настройки. Все параметры сохраняются в базе данных и применяются фоновым воркером при следующем цикле очистки.

detail_retention_days — срок хранения детализированных данных

Назначение: определяет, через сколько дней после создания события безопасности из него будут удалены (обнулены) поля, содержащие персональные данные пользователей. Это первая фаза очистки — PII scrub.

Какие поля обнуляются при истечении этого срока:

Поле Тип данных Что содержит Почему обнуляется
user_prompt TEXT Полный текст промпта пользователя. Может содержать ФИО, адреса, номера документов и другие ПДн, которые пользователь отправил в LLM Прямые персональные данные — подлежат минимизации хранения по 152-ФЗ
raw_request JSONB Полный HTTP-запрос: заголовки (могут содержать Authorization-токены, IP), тело (полная структура API-вызова к LLM с промптом и контекстом) Содержит промпт в исходном виде + авторизационные данные
pii_entities JSONB Список обнаруженных PII-сущностей на стороне запроса. Пример: [{"type": "PHONE", "value": "+7-999-123-45-67", "position": [42, 58]}] Содержит сами персональные данные в структурированном виде
output_pii_entities JSONB Список обнаруженных PII/секретов в ответе LLM. Пример: [{"type": "API_KEY", "value": "sk-proj-abc..."}] Содержит секреты и ПДн из ответа модели

Какие поля остаются после PII scrub (не обнуляются):

Все метаданные события сохраняются, что позволяет продолжать формировать статистику, строить графики на Dashboard и генерировать отчёты:

  • event_type — тип события (например, PII_DETECTED).
  • severity — уровень критичности (HIGH, MEDIUM и т.д.).
  • action — принятое решение (BLOCK, SANITIZE, ALLOW).
  • threat_score — числовой score детектора (0.0–1.0).
  • processing_time_ms — время обработки запроса.
  • provider_id, profile_id — к какому провайдеру и профилю относилось событие.
  • trace_id — сквозной идентификатор запроса.
  • tenant_id — идентификатор организации.
  • created_at — время создания события.
  • sanitized_prompt — маскированная версия промпта (например, Привет, меня зовут [PERSON]) — сохраняется, так как уже не содержит ПДн.

Значения:

Свойство Значение
По умолчанию 30 дней
Минимум 1 день
Максимум не может превышать event_retention_days (см. Правила валидации и ограничения)
Тип целое число (дней)

Когда изменять:

  • Уменьшить до 7 дней — если организация работает с большим объёмом ПДн и хочет минимизировать срок их хранения. Подходит для финансовых организаций, медицинских учреждений.
  • Увеличить до 90 дней — если команда безопасности регулярно проводит глубокие расследования инцидентов и нуждается в полных текстах промптов для анализа. После PII scrub текст промпта уже не доступен.
  • Оставить 30 дней — оптимальный баланс для большинства организаций: месяц — достаточно для расследования текущих инцидентов, при этом ПДн не хранятся дольше необходимого.

Пример: событие PII_DETECTED создано 1 марта. При detail_retention_days = 30 поля user_prompt, raw_request, pii_entities и output_pii_entities будут обнулены 31 марта. Само событие (тип, severity, action, score) останется до истечения event_retention_days.

event_retention_days — срок хранения событий безопасности

Назначение: определяет, через сколько дней после создания событие безопасности будет полностью удалено из базы данных. Это вторая фаза очистки — hard delete. После удаления событие не учитывается ни в статистике Dashboard, ни в отчётах, ни в экспорте.

Что удаляется: вся строка в таблице security_events — все поля без исключения. Запись перестаёт существовать.

Значения:

Свойство Значение
По умолчанию 90 дней
Минимум должен быть ≥ detail_retention_days
Максимум 36500 дней (~100 лет, техническое ограничение)
Тип целое число (дней)

Влияние на другие компоненты системы:

  • Dashboard — графики и карточки Top Summary учитывают только неудалённые события. После hard delete исторические данные «исчезают» из графиков. Например, если event_retention_days = 90, то график «Events per day» за последний год покажет данные только за последние 3 месяца.
  • Отчёты — при генерации отчёта за период, в котором события уже удалены, соответствующие разделы будут пустыми или содержать неполные данные. Рекомендуется генерировать регулярные отчёты до истечения срока хранения.
  • SIEM-экспортеры — экспорт событий происходит в реальном времени (при создании события), поэтому на retention не влияет. Если событие уже экспортировано в SIEM, его удаление из AppSec.AIGate не затрагивает копию в SIEM.
  • Фильтрация — удалённые события не возвращаются API и не отображаются в UI.

Когда изменять:

  • Уменьшить до 30 дней — при критически ограниченном дисковом пространстве. Учтите, что вы теряете возможность расследовать инциденты старше 30 дней.
  • Увеличить до 365 дней — если требуется длительное хранение для ретроспективного анализа, аудиторских проверок или юридических разбирательств.
  • Оставить 90 дней — достаточно для большинства SOC-процессов: инциденты расследуются в течение недель, а квартальные отчёты формируются до истечения 90 дней.

Пример: при конфигурации detail_retention_days = 30, event_retention_days = 90 жизненный цикл события:

  • Дни 0–30: полная запись (промпт, PII, метаданные)
  • Дни 31–90: метаданные (промпт и PII обнулены)
  • День 91+: запись удалена

audit_retention_days — срок хранения журнала аудита

Назначение: определяет, через сколько дней записи журнала аудита (административных действий) будут удалены из базы данных. Журнал аудита фиксирует все действия администраторов: создание, изменение и удаление провайдеров, профилей, политик, экспортеров, изменение настроек retention и т.д. (подробнее о записях аудита — см. Аудит и журнал действий).

Значения:

Свойство Значение
По умолчанию 1095 дней (3 года)
Минимум 1095 дней (жёстко ограничено на уровне БД, API и UI)
Максимум 36500 дней (~100 лет)
Тип целое число (дней)

Почему минимум — 3 года:

Требование 152-ФЗ «О персональных данных» (ст. 19, ч. 2) и подзаконных актов обязывает оператора ПДн хранить журнал учёта обработки персональных данных не менее 3 лет. Журнал аудита AppSec.AIGate содержит записи о создании и изменении профилей с настройками PII Detection, настройках retention, изменениях контентных политик — то есть фиксирует управление обработкой ПДн.

Ограничение соблюдается на трёх уровнях:

  1. База данныхCHECK-ограничение: audit_retention_days >= 1095. Попытка записать значение < 1095 приведёт к ошибке PostgreSQL.
  2. API — валидатор Pydantic отклонит запрос с audit_retention_days < 1095 и вернёт 422 Unprocessable Entity.
  3. UI — поле ввода имеет атрибут min=1095, визуально не позволяет ввести меньшее значение.

Когда изменять:

  • Оставить 1095 (3 года) — для подавляющего большинства организаций. Соответствует минимальным требованиям 152-ФЗ.
  • Увеличить до 1825 (5 лет) — если внутренние регламенты или отраслевые требования (банковское, медицинское законодательство) предписывают более длительные сроки.
  • Уменьшить ниже 1095невозможно. Система не позволит установить значение менее 3 лет.

report_retention_days — срок хранения отчётов

Назначение: определяет, через сколько дней сгенерированные отчёты будут удалены. Удаление затрагивает и запись в базе данных (метаданные отчёта: тип, даты, статус), и сам файл на диске (PDF или CSV).

Значения:

Свойство Значение
По умолчанию 365 дней (1 год)
Минимум 1 день
Максимум 36500 дней
Тип целое число (дней)

Что именно удаляется:

  1. Запись в таблице reports — метаданные (ID, тип отчёта, период, кем создан, дата генерации, статус).
  2. Файл на диске — физический файл PDF или CSV по пути report.file_path (обычно в volume /data/reports/).

Если файл уже был удалён с диска вручную (например, администратором ОС), воркер залогирует предупреждение, но продолжит удаление записи в БД.

Когда изменять:

  • Уменьшить до 90 дней — если отчёты генерируются часто и занимают значительный объём диска (один PDF-отчёт за месяц — от 100 КБ до нескольких МБ в зависимости от количества инцидентов).
  • Увеличить до 1825 (5 лет) — если отчёты используются как юридические документы и должны храниться в соответствии с внутренним регламентом.
  • Оставить 365 дней — достаточно для хранения ежемесячных отчётов за последний год.

Рекомендация

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

storage_warning_threshold_gb — порог предупреждения о размере хранилища

Назначение: определяет, при каком суммарном объёме данных (в гигабайтах) система покажет предупреждение на странице Retention Settings. Это индикаторный параметр: он не влияет на поведение системы и не запускает автоматическую очистку, а лишь помогает администратору отслеживать рост данных.

Значения:

Свойство Значение
По умолчанию 10.0 ГБ
Минимум любое положительное число
Максимум не ограничен
Тип число с плавающей точкой (гигабайты)

Как работает:

При каждом открытии страницы Retention Settings (или вызове GET /api/v1/settings/retention) система запрашивает у PostgreSQL размер трёх таблиц (security_events, audit_log, reports) через функцию pg_total_relation_size(). Если суммарный объём превышает storage_warning_threshold_gb × 1024 МБ, в ответе API поле storage_stats.warning устанавливается в true, а в UI отображается красный баннер-предупреждение.

Когда изменять:

  • Уменьшить до 5 ГБ — для инсталляций с ограниченным дисковым пространством (виртуальные машины с малым диском).
  • Увеличить до 50–100 ГБ — для крупных инсталляций с выделенным хранилищем, где 10 ГБ — это нормальный рабочий объём.

cleanup_batch_size — размер батча при очистке

Назначение: определяет, сколько записей обрабатывается за одну итерацию при выполнении операций PII scrub и hard delete. Retention Worker обрабатывает данные не одним большим DELETE или UPDATE, а порциями (батчами), чтобы не блокировать PostgreSQL длительными транзакциями и не создавать lock contention для основных API-запросов.

Значения:

Свойство Значение
По умолчанию 1000 записей за батч
Минимум не ограничен (но не рекомендуется < 100)
Максимум не ограничен (но не рекомендуется > 10000)
Тип целое число

Как работает:

Для каждой фазы очистки воркер выполняет цикл: выбирает cleanup_batch_size записей, подходящих под критерий (например, created_at < cutoff AND user_prompt IS NOT NULL), обрабатывает их (UPDATE или DELETE), фиксирует транзакцию, выжидает паузу 100 мс, затем берёт следующий батч. Цикл продолжается, пока подходящие записи не закончатся.

Когда изменять:

  • Уменьшить до 100–500 — если PostgreSQL работает на слабом оборудовании или делит ресурсы с другими сервисами. Маленькие батчи снижают пиковую нагрузку, но увеличивают общее время очистки.
  • Увеличить до 5000–10000 — для выделенных серверов PostgreSQL с хорошей производительностью I/O. Крупные батчи ускоряют очистку, но создают более длительные блокировки.
  • Оставить 1000 — сбалансированное значение для типовых инсталляций.

Влияние на производительность

При 1 млн накопленных событий и cleanup_batch_size = 1000 очистка потребует ~1000 итераций. При паузе 100 мс между батчами общее время составит ~100 секунд (не считая времени самих SQL-запросов). Это не влияет на доступность системы — очистка выполняется в фоне.

Правила валидации и ограничения

При сохранении настроек retention система проверяет несколько правил. Если правило нарушено, API вернёт ошибку и настройки не будут сохранены.

Правило 1: audit_retention_days ≥ 1095

  • Что: минимальный срок хранения журнала аудита — 1095 дней (3 года).
  • Почему: законодательное требование 152-ФЗ для журнала учёта обработки ПДн.
  • Где проверяется: CHECK-ограничение PostgreSQL + валидатор Pydantic + min-атрибут в UI.
  • Ошибка при нарушении: 422 Unprocessable Entity с сообщением audit_retention_days must be at least 1095.

Правило 2: detail_retention_days ≤ event_retention_days

  • Что: срок хранения деталей не может превышать срок хранения самого события.
  • Почему: детали (промпт, PII-сущности) — это часть события. Бессмысленно «хранить деталь дольше контейнера»: после hard delete события его деталей физически не существует.
  • Где проверяется: CHECK-ограничение PostgreSQL + валидация в API при PUT.
  • Ошибка при нарушении: 422 Unprocessable Entity с сообщением detail_retention_days must not exceed event_retention_days.

Пример нарушения: вы пытаетесь установить detail_retention_days = 120, event_retention_days = 90. API отклонит запрос, потому что детали (120 дней) хранились бы дольше, чем событие (90 дней) — после 90 дней событие удалено, и хранить его детали невозможно.

PII scrub vs Hard delete

AppSec.AIGate использует двухфазную модель очистки данных. Две фазы решают разные задачи: PII scrub убирает персональные данные (compliance), hard delete убирает всю запись (экономия хранилища).

Временная шкала жизни события

  День 0                    День 30                              День 90
  ────────────────────────────┼───────────────────────────────────┼────────────
  │ ПОЛНАЯ ЗАПИСЬ             │ ПОСЛЕ PII SCRUB                   │ УДАЛЕНО
  │                           │                                   │
  │ user_prompt = "Привет,    │ user_prompt = NULL                │ (записи
  │   меня зовут Иван         │ raw_request = NULL                │  нет в БД)
  │   Петров, ИНН 7707..."    │ pii_entities = NULL               │
  │ raw_request = {full JSON} │ output_pii_entities = NULL        │
  │ pii_entities = [{...}]    │                                   │
  │ output_pii_entities=[...] │ event_type = "PII_DETECTED" ✓     │
  │                           │ severity = "MEDIUM" ✓             │
  │ event_type = "PII_DET.."  │ action = "SANITIZE" ✓             │
  │ severity = "MEDIUM"       │ threat_score = 0.12 ✓             │
  │ action = "SANITIZE"       │ processing_time_ms = 45 ✓         │
  │ threat_score = 0.12       │ provider_id = "abc..." ✓          │
  │ processing_time_ms = 45   │ profile_id = "def..." ✓           │
  │ trace_id = "xyz..."       │ trace_id = "xyz..." ✓             │
  │ sanitized_prompt =        │ sanitized_prompt =                │
  │  "Привет, [PERSON],       │  "Привет, [PERSON],               │
  │   ИНН [INN]..."           │   ИНН [INN]..." ✓                 │
  ────────────────────────────┼───────────────────────────────────┼────────────
        ▲                          ▲                                   ▲
   Все данные доступны       Статистика работает,              Запись не существует.
   для расследований         промпт недоступен,                Не учитывается в
   и отчётов                 sanitized_prompt доступен         статистике и отчётах

Обратите внимание

Поле sanitized_prompt (маскированная версия промпта, например "Привет, [PERSON], ИНН [INN]") не обнуляется при PII scrub, потому что уже не содержит настоящих персональных данных — все ПДн заменены на токены типа [PERSON], [INN], [PHONE]. Это позволяет понять характер запроса даже после PII scrub.

Фаза 1 — PII scrub

Срабатывает через detail_retention_days после создания события.

Операция: UPDATE security_events SET user_prompt = NULL, raw_request = NULL, pii_entities = NULL, output_pii_entities = NULL WHERE created_at < cutoff AND (user_prompt IS NOT NULL OR raw_request IS NOT NULL OR pii_entities IS NOT NULL OR output_pii_entities IS NOT NULL)

Важные детали:

  • Воркер пропускает уже очищенные записи (условие IS NOT NULL) — повторный PII scrub одной и той же записи не происходит.
  • Операция выполняется батчами по cleanup_batch_size записей с паузой 100 мс между батчами.
  • После PII scrub запись продолжает учитываться на Dashboard, в отчётах и при экспорте в SIEM (экспорт уже произошёл ранее).

Что это значит для отчётов:

Секция отчёта До PII scrub После PII scrub
Общее количество инцидентов 500 500 (цифра сохраняется)
Группировка по типам событий PII_DETECTED: 200, JAILBREAK_DETECTED: 50, ... Те же цифры (метаданные целы)
Top Threat Details (текст промптов) Отображает полные тексты [данные обнулены в соответствии с политикой хранения]
PII entity breakdown PHONE: 80, EMAIL: 60, INN: 40, ... [данные обнулены] — список PII-сущностей обнулён

Фаза 2 — Hard delete

Срабатывает через event_retention_days после создания события.

Операция: DELETE FROM security_events WHERE created_at < cutoff

Что это значит:

  • Запись полностью удалена из PostgreSQL — она не существует.
  • Dashboard перестаёт её учитывать: графики за тот период «проседают».
  • При генерации отчёта за период с удалёнными событиями разделы будут пустыми или неполными.
  • Если событие было экспортировано в SIEM — копия в SIEM не затрагивается.

Рекомендация

Генерируйте регулярные compliance-отчёты (PII/DLP, инциденты) до истечения event_retention_days. После hard delete данные для отчёта будут потеряны. Лучшая практика — настроить ежемесячную автоматическую генерацию через API или запланированные отчёты.

Storage Statistics

На странице Retention Settings отображаются карточки статистики хранилища, помогающие контролировать рост данных и планировать дисковое пространство.

Как рассчитывается: при каждом открытии страницы (или вызове GET /api/v1/settings/retention) система выполняет SQL-запрос pg_total_relation_size() для трёх таблиц. Значения не кэшируются — вы видите актуальные данные на момент запроса.

Метрики хранилища

Security events (МБ):

Размер таблицы security_events — основная таблица, содержащая все события безопасности. Это обычно самая большая таблица в базе данных. Размер зависит от:

  • Количества запросов к LLM через AppSec.AIGate.
  • Доли запросов, генерирующих события (не каждый запрос генерирует событие — легитимные запросы при выключенном log_allow_decisions не создают событий).
  • Размера сохраняемых промптов и ответов (регулируется через Event Payload Configuration).

Ориентировочный рост: ~1 КБ на событие (метаданные) + 1–64 КБ на промпт/ответ. При 10 000 событий в день — ~100–650 МБ/день.

Audit log (МБ):

Размер таблицы audit_log — записи административных действий. Растёт медленно, пропорционально активности администраторов. Одна запись аудита — ~0.5–2 КБ.

Ориентировочный рост: при 50 административных действиях в день — ~50–100 КБ/день.

Reports (МБ):

Размер таблицы reports (метаданные) + физические файлы PDF/CSV на диске. Один PDF-отчёт — от 100 КБ до нескольких МБ (зависит от количества инцидентов в отчётном периоде и наличия диаграмм). CSV — обычно меньше.

Total (МБ):

Сумма трёх таблиц. Если превышает storage_warning_threshold_gb × 1024, отображается предупреждающий баннер.

Предупреждение о превышении порога

Если суммарный размер превышает порог (storage_warning_threshold_gb, по умолчанию 10 ГБ):

  • В API-ответе поле storage_stats.warning = true.
  • В UI отображается красный баннер: «Общий размер хранилища превышает пороговое значение».
  • Retention Worker при каждом цикле очистки также логирует WARNING в журнал.

Предупреждение — исключительно информационное. Система не выполняет автоматическую очистку при превышении порога. Для уменьшения размера:

  1. Уменьшите event_retention_days — записи удалятся быстрее.
  2. Уменьшите detail_retention_days — PII scrub обнулит тяжёлые текстовые поля.
  3. Уменьшите report_retention_days — удалятся старые PDF/CSV файлы.
  4. Уменьшите лимиты Event Payload Configuration — новые события будут занимать меньше места.

Retention Worker

Фоновый процесс admin-api-retention-worker — это отдельный контейнер, который периодически выполняет очистку данных в соответствии с настройками retention. Воркер запускается автоматически при деплое системы и работает непрерывно.

Параметры окружения воркера

Переменная окружения По умолчанию (prod) По умолчанию (dev) Описание
RETENTION_CLEANUP_INTERVAL_HOURS 24 1 Интервал между циклами очистки в часах. Каждые N часов воркер выполняет полный цикл из 5 фаз. В dev-режиме установлен 1 час для ускорения тестирования
RETENTION_INITIAL_DELAY_SECONDS 60 30 Задержка перед первым циклом очистки после запуска контейнера. Даёт время другим сервисам (PostgreSQL) полностью запуститься перед началом работы
ADMIN_DATABASE_URL postgresql+asyncpg://... Строка подключения к PostgreSQL. Воркер использует ту же БД, что и Admin API

Жизненный цикл воркера

  Старт контейнера
  Инициализация (подключение к БД)
  Ожидание initial_delay_seconds (60 сек)
  ┌─── Цикл очистки ───────────────────────────────┐
  │                                                │
  │  1. Загрузить ВСЕ retention settings из БД     │
  │     (глобальные + per-tenant)                  │
  │                                                │
  │  2. Для глобальных настроек:                   │
  │     → Фазы 1-5 для всех tenant                 │
  │       (кроме тех, у кого свои настройки)       │
  │                                                │
  │  3. Для каждого tenant с персональными         │
  │     настройками:                               │
  │     → Фазы 1-5 только для его данных           │
  │                                                │
  │  4. Запись метрик (Prometheus)                 │
  │                                                │
  └────────────────────────────────────────────────┘
  Ожидание cleanup_interval (24 часа)
  Повторение цикла... (до остановки контейнера)

5 фаз очистки

Каждый цикл состоит из 5 фаз, выполняемых строго последовательно:

Фаза 1 — PII scrub (обнуление персональных данных)

  • Таблица: security_events.
  • Критерий: created_at < (now - detail_retention_days) И хотя бы одно PII-поле не NULL.
  • Действие: UPDATE ... SET user_prompt = NULL, raw_request = NULL, pii_entities = NULL, output_pii_entities = NULL.
  • Батчирование: по cleanup_batch_size записей, с паузой 100 мс между батчами.
  • Метрика Prometheus: retention_events_scrubbed_total (counter, увеличивается на количество обработанных записей).

Фаза 2 — Hard delete events (удаление событий)

  • Таблица: security_events.
  • Критерий: created_at < (now - event_retention_days).
  • Действие: DELETE FROM security_events WHERE ....
  • Батчирование: по cleanup_batch_size записей, с паузой 100 мс.
  • Метрика Prometheus: retention_events_deleted_total.

Порядок фаз 1 и 2 важен

PII scrub выполняется до hard delete. Если воркер прервётся после фазы 1, но до фазы 2 — PII уже будут обнулены. Если бы порядок был обратным и воркер прервался после hard delete, но до PII scrub — записи с PII в диапазоне detail_retention_days < age < event_retention_days остались бы с необнулёнными данными.

Фаза 3 — Hard delete audit (удаление записей аудита)

  • Таблица: audit_log.
  • Критерий: created_at < (now - audit_retention_days).
  • Действие: DELETE FROM audit_log WHERE ....
  • Батчирование: по cleanup_batch_size записей, с паузой 100 мс.
  • Метрика Prometheus: retention_audit_deleted_total.

Фаза 4 — Hard delete reports (удаление отчётов и файлов)

  • Таблица: reports + файлы на диске.
  • Критерий: created_at < (now - report_retention_days).
  • Действие:

    1. Выборка записей отчётов из БД (порциями по cleanup_batch_size).
    2. Для каждого отчёта: удаление физического файла по пути report.file_path (например, /data/reports/pii_dlp_2026-01.pdf).
    3. Удаление записи из таблицы reports.
  • Обработка ошибок: если файл уже не существует на диске (удалён вручную или ранее) — воркер логирует предупреждение и продолжает удаление записи в БД.

  • Метрика Prometheus: retention_reports_deleted_total.

Фаза 5 — Check storage limits (проверка размера хранилища)

  • Действие: запрос pg_total_relation_size() для трёх таблиц, сравнение с storage_warning_threshold_gb.
  • Если объём превышает порог: логируется WARNING с деталями (размер каждой таблицы, общий размер, порог).
  • Если объём в норме: логируется INFO.
  • Автоматических действий нет — фаза исключительно мониторинговая.

Логирование воркера

Воркер записывает результаты каждого цикла в стандартный вывод контейнера (доступно через docker logs admin-api-retention-worker):

# Успешный цикл
[2026-03-10 03:00:12] INFO  [retention-worker] Starting cleanup cycle
[2026-03-10 03:00:12] INFO  [retention-worker] Phase 1: PII scrub — processing global settings
[2026-03-10 03:00:14] INFO  [retention-worker] Phase 1 complete: scrubbed=42 events
[2026-03-10 03:00:14] INFO  [retention-worker] Phase 2: Hard delete events
[2026-03-10 03:00:15] INFO  [retention-worker] Phase 2 complete: deleted=156 events
[2026-03-10 03:00:15] INFO  [retention-worker] Phase 3: Hard delete audit
[2026-03-10 03:00:15] INFO  [retention-worker] Phase 3 complete: deleted=0 audit entries
[2026-03-10 03:00:15] INFO  [retention-worker] Phase 4: Hard delete reports
[2026-03-10 03:00:15] INFO  [retention-worker] Phase 4 complete: deleted=3 reports
[2026-03-10 03:00:15] INFO  [retention-worker] Phase 5: Storage check — total=2.4 GB, threshold=10.0 GB — OK
[2026-03-10 03:00:15] INFO  [retention-worker] Cleanup cycle completed in 3.2s

# Предупреждение о хранилище
[2026-03-10 03:00:15] WARNING [retention-worker] Phase 5: Storage check — total=12.7 GB exceeds threshold=10.0 GB

Prometheus-метрики воркера

Если в инфраструктуре настроен Prometheus, воркер экспортирует следующие метрики:

Метрика Тип Описание
retention_events_scrubbed_total Counter Общее количество событий, прошедших PII scrub (нарастающий итог)
retention_events_deleted_total Counter Общее количество удалённых событий
retention_audit_deleted_total Counter Общее количество удалённых записей аудита
retention_reports_deleted_total Counter Общее количество удалённых отчётов
retention_cycle_errors_total Counter Количество циклов, завершившихся с ошибкой
retention_cycle_duration_seconds Histogram Длительность цикла очистки (секунды)
retention_last_success_timestamp Gauge Время последнего успешного цикла (UNIX timestamp)

Пример алерта для Prometheus/Grafana:

Если воркер перестал работать (упал контейнер, ошибка подключения к БД):

# Пример правила: нет успешных циклов более 48 часов
- alert: RetentionWorkerStale
  expr: time() - retention_last_success_timestamp > 172800
  for: 5m
  labels:
    severity: warning
  annotations:
    summary: "Retention worker не выполнял очистку более 48 часов"

Мультитенантность

Настройки retention поддерживают мультитенантную модель: можно задать глобальные настройки по умолчанию и переопределить их для отдельных организаций (tenant).

Как это работает:

  1. Глобальные настройки — запись в таблице retention_settings с tenant_id = NULL. Применяется ко всем tenant, у которых нет собственных настроек. Создаётся автоматически при первом деплое.

  2. Tenant-специфичные настройки — запись с конкретным tenant_id. Полностью заменяет глобальные настройки для данного tenant.

Логика очистки в мультитенантной среде:

Воркер при каждом цикле:

  1. Загружает все retention settings (глобальные + все tenant-специфичные).
  2. Применяет глобальные настройки ко всем событиям, исключая tenant'ов с собственными настройками.
  3. Для каждого tenant с персональными настройками — применяет их отдельно.

Пример:

Tenant detail event audit report Откуда
(глобальные) 30 90 1095 365 По умолчанию
bank-prod 7 365 1825 730 Персональные (строгий compliance)
dev-team Используются глобальные

В этом примере для bank-prod PII обнуляется через 7 дней, а события хранятся год. Для dev-team используются стандартные 30/90 дней.

Настройка через пользовательский интерфейс

  1. Перейдите в Settings → Retention Settings (/settings/retention).
  2. На странице отображаются:

    • Карточки Storage Statistics — четыре карточки с размерами таблиц (Security Events, Audit Log, Reports, Total) в мегабайтах.
    • Баннер предупреждения — красный алерт, если суммарный размер превышает storage_warning_threshold_gb.
    • Поля настроек — 6 полей ввода с иконками, текущими значениями, подсказками о минимальных значениях.
    • Информация о последнем обновлении — дата и имя пользователя, который последний раз изменял настройки.
  3. Измените необходимые значения.

  4. Нажмите «Сохранить».

Когда применятся изменения: при следующем цикле очистки воркера (по умолчанию — в течение 24 часов в production, 1 часа в dev). Изменения настроек не запускают немедленную очистку — они сохраняются в БД и будут учтены воркером при следующем цикле.

Внимание: необратимость уменьшения сроков

Если вы уменьшили detail_retention_days с 30 до 7 дней, при следующем цикле воркер обнулит PII-поля во всех событиях старше 7 дней — это все события в диапазоне 7–30 дней, которые раньше ещё хранили промпт. Восстановить обнулённые данные невозможно. Аналогично для hard delete: уменьшение event_retention_days приведёт к массовому удалению.

Перед уменьшением сроков убедитесь:

  1. Все необходимые отчёты за затрагиваемый период уже сгенерированы.
  2. Все расследования инцидентов за этот период завершены.
  3. Данные экспортированы в SIEM (если экспорт настроен — он происходит в реальном времени, и старые события уже в SIEM).

Управление через API

Настройки retention доступны через REST API. Используйте его для автоматизации: скрипты деплоя, IaC, мониторинг.

Получить текущие настройки:

curl -s http://localhost:8001/api/v1/settings/retention \
  -H "X-Forwarded-User: admin" \
  -H "X-Forwarded-Email: admin@company.com" \
  -H "X-Forwarded-Groups: admin" \
  -H "X-Forwarded-Tenant-Id: production" | jq .

Ответ:

{
  "id": "a1b2c3d4-...",
  "tenant_id": null,
  "event_retention_days": 90,
  "detail_retention_days": 30,
  "audit_retention_days": 1095,
  "report_retention_days": 365,
  "storage_warning_threshold_gb": 10.0,
  "cleanup_batch_size": 1000,
  "updated_at": "2026-03-10T14:30:00Z",
  "updated_by": "admin@company.com",
  "storage_stats": {
    "security_events_size_mb": 1250.4,
    "audit_log_size_mb": 12.7,
    "reports_size_mb": 85.3,
    "total_size_mb": 1348.4,
    "warning": false
  }
}

Изменить настройки (частичное обновление — указывайте только те поля, которые хотите изменить):

# Уменьшить detail retention до 7 дней и увеличить event retention до 180 дней
curl -s -X PUT http://localhost:8001/api/v1/settings/retention \
  -H "Content-Type: application/json" \
  -H "X-Forwarded-User: admin" \
  -H "X-Forwarded-Email: admin@company.com" \
  -H "X-Forwarded-Groups: admin" \
  -H "X-Forwarded-Tenant-Id: production" \
  -d '{
    "detail_retention_days": 7,
    "event_retention_days": 180
  }' | jq .

Примеры ошибок валидации:

# Попытка установить audit < 1095 дней
curl -s -X PUT http://localhost:8001/api/v1/settings/retention \
  -H "Content-Type: application/json" \
  -H "X-Forwarded-User: admin" \
  -H "X-Forwarded-Email: admin@company.com" \
  -H "X-Forwarded-Groups: admin" \
  -d '{"audit_retention_days": 365}'
# → 422 Unprocessable Entity: "audit_retention_days must be at least 1095"

# Попытка установить detail > event
curl -s -X PUT http://localhost:8001/api/v1/settings/retention \
  -H "Content-Type: application/json" \
  -H "X-Forwarded-User: admin" \
  -H "X-Forwarded-Email: admin@company.com" \
  -H "X-Forwarded-Groups: admin" \
  -d '{"detail_retention_days": 120, "event_retention_days": 90}'
# → 422 Unprocessable Entity: "detail_retention_days must not exceed event_retention_days"

Доступ: только роль admin. Роли operator и viewer получат 403 Forbidden.

Типичные конфигурации

Конфигурация по умолчанию

Параметр Значение Обоснование
detail_retention_days 30 ПДн хранятся месяц — достаточно для оперативного расследования
event_retention_days 90 Метаданные событий хранятся квартал — покрывает типичные SOC-процессы
audit_retention_days 1095 Минимум по 152-ФЗ
report_retention_days 365 Годовой архив отчётов
storage_warning_threshold_gb 10.0 Подходит для типовых ВМ
cleanup_batch_size 1000 Оптимально для большинства PostgreSQL-конфигураций

Подходит для большинства инсталляций с умеренной нагрузкой (до 50 000 событий в день).

Максимальная защита PII (финансы, медицина)

Параметр Значение Обоснование
detail_retention_days 7 ПДн удаляются через неделю. Минимизация хранения для организаций с PCI DSS, HIPAA, строгими внутренними политиками
event_retention_days 90 Метаданные нужны для квартальных отчётов
audit_retention_days 1825 5 лет — требование банковского регулирования
report_retention_days 730 2 года — для аудиторских проверок

Длительное расследование (SOC / incident response)

Параметр Значение Обоснование
detail_retention_days 90 Полные тексты промптов хранятся 3 месяца для глубокого анализа инцидентов и охоты за угрозами (threat hunting)
event_retention_days 365 Годовой горизонт для ретроспективного анализа и выявления паттернов
audit_retention_days 1095 Стандартный минимум
report_retention_days 365 Годовой архив

Минимальное хранилище (ограниченные ресурсы)

Параметр Значение Обоснование
detail_retention_days 7 Минимум PII
event_retention_days 30 Месяц — минимально достаточно для оперативных нужд
audit_retention_days 1095 Нельзя уменьшить (требование 152-ФЗ)
report_retention_days 90 Квартальный архив — скачивайте PDF/CSV до истечения
storage_warning_threshold_gb 5.0 Раннее предупреждение
cleanup_batch_size 500 Меньшие батчи — ниже пиковая нагрузка на БД

Типичные проблемы и решения

Воркер не запускается или не выполняет очистку

Симптом: данные не удаляются, несмотря на истёкшие сроки retention.

Диагностика:

# Проверить статус контейнера
docker ps | grep retention-worker

# Проверить логи воркера
docker logs admin-api-retention-worker --tail 50

# Проверить подключение к БД
docker exec admin-api-retention-worker python -c "from app.core.config import settings; print(settings.ADMIN_DATABASE_URL)"

Типичные причины:

  • Контейнер admin-api-retention-worker не запущен или перезапускается в цикле (проверьте логи).
  • Неверная строка подключения к PostgreSQL (ADMIN_DATABASE_URL).
  • PostgreSQL недоступен (перезапуск, сетевая проблема).

Данные удаляются раньше, чем ожидалось

Симптом: промпты в событиях стали NULL раньше, чем через detail_retention_days.

Причина: кто-то уменьшил detail_retention_days. Проверьте журнал аудита:

curl -s "http://localhost:8001/api/v1/audit-log?resource_type=retention_settings&limit=10" \
  -H "X-Forwarded-User: admin" \
  -H "X-Forwarded-Groups: admin" | jq '.items[] | {timestamp: .created_at, user: .user_id, changes: .details}'

Размер базы данных продолжает расти, несмотря на retention

Симптом: storage_stats.total_size_mb не уменьшается после hard delete.

Причина: PostgreSQL не сразу освобождает дисковое пространство после DELETE. Удалённые строки помечаются как «мёртвые», и реальное освобождение происходит при VACUUM (автоматический autovacuum или ручной VACUUM FULL).

Решение:

# Проверить мёртвые строки
docker exec llm-firewall-postgres psql -U postgres -d admin_api_db \
  -c "SELECT relname, n_dead_tup, last_autovacuum FROM pg_stat_user_tables WHERE n_dead_tup > 1000;"

# Принудительный VACUUM (осторожно: блокирует таблицу)
docker exec llm-firewall-postgres psql -U postgres -d admin_api_db \
  -c "VACUUM FULL security_events;"

Предупреждение

VACUUM FULL блокирует таблицу на время выполнения. Для production-инсталляций выполняйте в период минимальной нагрузки или используйте pg_repack для неблокирующей перепаковки.