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

К списку статей
23. Ротация ANON_SALT: согласованная реанонимизация портала и Сейфа

Аудитория: суперадминистратор, DPO, интегратор. Закрывает вопрос: «как сменить соль обезличивания, не разорвав связку обезличенный ID ↔ сотрудник?». Связано: 02 — ПДн и Сейф, 17 — Топология Сейфа.


Почему это операция, а не «поменять переменную»

Обезличивание построено так: user_id = HMAC(ANON_SALT → ключ_арендатора, табельный) (ГОСТ «Стрибог», ключ на арендатора). Смена `ANON_SALT` меняет ВСЕ `user_id`.

Один и тот же user_id хранится в двух местах, и они обязаны совпадать:

КонтурГде user_id
Портал (db)sam.masked_users, sam.activity_facts, sam.jml_events, sam.provisioning_jobs, sam.software_requests.requester_user_id, sam.user_entitlements
Сейф (vaultdb)vault.user_identity (ключ), vault.disclosure_log

Если просто сменить соль, новые user_id перестанут совпадать со старыми в БД → раскрытие в Сейфе даст 404, факты активности «осиротеют», метрики поедут. Поэтому ротация — это контролируемая операция обслуживания с одновременной реанонимизацией обоих контуров.

Перерасчёт может сделать только контур Сейфа: у него есть и соль, и табельный (tabel_no). У портала табельных нет (так и задумано), поэтому пересчитать user_id он не может — он лишь применяет готовую карту старый_user_id → новый_user_id.
Инструмент: vault-service/app/rotate_salt.py (контур Сейфа) — строит карту old→new из tabel_no под NEW_ANON_SALT и применяет её одним UPDATE-statement к Сейфу и порталу. Без --apply — СУХОЙ ПРОГОН (печатает план, ничего не меняет). Ниже — регламент с этим инструментом.

Когда менять
  • Подозрение на компрометацию ANON_SALT.
  • Регламентная смена ключевого материала по политике ИБ заказчика.

Процедура (по шагам, с downtime)

0. Резервные копии обеих БД. db и vaultdb — раздельно (deploy/backup.sh и deploy/backup-vault.sh). Без бэкапа не начинать.

1. Остановить запись. Остановить collector (прекратить приём фактов) и перевести портал в режим обслуживания/только чтение, чтобы user_id не менялись во время миграции.

2. Сухой прогон — построить и проверить карту, ничего не меняя (в контуре Сейфа):

docker compose -f docker-compose.lic.yml --env-file .env.lic \
  exec -T -e NEW_ANON_SALT='<новая-соль>' \
  -e ADMIN_DATABASE_URL="postgresql://postgres:<pw>@db:5432/licenziar" \
  vault python -m app.rotate_salt          # печатает: идентичностей / к пересчёту

3. Боевой прогон — применить карту одновременно к порталу и Сейфу (флаг --apply):

docker compose ... exec -T -e NEW_ANON_SALT='<новая-соль>' \
  -e ADMIN_DATABASE_URL="postgresql://postgres:<pw>@db:5432/licenziar" \
  vault python -m app.rotate_salt --apply  # печатает число затронутых строк по таблицам

Инструмент обновит все 6 столбцов портала (sam.masked_users/activity_facts/jml_events/ provisioning_jobs/software_requests.requester_user_id/user_entitlements) и Сейф (vault.user_identity, vault.disclosure_log) — каждый одним UPDATE-statement через временную карту (уникальные ключи не нарушаются: новые id уникальны, старое/новое множества не пересекаются).

4. Сменить `ANON_SALT` в окружении воркеров контура (collector, dbinit, vault) на то же <новая-соль> и перезапустить их. Хранить только в env/секрет-менеджере (не в БД/логах/git).

5. Снять обслуживание, запустить сбор, проверить:

  • раскрытие в Сейфе по новому user_id возвращает корректные ФИО/табельный;
  • метрики/инвариант целы, «осиротевших» фактов нет (нет activity_facts без masked_users);
  • новый сбор пишет уже с новой солью (совпадает с обновлёнными хешами).

Целостность: на что смотреть, чтобы не разрушить данные
  • user_id входит в уникальный ключ activity_facts (tenant, sys, user, date) и в PK

masked_users — при массовом UPDATE старого на новый возможны конфликты, если множества старых и новых значений пересекаются. Применять через таблицу-карту (UPDATE … FROM map) и при риске пересечения — двухфазно (через временный префикс), чтобы не нарушить уникальность.

  • Каждый UPDATE — в транзакции; сверять число затронутых строк с числом идентичностей.
  • Любая ошибка на шагах 3–4 → rollback обоих контуров и восстановление из бэкапа (шаг 0).
  • Порядок важен: сначала карта (Сейф), затем портал, затем Сейф, в конце — смена env-соли.

Чего НЕ делать
  • Не менять ANON_SALT «на горячую» без шагов 2–4 — это тихо разорвёт связку и раскрытие

перестанет работать.

  • Не выносить tabel_no/соль за контур Сейфа ради ротации — реанонимизация выполняется внутри

Сейф-контура, наружу уходит только карта old→new (это не ПДн).


Связанные: 02 — ПДн и Сейф · 17 — Топология Сейфа · 08 — Эксплуатация и бэкап.