Глава 19. Согласованность модели
19.1. Что означает согласованность
Пусть существуют:
F
— исходные факты,
R
— правила,
и:
P
— производная проекция.
Тогда согласованной можно считать модель, в которой:
P = F(Facts, Rules)
для определённого состояния исходных данных.
Иными словами, проекция должна соответствовать тем фактам и правилам, на которых она должна быть построена.
19.2. Источник истины остаётся исходным
Если:
User → Group
является исходным фактом, а:
effective_user_group
его производным представлением, то именно исходная связь является источником истины.
Если удалить запись из проекции вручную, это не изменяет предметную модель.
При следующем перестроении запись снова появится, если исходный факт всё ещё существует.
Поэтому:
Source facts = source of truth
Projection = derived state
19.3. Eventual consistency
В распределённых системах производная модель может обновляться с задержкой.
Это означает:
t0: source changed
t1: projection still old
t2: projection updated
Такой режим часто называют eventual consistency (согласованность в конечном итоге).
Сам по себе он не определяет, что должна делать система между t0 и t2.
Это архитектурное решение.
19.4. Почему для безопасности задержка особенно важна
Если проекция используется для авторизации, устаревшее состояние может привести к разным последствиям.
Например:
Grant
произошёл, но право ещё не появилось в проекции.
Тогда пользователь временно не получает доступ.
В другом случае:
Revoke
произошёл, но старое разрешение ещё осталось.
Тогда пользователь временно сохраняет доступ.
Эти ситуации не обязательно имеют одинаковую приемлемость для конкретной системы.
Поэтому семантика задержки должна быть частью архитектуры.
19.5. Граница состояния запроса
Важно определить, какое состояние считается актуальным для одного запроса.
Возможны разные модели:
read current projection
или:
read projection at version N
или:
wait until projection reaches required version
Последний вариант особенно полезен, когда действие должно быть разрешено только после применения конкретного изменения.
Таким образом, согласованность — это не только вопрос обновления таблицы.
Это вопрос того, какое состояние модели имеет право увидеть запрос.
19.6. Несколько проекций должны согласовываться по смыслу
Рассмотрим:
effective_user_permission
object_scope
Если одно представление уже обновлено, а второе ещё нет, результат может быть промежуточным.
Например:
new permission
+
old object scope
или наоборот.
Поэтому для связанных проекций необходимо определить границу согласованности.
Она может быть транзакционной, версионной или иной.
Но она должна быть явной.
19.7. Полное перестроение как часть нормальной архитектуры
Проекция должна быть восстанавливаемой из:
Source facts + Rules
Это означает, что полное перестроение не является аварийным костылём.
Оно необходимо как минимум для:
-
восстановления после сбоя;
-
проверки корректности;
-
изменения правил;
-
миграции;
-
устранения накопленного расхождения.
Если проекцию невозможно восстановить, она слишком сильно зависит от своей собственной истории изменений.
19.8. Изменение правил также изменяет производные данные
Не только факты могут измениться.
Могут измениться сами правила.
Например:
Role R → READ
превращается в:
Role R → READ + UPDATE
Исходные отношения пользователей не изменились.
Но эффективные разрешения изменились.
Следовательно:
Projection = F(Source facts, Rules)
а не только:
Projection = F(Source facts)
При изменении правил может потребоваться перестроение соответствующей части модели.
19.9. Согласованность должна быть проверяема
Нельзя ограничиться утверждением:
Проекция обычно обновляется.
Нужно иметь возможность проверить:
Source facts
↓
Rebuild
↓
Expected projection
и сравнить результат с текущим состоянием.
Это превращает согласованность из предположения в проверяемое свойство.
19.10. Guardian как пример
В Guardian исходные отношения и публикации являются источниками изменений.
Из них строятся производные представления:
KUserGroupLink
↓
effective_user_group
↓
Scope Barrier
↓
effective_user_permission
и:
KPublish / ownership / other security facts
↓
object_scope
Проверка объекта затем использует подготовленные:
effective_user_permission
object_scope
Это позволяет отделить построение модели от проверки запроса.
19.11. Согласованность не означает отсутствие задержки
Это важное различие.
Можно иметь модель с задержкой обновления и при этом иметь строго определённую согласованность:
Projection version N
может быть согласована с:
Source version N
хотя исходная модель уже находится на версии N+1.
Поэтому вопрос:
Согласована ли проекция?
не равен вопросу:
Самая ли это последняя версия?
19.12. Безопасность требует определённой деградации
Если проекция недоступна, система должна знать, что делать.
Недопустимо случайно выбирать поведение:
projection unavailable → ALLOW
или:
projection unavailable → DENY
только потому, что это оказалось самым простым техническим вариантом.
Это должно быть архитектурным решением.
Особенно важно не создавать параллельный «аварийный» механизм авторизации, который со временем станет второй моделью безопасности.
19.13. Главный вывод
Согласованность модели безопасности — это соответствие производных фактов исходным фактам и правилам.
Полная цепочка выглядит так:
Source facts
+
Security rules
↓
Security projections
↓
Effective permissions
↓
Access decision
Если исходный факт изменился, должна измениться и зависимая производная модель.
Если изменилось правило, производная модель также может потребовать перестроения.
Поэтому проекции безопасности должны быть:
-
производными;
-
объяснимыми;
-
восстанавливаемыми;
-
проверяемыми;
-
согласованными с определённой версией исходной модели.
Именно это позволяет перейти от простой проверки прав к устойчивой архитектуре безопасности.