DBAtlas · Атлас эксплуатации баз данных

Настроить изоляцию арендаторов (tenant) через row-level security

PostgreSQLБезопасность

Команда

ALTER TABLE app.orders ENABLE ROW LEVEL SECURITY;
-- Make the table owner subject to the policy too
ALTER TABLE app.orders FORCE ROW LEVEL SECURITY;

CREATE POLICY orders_tenant_isolation ON app.orders
  FOR ALL
  TO app_readwrite
  USING (tenant_id = NULLIF(current_setting('app.tenant_id', true), '')::int)
  WITH CHECK (tenant_id = NULLIF(current_setting('app.tenant_id', true), '')::int);

-- The application sets the tenant at the start of every transaction (pooler-friendly)
BEGIN;
SET LOCAL app.tenant_id = '42';
SELECT * FROM app.orders;
COMMIT;

-- Configured policies
SELECT schemaname, tablename, policyname, roles, cmd, qual, with_check
FROM pg_policies
WHERE tablename = 'orders';

Что делает

Включает RLS на таблице и определяет политику, которая фильтрует строки по идентификатору арендатора из переменной сессии (USING) и блокирует запись для другого арендатора (WITH CHECK).

Когда использовать

Чтобы обеспечить изоляцию данных в multi-tenant-приложениях на уровне базы данных, а не полагаться на код приложения.

Внимание

Суперпользователи и роли с атрибутом BYPASSRLS всегда обходят политики; на владельца таблицы они распространяются только с FORCE ROW LEVEL SECURITY. При включённом RLS и отсутствии подходящей политики результат пуст (без ошибки). current_setting(..., true) возвращает NULL, если переменная не определена; NULLIF не даёт пустой строке, оставшейся после RESET, вызвать ошибку как ''::int. Пользователи могут изменить app.tenant_id через SET; задавать его должен только доверенный уровень приложения, и конечные пользователи не должны получать доступ к SQL. С пулером в режиме transaction используйте SET LOCAL вместо SET. Проиндексируйте столбец tenant_id, используемый в политике. pg_dump завершается ошибкой при запуске от пользователя, на которого распространяется RLS; снимайте бэкапы ролью с BYPASSRLS.

Открыть в DBAtlas →

Связанные материалы