Документация

К списку статей
17. Целевая топология сервиса идентификации (Эпик F, F1)

Тип: проектный документ границы (аналог docs/admin/16-integration-boundary.md, но граница здесь — аттестационная, а не интеграционная). Основание: docs/23-enclave-tokenization-gap.md (дефициты D8, D9), docs/22 Эпик F. Цель документа: зафиксировать целевую архитектуру выноса функций токенизации и схемы vault в отдельный сервис идентификации, чтобы основной backend оперировал только хеш-суррогатами. Это инженерная задача минимизации области аттестации ФСТЭК по 152-ФЗ. Статус: проект топологии (до реализации F3). Код в этом шаге не меняется.


0. Зачем (одним абзацем)

Сейчас функция токенизации (anonymize) и схема vault живут в одном процессе и одной БД с основным backend. По строгому чтению 152-ФЗ обработка идентификаторов в оперативной памяти узла включает этот узел в область аттестации → в область попадает весь backend + БД. Цель F — сжать область до компактного сервиса идентификации (1–2 ВМ), оставив портал, аналитику, дашборды и фронт вне области. Архитектура это уже допускает без пересборки: токенизация — один чокпойнт, схема sam уже хеш-онли, vault — уже отдельная схема со своей RLS-политикой (docs/23 §4).


1. Граница ответственности «портал / сервис идентификации»
ЗонаЧто внутриВидит сырьё?В области аттестации?
Сервис идентификации (новый)anonymize + схема vault + 5 кромочных точек приёмада (единственный носитель)да — и только он
Основной backend (портал)схема sam, аналитика, эффективность, заявки/ЖЦ, отчёт (A), экспорт (C)нет (только хеши)нет (цель F3)
Фронт / Nextконтракт, дашборды, печатьнетнет
Инфраструктура (IaaS)железо/гипервизор/ЦОДнетнаследуемый аттестат (D12)

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

коллектор/клиент ──сырой tabel_no──► [Сервис идентификации: anonymize + vault] ──hash──► backend (sam)
DPO-консоль ──────── запрос раскрытия ───────────────────────────────────────► [Сервис идентификации]

2. Целевые компоненты сервиса идентификации
СвойствоСейчас (логический изолят)Цель F3 (физический сервис)
Процесстот же FastAPI, что и порталотдельный FastAPI-процесс/контейнер
Роль БДlicenziar_app (общая)выделенная роль vault_app (только схема vault)
Портобщий с APIотдельный внутренний порт, наружу не публикуется
Сетевой сегментсеть backendвыделенный сегмент (VLAN/VPC), доступ только от портала и DPO-канала
Схема БДvault в общей БДvault в отдельной БД/инстансе (предпочтительно) либо отдельная роль с FORCE RLS
Контрактвнутренние вызовы anonymize()внутренний API: tokenize(tenant, id) → hash, resolve(tenant, hash, basis) → identity

Неизменно (гардрейлы): токенизация — ГОСТ Р 34.11-2012 (Стрибог-256), соль из env, не в БД и не в логах; vault под RLS FORCE + политика vault_dpo_only; раскрытие пишет аудит ФЗ-152 всегда; ноль внешних обращений; ноль копилефта.


3. Карта 5 кромочных точек к выносу (что переезжает в сервис)

Точные адреса в коде (подтверждено чтением, docs/23 §3):

#ТочкаФайл:строкаЧто переедет
1Приём телеметрииingest_routes.py:65вызов anonymize → запрос tokenize к сервису
2Создание заявкиworkflow.py:42то же
3Приём кадровых событийworkflow.py:274то же
4Раскрытие связи (DPO)workflow.py:390resolve идёт прямо в сервис, минуя портал
5Загрузка идентификацийinit_db.py:213переезжает в инициализацию сервиса

После переезда основной backend получает на вход уже хеши; вызовов anonymize и обращений к vault.* в коде портала не остаётся.


4. Контракт сервиса идентификации (целевой)

Внутренний API (вызывается только из доверенного сегмента, наружу не публикуется):

МетодВходВыходКто вызывает
POST /tokenize{tenant, tabel_no}{user_id_hash}backend на кромке приёма (точки 1–3)
POST /tokenize/batch{tenant, [tabel_no]}{[user_id_hash]}пакетный приём телеметрии/HR
POST /resolve{tenant, user_id_hash, basis, principal}{tabel_no, full_name} + запись аудитаDPO-консоль напрямую

Свойства контракта:

  • tokenize детерминирован для пары (соль, tenant, tabel_no) — те же суррогаты, что сейчас

(инвариант artek 0.6585/6 не двигается).

  • resolve доступен только роли dpo, всегда пишет запись VAULT_RESOLVE в аудит ФЗ-152.
  • Контракт двусторонне совместим с текущим anonymize() → переезд не меняет значения хешей.

