Многоарендная B2B SaaS-платформа: как не показать данные одного клиента другому
Данные клиента не видны другому клиенту, а это проверяется тестом на каждом изменении, а не обещанием
Проверяется: набор тестов изоляции и прогон прав
SaaS и продуктыРаботаем по NDA
Продукт создавался под одного заказчика, потом появились второй и третий. Данные лежат в общих таблицах, различие клиентов держится на условиях в запросах. Каждая новая функция рискует забыть условие, а отчёты и фоновые задачи вообще работают поверх всей базы. Команда боится выкладывать изменения.
Что съедает срок и бюджет на самом деле
Сложность не в самой изоляции, а в том, что её нужно удержать на всех путях доступа к данным.
Фильтр по клиенту живёт в каждом запросе
достаточно одного забытого условия в новом отчёте, чтобы выдать чужие строки. Нужна защита ниже кода приложения, на уровне базы или обязательного слоя доступа.
Фоновые задачи и выгрузки не знают о клиенте
очередь, рассылки и экспорт работают с данными вне пользовательского запроса, где нет текущего клиента. Идентификатор клиента должен передаваться явно.
Роли платформы и роли клиента смешаны
администратор платформы, администратор клиента и рядовой пользователь получают права из одной таблицы. Ошибка здесь даёт повышение прав.
Миграции на общей базе опасны
изменение схемы блокирует всех клиентов сразу. Без плана выкладки без простоя выкладка превращается в окно недоступности для всех.
Ограничение, которое определяет решение
Некоторые клиенты требуют хранить их данные отдельно, на своём сервере или в отдельной базе. Поэтому схему изоляции выбирают не только по удобству: общая база с защитой по строкам, отдельная схема на клиента или отдельная база. Персональные данные граждан России обычно должны храниться на серверах в России. Договор с клиентом и согласия пользователей готовит юрист заказчика.
Как проверить, что работа сделана
Тест изоляции: автоматический набор, который создаёт двух клиентов и пробует прочитать, изменить и выгрузить данные одного из-под учётной записи другого. Любая успешная попытка проваливает сборку.
Прогон ролей: из-под каждой роли пробуем действия, на которые у неё нет прав, на уровне интерфейса и программного интерфейса.
Миграция: схему меняют на копии боевой базы с замером времени блокировок, и порядок выкладки записан до запуска.
О чём спросить любого подрядчика
- Где именно проверяется принадлежность записи клиенту: в каждом запросе или в слое, который нельзя обойти.
- Как изолированы фоновые задачи, выгрузки и отчёты.
- Есть ли автоматические тесты изоляции и запускаются ли они на каждом изменении.
- Можно ли вынести одного клиента на отдельную базу, если он потребует.
- Как выкладывается изменение схемы без остановки для всех.
Как мы идём по этапам
На каждом этапе назван результат, который остаётся у заказчика. Остановиться можно после любого.
- Карта данныхЗаписываем, какие таблицы принадлежат клиенту, какие общие, какие связывают их. Результат: схема принадлежности данных.
- Выбор схемы изоляцииСравниваем вариант с общей базой и защитой по строкам, отдельные схемы и отдельные базы под ваши требования. Результат: обоснованное решение.
- Слой доступа и ролиДелаем обязательный слой, который подставляет клиента, и разделяем роли платформы и клиента. Результат: рабочее ядро на стенде.
- Тесты изоляцииПишем автоматический набор и подключаем его к сборке. Результат: сборка, которая падает при утечке.
- Миграция существующих данныхПроставляем принадлежность, проверяем на копии, выкладываем поэтапно. Передаём исходный код, инструкции и регламент сопровождения.
Как это обычно устроено внутри
Типовая схема: у каждой строки есть идентификатор клиента, в базе включена защита по строкам, соединение приложения получает текущего клиента из сессии и не может его сменить. Фоновые задачи запускаются от имени конкретного клиента. Роли платформы и клиента хранятся раздельно, действия администраторов пишутся в журнал.
- PostgreSQL
- Защита по строкам
- REST API
- Очередь задач
- Автоматические тесты
- Docker
Похожая задача у вас?
Разберём её на созвоне за 40 минут: назовём объём работ, ограничения контура и по каким числам вы будете принимать результат. Если задача не наша — скажем прямо.