DBAtlas · Atlas für Datenbankbetrieb

Mandantentrennung mit Row-Level Security einrichten

PostgreSQLSicherheit

Befehl

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

Was es tut

Aktiviert RLS auf der Tabelle und definiert eine Policy, die Zeilen nach der Mandanten-ID in einer Session-Variable filtert (USING) und Schreibvorgänge für einen anderen Mandanten blockiert (WITH CHECK).

Wann einsetzen

Um bei mandantenfähigen Anwendungen die Datentrennung in der Datenbank zu erzwingen, statt sich auf den Anwendungscode zu verlassen.

Vorsicht

Superuser und Rollen mit dem Attribut BYPASSRLS umgehen Policies immer; der Tabelleneigentümer unterliegt ihnen nur mit FORCE ROW LEVEL SECURITY. Ist RLS aktiviert und passt keine Policy, ist das Ergebnis leer (kein Fehler). current_setting(..., true) liefert NULL, wenn die Variable nicht definiert ist; NULLIF verhindert, dass der nach RESET verbleibende leere String als ''::int fehlschlägt. Benutzer können app.tenant_id mit SET ändern; nur eine vertrauenswürdige Anwendungsschicht sollte sie setzen, und Endbenutzer dürfen keinen SQL-Zugriff erhalten. Mit einem Pooler im Transaktionsmodus SET LOCAL statt SET verwenden. Indiziere die in der Policy genutzte Spalte tenant_id. pg_dump schlägt fehl, wenn es als Benutzer läuft, der RLS unterliegt; erstelle Backups mit einer BYPASSRLS-Rolle.

In DBAtlas öffnen →

Verwandte Einträge