5. Матрица разделения ответственности с IaaS (уточнение D12)
СлойЧья ответственностьАттестация
ЦОД, железо, гипервизор, сеть провайдераIaaS-провайдераттестат провайдера (наследуется)
Гостевая ОС сервиса идентификациинашаСЗИ-от-НСД ставим и сопровождаем мы
PostgreSQL сервиса + прикладной коднашааттестуется наш прикладной контур
Сегментация сети контура (VLAN/VPC)совместнофиксируется в модели угроз (docs/24)

При проверке нужна подписанная матрица разделения ответственности (этот раздел — её черновик).


6. Что даёт сжатие области (экономика)
  • В области аттестации остаётся сервис идентификации (1–2 ВМ) вместо «портал + БД +

аналитика + фронт».

  • Единый доверенный сегмент (портал и сервис в одном контуре одного ЦОД) делает требование

канального шифрования между ними неактуальным — это обосновывается в модели угроз (docs/24), а не закрывается тяжёлой крипто-инфраструктурой.

  • Аналитика, дашборды, отчёт (A), экспорт (C), весь контракт фронта — не трогаются.

7. Чек-лист перехода к F3 (реализация)
  1. Завести роль БД vault_app с доступом только к схеме vault (FORCE RLS сохраняется).
  2. Поднять сервис идентификации (отдельный контейнер, внутренний порт, сегмент).
  3. Реализовать контракт tokenize/resolve (§4) поверх существующего anonymize и vault.
  4. Перенаправить 5 кромочных точек (§3) на вызовы сервиса; убрать anonymize/vault.* из портала.
  5. Включить контракт-гейт F2 «backend принимает/отдаёт только хеши» (следующий шаг).
  6. Прогнать: инвариант artek 0.6585/6 цел, Static==Http, все тесты зелёные.

8. Достигнутое состояние (F1→F4-db)
  • F1/F2 — топология и контракт-гейты «портал отдаёт/принимает только хеши» (готово).
  • F3a — сервис идентификации поднят аддитивно (роль vault_app, контракт tokenize/identity/

resolve, golden-vector). Миграция 011.

  • F3b — полный cutover: портал-api выведен из ИСПДн (принимает только хеши, resolve в

Сейфе, migration 012 отзывает у licenziar_app доступ к vault, api без ANON_SALT).

  • F3c — контур аккредитации сжат до Сейф-образа. Весь код, касающийся сырых ПДн

(anonymize, коллекторы, фикстуры, сидинг), физически вынесен в подпакет app/enclave/ + seed_data.py/init_db.py. Docker-таргет `portal` (api/web) ФИЗИЧЕСКИ удаляет эти модули из образа (rm -rf app/enclave app/seed_data.py app/init_db.py app/make_fixture.py); таргет `enclave` (dbinit/collector) их содержит. Доказательно: в portal-образе grep -r anonymize app/ --include='*.py' → нет кода (только доккомментарии), нет .pyc удалённых модулей; гейт test_api_import_graph_excludes_enclave_and_seed держит границу.

  • F4-db — отдельный инстанс БД Сейфа (готово, проверено live). Носитель ПДн и журнал

раскрытий вынесены в отдельный Postgres `vaultdb` (свой том, сегмент vaultnet): таблица vault.user_identity (FK на sam.tenants снят), собственный журнал vault.disclosure_log, дублированные RLS-функции vault.current_*, роль vault_app заводит vault-init. В БД портала схемы `vault` НЕТ вовсе (миграция 001 очищена, 011/012 — тостоуны). Сейф пишет раскрытия в свой журнал (ноль egress: 0 строк VAULT_RESOLVE в sam.fz152_audit); DPO смотрит историю через GET /disclosures. Схема: vault-service/migrations/001_vault_schema.sql.

Контур ИСПДн (рантайм, после F4-db): vault-service (носитель связки) + vaultdb (инстанс ПДн) + collector/dbinit (enclave-образ, токенизируют/сидят хеши в sam). Портал api/web/nginx и его БД dbвне ИСПДн (нет кода токенизации, нет ANON_SALT, нет схемы vault ни в коде, ни в БД).

Остаётся инфра-шагом (не код): разместить инстанс Сейфа на отдельной ВМ/аттестованном IaaS-152, настроить бэкап-контур. Это финализирует независимо аттестуемый узел.

Связанные документы: docs/23-enclave-tokenization-gap.md (карта 5 точек, дефициты), docs/24-private-threat-model-draft.md (модель угроз, обоснование единого контура), docs/admin/16-integration-boundary.md (аналог для интеграционной границы), docs/admin/01-not-skzi-crypto.md (позиционирование «не СКЗИ»), docs/admin/02-pii-fz152-vault.md (текущая работа vault и аудита).