← Все статьи
ИНЖЕНЕРНЫЙ БЛОГ / АРХИТЕКТУРА · 3 МИН ЧТЕНИЯ

Realm — это граница, а не просто поле в таблице

Область арендатора в identity-системе должна влиять на все операции: от поиска пользователя до вычисления ролей.

Когда приложение получает несколько организаций или изолированных окружений, появляется соблазн решить задачу одним столбцом realm_id. Это начало модели, но ещё не изоляция.

Почему ключа недостаточно

Предположим, что таблица пользователей содержит уникальные UUID и идентификатор realm. Если API получает UUID пользователя и выбирает его без ограничения по realm, он может вернуть объект из соседнего контура. Даже если внешний UI показывает только «своих», клиент способен отправить другой идентификатор напрямую.

Изоляция — свойство всего маршрута запроса: HTTP-обработчика, сервисного слоя, SQL-фильтра, кэша и событий. Каждая часть должна сохранять контекст арендатора.

Где граница чаще всего теряется

  • Поиск по ID. UUID трудно угадать, но он не заменяет авторизацию.
  • Связанные сущности. При назначении роли пользователю нужно проверить realm обеих записей.
  • Кэш. Ключ и область инвалидирования не должны смешивать разные домены полномочий.
  • Административные операции. Передача realm из параметра запроса ещё не означает права управлять этим realm.

Практический тест

Создайте realm A и realm B, пользователей и роли в каждом. Затем попытайтесь от имени оператора A прочитать или изменить сущность B через каждый административный endpoint. Недостаточно проверить только ответы на чтение: операции назначения и удаления связей столь же важны.

«Граница доверия должна существовать в коде, а не только в навигации интерфейса.»

Как это связано с RustCloak

В проекте роль realm прослеживается в слое RBAC и административных операциях. Для уверенности нужны интеграционные тесты, которые доказывают невозможность межарендных операций после любых изменений.

Отдельно важно проверять негативные сценарии и поведение после инвалидирования кэша. Доступ, который был отозван, не должен оставаться доступным дольше, чем допускает выбранная модель консистентности.

Безопасный запрос к данным

Вместо поиска пользователя только по ID используйте одновременно ID субъекта и realm, который был установлен и проверен серверной частью. Это особенно важно для административных mutations, где участвующие сущности могут быть переданы разными аргументами.

SQL · упрощённый принцип
-- Концептуальный пример, не SQL проекта
SELECT id, email
FROM users
WHERE id = $1 AND realm_id = $2;

Однако даже такой фильтр не заменяет проверку, вправе ли вызывающий оператор работать в указанном realm. Иными словами: фильтрация данных и решение об авторизации — две отдельные задачи, и обе обязательны.

Проверяйте операции в обе стороны

Частая ошибка — тестировать только попытку читать пользователя другого realm. Изменяющие методы требуют отдельной матрицы. Например: пользователь из A, роль из B; пользователь из A, группа из B; удаление назначения из B через endpoint realm A; попытка назначить составную роль, включающую запрещённую роль.

Негативные сценарии полезно запускать от обычного администратора realm, от глобального оператора и от пользователя без административных прав. Статус ответа должен соответствовать договорённой политике ошибок и не раскрывать чувствительную информацию из соседнего realm.

События тоже содержат контекст

Запись в журнале административных операций должна позволять понять, какой realm был затронут, кем и какой результат получен. Но аудит не должен превращаться в хранилище секретов, JWT или персональных данных сверх потребности расследования.

Критерий завершения

Изоляцию можно считать проверяемой, когда для каждого публичного и административного маршрута существует тест на чужой realm, а все добавляемые методы проходят те же инварианты. Конкретную реализацию этого инварианта нужно подтверждать тестами и ревью, а не доверять только наличию SQL-фильтра.

Продолжить изучение

Справочные материалы по протоколам и устройству RustCloak собраны в технической Wiki.

Перейти в Wiki →