Runbook: Visibility policy cache poisoning / неконсистентность

Severity (default): P1 (риск раскрытия / сокрытия данных). Owner: visibility / security team. Связанные алерты:

  • visibility_cache_miss_rate > 0.5 за 5 мин (нарушение инвалидации).
  • visibility_policy_compile_errors_total > 0.
  • Жалоба клиента / оператора: “видны данные, которых не должно быть” / “пропали данные, которых не должно быть”.

Симптом

  • Клиент видит товары / цены, которые должна скрывать deny-policy.
  • Клиент НЕ видит данные, которые должны быть видны (после изменения policy не подхватилось).
  • Симулятор в admin UI и реальный ответ расходятся.

Диагностика

ВНИМАНИЕ: пока не подтвердим scope — действуем как при потенциальном инциденте безопасности. Не “просто перезагружаем кэш и забываем”.

# 1. Какие policies сейчас активны для затронутого subject?
kubectl -n tracium exec deploy/admin-api -- \
  curl -X POST localhost:8080/v1/admin/visibility-policies/simulate \
  -H 'X-Admin-Token: <token>' \
  -d '{"subject":{"customer_id":"<CUSTOMER>","role":"<ROLE>"},"target_kind":"<KIND>","candidates":[<sample>]}'
# 2. Состояние кэша по этому subject
kubectl -n tracium exec deploy/redis -- \
  redis-cli GET "visibility:compiled:<SUBJECT_HASH>"
kubectl -n tracium exec deploy/redis -- \
  redis-cli TTL "visibility:compiled:<SUBJECT_HASH>"
-- 3. История изменений policies для этого subject
SELECT id, version, occurred_at, event_type, event_data->'subject' AS subject
FROM event_store
WHERE aggregate_type='data_visibility_policy'
  AND occurred_at > now() - interval '24h'
ORDER BY occurred_at DESC;
# 4. Ошибки компиляции
kubectl -n tracium logs deploy/visibility --since=1h | grep -E "compile|error"

Возможные причины:

  • A: Изменение policy не инвалидировало кэш (баг в инвалидации).
  • B: Ошибка компиляции policy — fallback к default allow сработал на ошибочной policy, поднимая риск утечки данных.
  • C: Race в multi-replica visibility (одна реплика с новой policy, другая со старой).
  • D: Поломанная схема policies (после миграции).
  • E: Намеренное вмешательство в БД мимо API (audit trail должен показать).

Смягчение

Шаг 0 — пауза (ВСЕГДА перед расследованием при подозрении на data leak)

# Глобально переключить fallback effect на deny — стоп раскрытия. ВЛИЯЕТ НА ВСЕХ КЛИЕНТОВ.
# Делать только если подтверждён leak и blast radius серьёзный.
kubectl -n tracium set env deploy/visibility VISIBILITY_DEFAULT_EFFECT=deny
kubectl -n tracium rollout restart deploy/visibility

После этого — клиенты массово увидят пустые ответы по неуказанным policies. Снимать только после fix.

A: Инвалидация кэша

# Сбросить кэш по конкретному subject
kubectl -n tracium exec deploy/redis -- \
  redis-cli DEL "visibility:compiled:<SUBJECT_HASH>"
 
# Или сбросить всё (с осторожностью — поднимет latency пока идёт recompile)
kubectl -n tracium exec deploy/redis -- redis-cli --scan --pattern 'visibility:compiled:*' \
  | xargs -n 100 kubectl -n tracium exec deploy/redis -- redis-cli DEL

B: Ошибка компиляции

Найти конкретную policy:

kubectl -n tracium logs deploy/visibility --since=2h | grep -E "compile" | tail -20

Откатить policy:

kubectl -n tracium exec deploy/admin-api -- \
  curl -X POST localhost:8080/v1/admin/visibility-policies/<POLICY_ID>/revert \
  -d '{"to_version":<N>,"reason":"compile error in v<N+1>"}'

C: Race

Принудительный перезапуск всех реплик visibility (последовательно):

kubectl -n tracium rollout restart deploy/visibility

E: Вмешательство

Эскалация в #security немедленно. Аудит:

SELECT * FROM event_store
WHERE aggregate_type='data_visibility_policy'
  AND metadata->'actor'->>'type' NOT IN ('user','system')
ORDER BY occurred_at DESC LIMIT 50;

Устранение root cause

  • A: тест на инвалидацию (event-driven invalidation в consumer’е visibility).
  • B: pre-publish dry-run компиляции policy в admin-api.
  • C: версия snapshot в Redis-ключе (ключ кэша включает версию policy).
  • D: тесты миграций схем.
  • E: ограничение прямого DB access (через bastion + аудит).

Пост-инцидент

При подтверждённой утечке данных:

  1. Аудит, кто видел что: policy_evaluation_audit + ответы через correlation_id.
  2. Уведомление затронутых клиентов (в зависимости от масштаба утечки).
  3. Запись инцидента в security log (отдельный регистр).
  4. Post-mortem.

Эскалация

  • Любое подозрение на утечку данных → #security немедленно.
  • 30 мин без mitigation → on-call lead.

Связано

  • ADR-0012 (data visibility policy).
  • 10-business/contexts/visibility.md
  • 30-services/visibility/README.md