Row-Level Security
AiHummer многоарендный, и PostgreSQL Row-Level Security (RLS) — это дополнительная граница изоляции на уровне базы данных. При включённом RLS база данных — а не только код приложения — гарантирует, что запрос видит только строки, принадлежащие текущему арендатору.
Важно: RLS не заменяет аутентификацию, RBAC и правильную установку
tenant_id в транзакции — это дополнительный слой под ними, а не замена.
Зачем RLS
Фильтрация на уровне приложения (WHERE tenant_id = ...) необходима, но хрупка:
одно забытое условие может «утечь» данные между арендаторами. RLS переносит
гарантию в PostgreSQL, так что даже нефильтрованный запрос вернёт только строки
текущего арендатора. Это слой эшелонированной защиты под собственным
ограничением области доступа приложения. Полную модель multitenancy — и как она сочетается с идемпотентными
побочными эффектами — см. в
Multitenancy и идемпотентность.
Ограниченная роль (опционально)
RLS включается опционально — передачей gateway второго подключения к базе, которое использует ограниченную роль вместо владельца:
# ~/.aihummer/etc/gateway.env
# Пул владельца — выполняет миграции, используется для system/bypass операций
AIHUMMER_DATABASE_URL=postgres://owner:...@localhost/aihummer
# Ограниченный пул приложения — действуют политики RLS (роль aihummer_app)
AIHUMMER_DB_APP_URL=postgres://aihummer_app:...@localhost/aihummer
Роль aihummer_app не является владельцем таблиц, поэтому PostgreSQL
применяет к ней политики RLS. Запросы приложения идут через этот ограниченный
пул. Включение RLS сводится к заданию AIHUMMER_DB_APP_URL — и
локальные/стандартные (host-native) установки настраивают эту переменную
автоматически, поэтому RLS активен «из коробки». «Опционально» он лишь в том
смысле, что при нестандартном или ручном развёртывании AIHUMMER_DB_APP_URL
нужно задать самому.
[!NOTE] Без
AIHUMMER_DB_APP_URLшлюз использует пул владельца для всего, и RLS фактически не применяется. Задайте ограниченный пул (что за вас делает стандартный установщик), чтобы включить изоляцию на уровне базы данных.
[!IMPORTANT] RLS не зависит от тарифа. Он работает одинаково на всех тарифах, включая Community. Если на экране лицензии строка «Защита на уровне строк» показана как недоступная, это неточность самого экрана, а не состояние базы данных.
Где RLS активен сразу, а где его надо включить
| Как вы ставили продукт | Состояние RLS после установки |
|---|---|
| Обычная установка, PostgreSQL разворачивает установщик | Активен. Ограниченная роль и AIHUMMER_DB_APP_URL создаются автоматически |
| Свой или управляемый PostgreSQL (адрес базы задан заранее) | Не активен. Роль и AIHUMMER_DB_APP_URL заводит оператор |
| Установка без прав администратора (rootless) | Не активен. То же самое |
[!WARNING] Две ошибки, после которых RLS «включён», но не защищает. Первая: в
AIHUMMER_DB_APP_URLуказана роль-владелец таблиц или суперпользователь — PostgreSQL освобождает такие роли от политик, а шлюз при этом всё равно сообщит, что RLS активен. Используйте отдельную ограниченную роль. Вторая: на своём PostgreSQL ограниченная роль может быть создана автоматически с предсказуемым паролем — задайте ей собственный пароль до того, как база станет доступна по сети.
Ограничение по арендатору
Внутри запроса приложение устанавливает текущего арендатора (tenant_id) на
подключении до выполнения запросов, ограниченных арендатором — концептуально
db.WithTenant. После этого политики RLS на ограниченной роли ограничивают
каждое чтение и запись строками этого арендатора. Область действия привязана к
единице работы, поэтому она не утекает между параллельными запросами. Если
приложение не установит tenant_id корректно, RLS не спасёт — поэтому этот шаг
обязателен.
запрос ─▶ определить арендатора ─▶ db.WithTenant(арендатор) ─▶ запросы видят только его
Режим system / bypass для воркеров
Часть работы законно кросс-арендна или не привязана к арендатору — фоновые воркеры, планировщики, восстановление доставки и похожее обслуживание. Для них шлюз использует режим system (bypass), который работает на пуле владельца, вне политик RLS на арендатора, чтобы инфраструктурные задачи могли работать со всем набором данных.
[!WARNING] Режим bypass — только для доверенных внутренних воркеров. Кодовые пути обработки запросов, действующие от имени пользователя, всегда должны идти через ограниченный, привязанный к арендатору пул — никогда через путь bypass.
Миграции выполняются на пуле владельца
Изменения схемы требуют привилегий, которых у ограниченной роли нет, поэтому
миграции всегда выполняются на пуле владельца (AIHUMMER_DATABASE_URL), под
advisory-lock, при старте. Ограниченная роль aihummer_app используется только
для обычного трафика приложения. Это держит разделение привилегий чистым:
операции изменения схемы — у владельца; доступ к данным арендаторов — у
ограниченной роли с применением RLS.
Куда дальше
- Multitenancy и идемпотентность — полная модель арендаторов и как побочные эффекты остаются безопасными при восстановлении.
- Хранилище секретов — ключ данных на арендатора усиливает ту же изоляцию на уровне секретов.
- RBAC и API-ключи с ограниченными правами — авторизация над слоем данных.