DBAtlas · Atlas de operações de banco de dados

Configurar isolamento de tenants com row-level security

PostgreSQLSegurança

Comando

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';

O que faz

Habilita RLS na tabela e define uma política que filtra as linhas pelo id do tenant em uma variável de sessão (USING) e bloqueia gravações para outro tenant (WITH CHECK).

Quando usar

Para impor no banco o isolamento de dados de aplicações multi-tenant em vez de depender do código da aplicação.

Atenção

Superusuários e roles com o atributo BYPASSRLS sempre ignoram as políticas; o dono da tabela só fica sujeito a elas com FORCE ROW LEVEL SECURITY. Com RLS habilitado e nenhuma política correspondente, o resultado é vazio (sem erro). current_setting(..., true) retorna NULL quando a variável não está definida; NULLIF evita que a string vazia deixada após RESET falhe como ''::int. Os usuários podem alterar app.tenant_id com SET; apenas uma camada de aplicação confiável deve defini-lo e os usuários finais não devem ter acesso SQL. Com um pooler em modo transaction, use SET LOCAL em vez de SET. Indexe a coluna tenant_id usada na política. O pg_dump falha quando executado como um usuário sujeito a RLS; faça backups com uma role BYPASSRLS.

Abrir no DBAtlas →

Relacionados