Настройки хранения данных¶
Настройки хранения (retention) определяют, как долго AppSec.AIGate хранит различные типы данных и когда выполняет их очистку. Правильная настройка retention — это баланс между тремя требованиями:
- Compliance — 152-ФЗ требует хранить журнал учёта обработки ПДн минимум 3 года.
- Защита PII — персональные данные в промптах должны удаляться как можно раньше (минимизация хранения ПДн по принципу data minimization).
- Операционные нужды — события безопасности нужны для расследований инцидентов и формирования отчётов.
Ключевая идея
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, изменениях контентных политик — то есть фиксирует управление обработкой ПДн.
Ограничение соблюдается на трёх уровнях:
- База данных —
CHECK-ограничение:audit_retention_days >= 1095. Попытка записать значение < 1095 приведёт к ошибке PostgreSQL. - API — валидатор Pydantic отклонит запрос с
audit_retention_days < 1095и вернёт422 Unprocessable Entity. - UI — поле ввода имеет атрибут
min=1095, визуально не позволяет ввести меньшее значение.
Когда изменять:
- Оставить 1095 (3 года) — для подавляющего большинства организаций. Соответствует минимальным требованиям 152-ФЗ.
- Увеличить до 1825 (5 лет) — если внутренние регламенты или отраслевые требования (банковское, медицинское законодательство) предписывают более длительные сроки.
- Уменьшить ниже 1095 — невозможно. Система не позволит установить значение менее 3 лет.
report_retention_days — срок хранения отчётов¶
Назначение: определяет, через сколько дней сгенерированные отчёты будут удалены. Удаление затрагивает и запись в базе данных (метаданные отчёта: тип, даты, статус), и сам файл на диске (PDF или CSV).
Значения:
| Свойство | Значение |
|---|---|
| По умолчанию | 365 дней (1 год) |
| Минимум | 1 день |
| Максимум | 36500 дней |
| Тип | целое число (дней) |
Что именно удаляется:
- Запись в таблице
reports— метаданные (ID, тип отчёта, период, кем создан, дата генерации, статус). - Файл на диске — физический файл 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 в журнал.
Предупреждение — исключительно информационное. Система не выполняет автоматическую очистку при превышении порога. Для уменьшения размера:
- Уменьшите
event_retention_days— записи удалятся быстрее. - Уменьшите
detail_retention_days— PII scrub обнулит тяжёлые текстовые поля. - Уменьшите
report_retention_days— удалятся старые PDF/CSV файлы. - Уменьшите лимиты 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). -
Действие:
- Выборка записей отчётов из БД (порциями по
cleanup_batch_size). - Для каждого отчёта: удаление физического файла по пути
report.file_path(например,/data/reports/pii_dlp_2026-01.pdf). - Удаление записи из таблицы
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).
Как это работает:
-
Глобальные настройки — запись в таблице
retention_settingsсtenant_id = NULL. Применяется ко всем tenant, у которых нет собственных настроек. Создаётся автоматически при первом деплое. -
Tenant-специфичные настройки — запись с конкретным
tenant_id. Полностью заменяет глобальные настройки для данного tenant.
Логика очистки в мультитенантной среде:
Воркер при каждом цикле:
- Загружает все retention settings (глобальные + все tenant-специфичные).
- Применяет глобальные настройки ко всем событиям, исключая tenant'ов с собственными настройками.
- Для каждого 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 дней.
Настройка через пользовательский интерфейс¶
- Перейдите в Settings → Retention Settings (
/settings/retention). -
На странице отображаются:
- Карточки Storage Statistics — четыре карточки с размерами таблиц (Security Events, Audit Log, Reports, Total) в мегабайтах.
- Баннер предупреждения — красный алерт, если суммарный размер превышает
storage_warning_threshold_gb. - Поля настроек — 6 полей ввода с иконками, текущими значениями, подсказками о минимальных значениях.
- Информация о последнем обновлении — дата и имя пользователя, который последний раз изменял настройки.
-
Измените необходимые значения.
- Нажмите «Сохранить».
Когда применятся изменения: при следующем цикле очистки воркера (по умолчанию — в течение 24 часов в production, 1 часа в dev). Изменения настроек не запускают немедленную очистку — они сохраняются в БД и будут учтены воркером при следующем цикле.
Внимание: необратимость уменьшения сроков
Если вы уменьшили detail_retention_days с 30 до 7 дней, при следующем цикле воркер обнулит PII-поля во всех событиях старше 7 дней — это все события в диапазоне 7–30 дней, которые раньше ещё хранили промпт. Восстановить обнулённые данные невозможно. Аналогично для hard delete: уменьшение event_retention_days приведёт к массовому удалению.
Перед уменьшением сроков убедитесь:
- Все необходимые отчёты за затрагиваемый период уже сгенерированы.
- Все расследования инцидентов за этот период завершены.
- Данные экспортированы в 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 для неблокирующей перепаковки.