Когда AI-агент — Cursor, Claude Code или Copilot — читает репозиторий с персональными данными (ПДн), отправляет их в LLM и получает назад инструкцию модифицировать запись в базе, именно в этот момент начинается обработка ПДн в смысле 152-ФЗ. И именно в этот момент у оператора возникает обязанность вести аудит логирование: кто, когда, к каким данным и на каком правовом основании обращался. Между «у нас есть логи в stdout» и «журнал, который пройдёт проверку Роскомнадзора и ФСТЭК» — дистанция размером с tamper-evident hash chain, retention-политику и географическую привязку хранилища.
Эта статья — technical compliance-гайд для платформ governance AI. В ней нет общих слов про «важность безопасности»: только конкретные события, поля, сроки хранения и реализация hash-chain журнала на Rust, которую можно скопировать в production.
Краткий ответ
Что вы узнаете:
- Какие именно нормативные акты (152-ФЗ, ФЗ-149, приказы ФСТЭК №17 и №21) накладывают требования к журналированию и где в них «спрятан» ИИ.
- Таблица из 12 обязательных классов событий с полями, источником сбора и сроком retention.
- Как построить tamper-evident hash-chain журнал на HMAC-SHA256 с anchoring и верификацией.
- Retention-конфиг hot/warm/cold с WORM-хранением и географической привязкой к РФ.
- Чек-лист из 15 пунктов для прохождения аудита соответствия.
12
5 лет
Нормативная база: 152-ФЗ и ФЗ-149
Российская модель регулирования в части информационной безопасности держится на трёх опорах, и AI-агенты подпадают под каждую из них — просто потому, что обрабатывают те же данные, что и любая ИСПДн.
Федеральный закон №152-ФЗ «О персональных данных» требует от оператора принимать «необходимые правовые, организационные и технические меры». Конкретика расшифрована в приказе ФСТЭК №21 («Об утверждении состава и содержания организационных и технических мер»): пункт 6.1 прямо предписывает «учёт и хранение» действий по доступу к ПДн, а пункт 6.2 — регистрацию событий безопасности. Уровень защищённости (УЗ-1…УЗ-4) определяет глубину: для УЗ-1 и УЗ-2 требуется фиксация каждого доступа с возможностью восстановления хронологии.
Федеральный закон №149-ФЗ «Об информации, ИТ и о защите информации» — это каркас. Статья 16 устанавливает обязанность владельца ИС защищать обрабатываемую информацию, а развитие ИИ-направления — Указ Президента №490 «О Стратегии развития ИИ» и сопутствующие методические рекомендации — прямо указывает на необходимость контроля за решениями, принимаемыми ИИ-системами. Иными словами, ФЗ-149 и ИИ уже связаны: система, которая автономно обращается к данным, должна быть включена в контур защиты и аудита наравне с человеком-оператором.
Для ГИС и КИИ дополнительно
Где именно AI-агент создаёт новые обязательства? В трёх точках, которых нет у классического веб-приложения:
- Трансграничная передача ПДн — запрос к
api.openai.comилиapi.anthropic.comфизически переносит ПДн за пределы РФ. Это действие подлежит отдельному учёту (ст. 18.5 152-ФЗ). - Автономное решение — если агент сам решил прочитать файл с ПДн, в журнале должна быть не только запись «файл прочитан», но и причина: какая prompt-инструкция, какой tool-call, какая модель.
- Цепочка делегирования — человек одобрил план → агент вызвал MCP-сервер → MCP-сервер обратился к БД. Все три звена — отдельные события, связанные единым
trace_id.
Что обязательно логировать
«Логировать всё» — это не требование, это путь к журналу в 40 ГБ/сутки, который невозможно проверить. Приказы ФСТЭК и практика проверок Роскомнадзора выделяют конкретные классы событий. Ниже — таблица, которую мы используем как baseline при настройке compliance AI контура в FlowLink.
| Событие | Обязательные поля | Источник | Retention | Основание |
|---|---|---|---|---|
| Доступ к ПДн (чтение/запись записи) | actor, resource_id, category ПДн, decision | policy engine (OPA) | 5 лет | 152-ФЗ ст.19; ФСТЭК №21 п.6.1 |
| LLM-вызов с ПДн в контексте | model, tokens_in/out, has_pdn, provider_geo | MCP gateway / proxy | 5 лет | 152-ФЗ ст.18.5 (трансгран.) |
| Аутентификация / токен-обмен | subject, method, success, ip, device_fp | SPIFFE / IdP | 1 год | ФСТЭК №17 п.5.3 |
| Изменение прав / ролей | who, target, old_role, new_role | policy engine | 5 лет | ФСТЭК №21 п.6.2 |
| Доступ к credential vault | secret_ref, agent_id, scope, ttl | credential vault | 3 года | 152-ФЗ ст.19.1 |
| MCP tool-call (внешний) | server, tool, args_hash, result_code | MCP gateway | 1 год | ФЗ-149 ст.16 |
| Shell-команда / file-write | cmd_hash, path, syscall, sandbox | eBPF shield | 1 год | ФСТЭК №17 п.6.4 |
| Срабатывание политики (allow/deny) | rule_id, decision, reason, eval_ms | OPA / Rego | 3 года | ФСТЭК №21 п.6.2 |
| Экспорт / выгрузка данных | dest, volume, format, approver | DLP / proxy | 5 лет | 152-ФЗ ст.18.5 |
| Ошибка / отказ компонента | component, error_code, trace_id | systemd / journald | 1 год | ФСТЭК №17 п.5.5 |
| Превышение бюджета / throttle | agent, cost_usd, limit, action | budget governor | 1 год | Внутренний контроль |
| Промпт-инъекция (детект) | signature, score, blocked, source | policy engine | 3 года | ФЗ-149 ст.16; NIST AI RMF |
Каждое событие должно содержать минимальный набор сквозных полей: ts (RFC3339, UTC — с синхронизацией по NTP, иначе хронология «поплывёт»), trace_id (для связи цепочки вызовов), actor (идентификатор агента или пользователя), decision(allow/deny) и prev_hash (ссылка на предыдущую запись — основа tamper-evidence). Подробно о том, как эти события превращаются в метрики и алерты, — в статье про мониторинг активности AI-агентов; здесь же мы фокусируемся на immutable-стороне журнала.
Hash-chain журнал: реализация
Обычный лог-файл бесполезен для аудита: администратор с правом root может отредактировать или удалить любую строку, и никто не заметит. Приказы ФСТЭК требуют «целостности и доступности» записей — технически это достигается tamper-evident журналом, где каждая запись криптографически связана с предыдущей. Это и есть hash chain.
Идея проста: каждая запись Eₙ содержит хеш H(Eₙ₋₁ ‖ payloadₙ ‖ nonce). Изменить любую прошлую запись, не сломав цепочку, невозможно — нарушится хеш в следующей. Для усиления используется HMAC с секретным ключом (аутентифицированный хеш) и периодический anchoring — фиксация текущего «головного» хеша во внешнем хранилище, недоступном для агентов.
- E₀ (genesis)
- E₁ (prev_hash=H₀)
- E₂ (prev_hash=H₁)
- …
- Eₙ (anchored)
// Core хеширующего аппендера (Rust, crate: sha2 + hmac)use sha2::Sha256;use hmac::{Hmac, Mac};type HmacSha256 = Hmac<Sha256>;#[derive(serde::Serialize, serde::Deserialize, Clone)]pub struct AuditEntry { pub seq: u64, // монотонный номер, never reused pub ts: String, // RFC3339, UTC pub actor: String, // agent_id или user sub pub event: String, // "pd_access" | "llm_call" | ... pub resource: String, // canonical resource uri pub decision: String, // "allow" | "deny" pub trace_id: String, pub prev_hash: String, // this_hash предыдущей записи pub this_hash: String, // вычисляется в seal()}impl AuditEntry { /// payload под хеш: все поля, кроме this_hash, в фиксированном порядке fn signed_payload(&self) -> Vec<u8> { let mut v = self.seq.to_le_bytes().to_vec(); for f in [&self.ts, &self.actor, &self.event, &self.resource, &self.decision, &self.trace_id, &self.prev_hash] { v.extend_from_slice(f.as_bytes()); } v } pub fn seal(&mut self, chain_key: &[u8]) { let mut mac = HmacSha256::new_from_slice(chain_key).expect("hmac key"); mac.update(&self.signed_payload()); self.this_hash = hex::encode(mac.finalize().into_bytes()); }}/// Аппендер: берёт хвост цепи, ставит prev_hash, печатает this_hashpub fn append( tail_hash: &str, // this_hash последней записи (или genesis) chain_key: &[u8], // ключ из KMS, не на диске агента mut entry: AuditEntry,) -> AuditEntry { entry.prev_hash = tail_hash.to_string(); entry.seal(chain_key); entry}Несколько тонкостей, без которых журнал «не пройдёт»:
- Ключ
chain_keyхранится в KMS (Yandex KMS, HashiCorp Vault transit, AWS KMS), а не рядом с агентом. Агент только «слепит» запись; ключ ему не отдаётся. seqмонотонный и без пропусков. Пропущенный номер = красный флаг для аудитора. Контролируется отдельным счётчиком в БД с advisory-lock.- Anchoring каждые N минут. Текущий
this_hashфиксируется во внешнем хранилище (например, записью в отдельной WORM-колонке или транзакцией в публичном источнике). Если позже кто-то подменит хвост цепи, anchor перестанет совпадать. - Batch verification через Merkle tree. Для проверки целого месяца записей не нужно хешировать каждую: строится дерево, и проверяется корневой хеш против anchored-значения.
Верификатор цепи (используется на ежесуточном джобе и по запросу аудитора):
# Python-верификатор: проходит по записям, проверяет связь и HMACimport hmac, hashlib, sysCHAIN_KEY = kms_fetch("audit/chain-key") # из KMS, не из конфигаdef verify(entries, anchored_head_hash): prev = "0" * 64 # genesis for e in entries: if e["prev_hash"] != prev: raise SystemExit(f"BROKEN chain at seq={e['seq']}: prev_hash mismatch") payload = b"".join([ e["seq"].to_bytes(8, "little"), e["ts"].encode(), e["actor"].encode(), e["event"].encode(), e["resource"].encode(), e["decision"].encode(), e["trace_id"].encode(), e["prev_hash"].encode(), ]) expected = hmac.new(CHAIN_KEY, payload, hashlib.sha256).hexdigest() if not hmac.compare_digest(expected, e["this_hash"]): raise SystemExit(f"TAMPERED entry seq={e['seq']}: HMAC mismatch") prev = e["this_hash"] if prev != anchored_head_hash: raise SystemExit("HEAD mismatch vs anchor — tail was rewritten") print(f"OK: {len(entries)} entries, chain intact")if __name__ == "__main__": verify(load_entries(sys.argv[1]), load_anchor("today"))Если верификатор падает на TAMPERED entry — запись подделана; наHEAD mismatch — подменён хвост. Оба случая — автоматический алерт и инцидент в рамках реакции на события ИБ.
Хранение и retention
Сроки хранения диктуются нормативом: для ИСПДн уровня УЗ-1/УЗ-2 — не менее 1 года (приказ ФСТЭК №21), для журналов доступа к ПДн на практике мы закладываем 5 лет с запасом — срок исковой давности по 152-ФЗ. Хранилище должно быть только для добавления(WORM — write once, read many) и находиться географически в РФ, потому что вывоз ПДн за пределы страны без отдельного основания (ст. 18.5) — самостоятельное нарушение.
- Hot (PostgreSQL, 90д)
- Warm (ClickHouse, 1г)
- Cold (S3 WORM, 5л)
Типичный hot/warm/cold пайплайн (конфиг FlowLink):
# /etc/flowlink/audit-retention.yamlretention: hot: # быстрый поиск, до 90 дней backend: postgresql table: audit_events_hot partition: weekly # авто-truncate партиций duration: 90d encryption: aes-256-gcm # at-rest, ключи в KMS warm: # аналитика, 90д–1год backend: clickhouse duration: 1y compression: lz4 cold: # архив для проверок, 1–5 лет backend: s3-compatible bucket: flowlink-audit-cold worm: # S3 Object Lock, compliance mode mode: COMPLIANCE retain_until: "now + 5y" encryption: aws:kms # серверсайд, ключ в ru-central1 geo: region: ru-central1 # запрет replication за пределы РФ cross_region_replication: falseintegrity: chain_key_kms_ref: "kms/audit/chain-key" anchor: interval: 5m # фиксация head-hash во WORM-колонке target: audit_anchors # отдельная COMPLIANCE-locked таблица verify_job: schedule: "0 3 * * *" # ежесуточно в 03:00 alert_on_fail: pagerdutyГеографическая привязка и запрет на вынос ПДн за пределы РФ контролируются не «доверием к конфигу», а политикой, которая проверяется на каждом запросе. В FlowLink это Rego-правило в OPA, которое блокирует любую попытку репликации или экспорта audit-данных в неразрешённый регион:
# audit_geo_fence.rego — запрещает запись ПДн-логов вне РФpackage flowlink.auditimport rego.v1default allow := false# Разрешённые локации хранения журналов с ПДнallowed_regions := {"ru-central1", "ru-central1-a", "ru-central1-b"}allow if { input.action == "audit_write" input.store.region in allowed_regions not input.store.cross_region_replication input.store.encryption != null}# Жёсткий запрет: экспорт ПДн-события за границуdeny[msg] if { input.action == "audit_export" input.dest.country != "RU" input.has_pdn == true msg := sprintf( "BLOCKED: ПДн-аудит нельзя вывозить в %v (ст. 18.5 152-ФЗ)", [input.dest.country], )}# Запрет на удаление записи младше retentiondeny[msg] if { input.action == "audit_delete" input.entry_age_days < 1825 msg := sprintf( "BLOCKED: запись младше 5 лет (age=%v дн.)", [input.entry_age_days], )}Заметьте: правило не «рекомендует», а возвращает allow = false по умолчанию и явно deny — то есть MCP-gateway и policy engine физически не пропустят операцию. Это и есть compliance as code: вместо регламента на бумаге — исполняемая политика, чьи решения сами попадают в тот же hash-chain журнал.
Сами секреты, к которым обращаются агенты, — отдельная зона риска: доступ к credential vault тоже входит в обязательный журнал (строка 5 таблицы выше). Как сделать так, чтобы секреты не утекли ещё до того, как попадут в лог, — разбиралось в материале пропредотвращение утечек учётных данных через MCP.
Чек-лист соответствия
Сведём всё в пошаговый список. Если по каждому пункту есть «да» с артефактом (конфиг, запись в журнале, KMS-ключ) — контур готов к проверке Роскомнадзора или внутреннему compliance-аудиту.
Чек-лист соответствия AI-аудита 152-ФЗ
15 пунктов для прохождения аудита Роскомнадзора или внутреннего compliance-аудита.
Определить оператора ПДн и УЗ
Определён оператор ПДн и уровень защищённости (УЗ-1…УЗ-4) для каждой ИСПДн, в которую ходит AI-агент.
Инвентаризировать потоки ПДн
Инвентаризированы потоки ПДн — известно, какие файлы/таблицы содержат ПДн и какие агенты имеют к ним доступ.
Policy engine для каждого запроса
Каждый запрос к ПДн проходит через policy engine (OPA/Rego), решение (
allow/deny) фиксируется в журнале.Hash-chain журнал с HMAC-SHA256
Журнал ведётся в формате hash-chain с HMAC-SHA256, ключ в KMS, монотонный
seqбез пропусков.Anchoring головного хеша
Настроен anchoring головного хеша каждые ≤5 минут во внешнее WORM-хранилище.
Ежесуточная верификация цепи
Ежесуточная верификация цепи автоматизирована, падение = инцидент (PagerDuty).
Все 12 классов событий
Каждое из 12 классов событий из таблицы выше действительно пишется и проверено тестом.
Трансграничные LLM-вызовы
Трансграничные LLM-вызовы с ПДн в контексте помечены и учтены отдельно (ст. 18.5 152-ФЗ).
Retention hot/warm/cold
Retention: hot 90д / warm 1г / cold 5л, холодный слой в S3 Object Lock (compliance mode).
Хранилище в ru-central1
Хранилище журналов в регионе ru-central1, cross-region replication выключена, шифрование at-rest включено.
Geo-fencing политика на Rego
Geo-fencing-политика (Rego) блокирует экспорт ПДн-аудита за пределы РФ и удаление записей младше retention.
NTP-синхронизация
Время синхронизировано по NTP, таймстампы в UTC RFC3339 — иначе хронология не восстановима.
Права на запись в журнал
Права на запись в журнал есть только у сервисной учётки аппендера, ключ цепи агенту недоступен.
Доступ к журналу для чтения
Доступ к журналу для чтения — только через отдельную роль аудитора с two-person rule.
Процедура реакции на tamper
Процедура реакции на срабатывание верификатора (tamper/break) описана и отрепетирована.
Hash-chain журнал: стоит ли внедрять?
Плюсы
- Tamper-evidence: подмена любой записи обнаруживается автоматически через разрыв HMAC-цепочки
- Anchoring во внешнее WORM-хранилище — двойная защита от подмены хвоста цепи
- Retention hot/warm/cold оптимизирует стоимость при соблюдении нормативных сроков (5 лет)
- Compliance as code: Rego-политики исполняемы, аудируемы и сами попадают в hash-chain
- Merkle tree verification позволяет проверять месяцы записей за миллисекунды
Минусы
- Высокая сложность: KMS для chain_key, WORM-S3, Rego-политики, eBPF-shield — каждая подсистема требует экспертизы
- Anchoring требует дополнительной инфраструктуры (отдельная WORM-таблица, cron-джобы)
- Накладные расходы: append-only журнал с HMAC и монотонным seq медленнее обычного логирования
- Geo-fencing (ru-central1) ограничивает выбор cloud-провайдеров и повышает стоимость хранилища
Compliance для AI-агентов — это не «дополнительная галочка», а продолжение тех же требований 152-ФЗ и ФЗ-149, перенесённое на новую модель исполнения. Агент, который сам принимает решения и сам обращается к данным, требует более строгого, а не менее строгого журналирования. Hash-chain журнал с anchoring, WORM-retention и geo-fencing — это тот минимум, при котором фраза «у нас ведётся аудит логирование» соответствует не только внутреннему убеждению, но и нормативу.
Часто задаваемые вопросы
Какие нормативные акты регулируют аудит-логирование AI-агентов в РФ?
Три опоры: 152-ФЗ («О персональных данных») — ст. 18.5 (трансграничная передача), ст. 19 (обработка ПДн); ФЗ-149 («Об информации, ИТ и о защите информации») — ст. 16 (защита информации); приказы ФСТЭК №17/№21 — требования к регистрации событий безопасности и составу технических мер. AI-агенты подпадают под все три, потому что обрабатывают те же данные, что и классические ИСПДн.
Какие 12 классов событий обязательно логировать?
Доступ к ПДн, LLM-вызов с ПДн, аутентификация/токен-обмен, изменение прав/ролей, доступ к credential vault, MCP tool-call, shell-команда/file-write, срабатывание политики (allow/deny), экспорт/выгрузка данных, ошибка/отказ компонента, превышение бюджета/throttle, промпт-инъекция (детект). Каждый класс с обязательными полями, источником сбора и сроком retention — см. таблицу в статье.
Что такое hash-chain журнал и зачем он нужен для compliance?
Hash-chain журнал — это tamper-evident журнал, где каждая запись содержит HMAC-хеш предыдущей. Подменить любую прошлую запись, не сломав цепочку, невозможно. Ключchain_key хранится в KMS, seq монотонный без пропусков, anchoring фиксирует головной хеш каждые 5 минут. Это соответствует требованиям ФСТЭК к «целостности и доступности» записей и проходит аудит Роскомнадзора.
Какие сроки хранения журналов соответствуют 152-ФЗ?
Для ИСПДн уровня УЗ-1/УЗ-2 — не менее 1 года (приказ ФСТЭК №21). На практике закладываем 5 лет с запасом (срок исковой давности по 152-ФЗ). Хранилище: hot (PostgreSQL, 90 дней), warm (ClickHouse, 1 год), cold (S3 Object Lock compliance mode, 5 лет). Холодный слой находится географически в РФ (ru-central1).
Как geo-fencing защищает от трансграничной утечки ПДн?
Rego-политика в OPA проверяет каждый запрос к audit-хранилищу: allow только если region in allowed_regions и cross_region_replication == false. Запрет на экспорт ПДн-аудита за пределы РФ и на удаление записей младше retention — это не рекомендация, а исполняемая политика, физически блокирующая операцию.
Что такое anchoring в hash-chain журнале?
Anchoring — периодическая фиксация текущего «головного» хеша (последней записи цепи) во внешнем хранилище, недоступном для агента (WORM-таблица). Интервал — ≤5 минут. Если кто-то подменит хвост цепи, anchored-значение перестанет совпадать — верификатор обнаружит HEAD mismatch и поднимет алерт. Batch verification через Merkle tree проверяет месяцы записей за миллисекунды.
Готовы защитить свои AI-агенты?
Начните с бесплатного аудита безопасности ваших AI-инструментов.
Получить бесплатный аудит