PRODSouveräne europäische BaaS-PlattformÖffnen Sie das Dashboard →

Ingenieurwesen · 10 Min. Lesezeit

RLS im Vergleich zu einer dedizierten Datenbank pro Projekt

Affane Daylami · Fondateur · 27. Juli 2026

Zurück zum Blog

Suchen Sie nach „RLS Multi-Tenant Postgres“ und Sie stoßen fast überall auf dasselbe Schema: eine gemeinsam genutzte Datenbank, eine Tenant_ID-Spalte, eine Richtlinie, die die Zeilen filtert. Dies ist nicht das Modell, das Aurabase verwendet, um seine Projekte voneinander zu isolieren. Jedes Projekt erhält seine eigene Postgres 16-Datenbank, die nie mit einem anderen Kunden geteilt wird – das RLS bleibt dort, aber auf einer anderen Ebene: in Ihrer Datenbank, für Ihre eigenen Benutzer.

Dieser englische Text wurde automatisch aus dem französischen Original generiert und wurde noch nicht überprüft.
Diese Seite wurde automatisch übersetzt. Maßgeblich ist die englische Version.

„RLS“ und „Multi-Tenant“ finden sich in fast allen bereits zu diesem Thema veröffentlichten Inhalten nebeneinander – eine legitime Wahl für viele SaaS-Architekturen, die aber nicht die Entscheidung von Aurabase ist, die eigenen Clients voneinander zu trennen. In diesem Beitrag wird der Unterschied zur echten Bereitstellungs-Engine und den tatsächlich angewendeten RLS-Richtlinien erläutert, es handelt sich nicht um eine vereinfachte Marketingbeschreibung. Einen Überblick darüber, was die Managed Postgres-Engine von Aurabase über die Isolation hinaus abdeckt, finden Sie in der Dokumentation zur Datenbank .

Das Wesentliche

  • Zwischen Projekten isoliert Aurabase durch dedizierte Postgres-Basis, niemals durch RLS allein – jedes Projekt hat seine eigene physische Basis, auf einem dedizierten CNPG-Cluster (Unternehmensebene) oder auf dem CNPG-Cluster seiner eigenen Organisation (Free/Pro/Team), die niemals mit einer anderen Organisation geteilt wird.
  • Das RLS (auth.uid(), auth.role(), auth.jwt()) bleibt aktiv und wird innerhalb Ihrer-Basis empfohlen, um Ihre eigenen Benutzer zu isolieren – dieselbe Konvention wie bei Supabase.
  • service_role und projektbasierte Verwaltungsrollen umgehen RLS absichtlich (BYPASSRLS): eine angenommene architektonische Wahl für den Serverbetrieb, kein Fehler.
  • Eine in diesem Repository bereits korrigierte Regression – irrtümlich gewährte PUBLIC-Rechte für alte gemeinsame Schemata – veranschaulicht konkret, warum eine Grenze auf der Basisebene besser resistent ist als eine reine Anwendungsgrenze.
#
Das Standardmodell

Die Abkürzung, die die meisten Multi-Tenant-RLS-Anleitungen verwenden

Das am häufigsten dokumentierte Muster für Multi-Tenant-Postgres besteht aus drei Zeilen: einer einzelnen Basis, einer tenant_id-Spalte in jeder Tabelle, einer RLS-Richtlinie, die diese Spalte mit einem aus dem JWT extrahierten Wert vergleicht. Es ist wirtschaftlich – ein Pool von Verbindungen, ein Diagramm, eine einzelne Instanz zum Ausführen – und es funktioniert gut, wenn die Mandanten zahlreich und klein sind und der individuelle Anteil gering ist.

Der Kompromiss ist real: Die Grenze zwischen zwei Clients wird zu einem SQL-Ausdruck, der Tabelle für Tabelle ausgewertet wird. Eine in einer neuen Tabelle vergessene Richtlinie, eine Verbindung, die mit einer Superuser-Rolle ausgeführt wird, ein live gestartetes Debug-Skript – jeder dieser Vorfälle, so trivial er auch sein mag, kann stillschweigend die Leitungen aller Mandanten gleichzeitig offenlegen. Die Sicherheitsgrenze und die technische Grenze (die Basis) sind dann genau dasselbe.

Infos

Das ist an sich keine schlechte Wahl – für viele Produkte ist es der richtige Kompromiss. Der Sinn dieses Beitrags liegt woanders: Dies ist nicht der Kompromiss, den Aurabase eingegangen ist, um seine eigenen Kunden (ganze Projekte, möglicherweise mit unterschiedlichen Compliance-Anforderungen) voneinander zu trennen.

#
Im Code

Zwei Architekturen, niemals eine gemeinsame Basis zwischen Projekten

Seit einer kürzlichen Konsolidierung des Provisioners (im Code als „Task 12“ gekennzeichnet) fällt ein aktives Postgres-Projekt bei Aurabase unter genau zwei Architekturen – die alten Modelle mit einer tatsächlich von mehreren Projekten gemeinsam genutzten Basis wurden aus dem Provisioning-Pfad entfernt.

provisioning/instances.rsrust
pub enum ProjectInstanceKind {
    /// CNPG-Cluster, der NUR DIESEM Projekt gewidmet ist (Unternehmensebene).
    FullyDedicated,

    /// Datenbank zum CNPG-Cluster des Projekts ORGANIZATION —
    /// mit ANDEREN Projekten derSELBEN Organisation geteilt,
    /// niemals mit einer Drittorganisation.
    SharedClusterDedicated,
}

Die Projektebene entscheidet, welche der beiden zutrifft – und es ist der Code, der entscheidet, nicht ein angekreuztes Kästchen in einem Dashboard:

provisioning/rules.rsrust
fn should_provision_dedicated(engine: &str, db_url_encrypted: &Option<String>, plan: &str) -> bool {
    matches!(engine, "postgres" | "postgresql")
        && plan == "enterprise"
        && !non_empty(db_url_encrypted)
}

// Should_route_to_fleet(): jede Nicht-Firmen-Stufe (Free/Pro/Team)
// Route zum CNPG-Cluster IHRER EIGENEN Organisation, niemals zu dem einen
// von einer anderen – siehe Migration 073, Konsolidierung auf 2 Architekturen.
AbmessungenFullyDedicated (Unternehmen)SharedClusterDedicated (kostenlos/Pro/Team)
CNPG-ClusterDiesem einen Projekt gewidmetGeteilt, aber niemals zwischen zwei Organisationen
Postgres-DatenbankApp, nur darauf projizierenproject_<uuid>, eine pro Projekt im Cluster
PostgreSQL-AnmeldungEin einzelnes Projekt im Cluster: keine Gefahr einer KreuzmitgliedschaftMelden Sie sich pro Projekt an (F-013), Mitglied der einzigen Rollen „tenant_<uuid>“.

On both architectures, the base or cluster never hosts two different organizations — so the question is not “is your data isolated” but “does your project have compute CloudNativePG all to itself, or does it share it with other projects in the same organization.”

Diese Konsolidierung zweier Architekturen ist neu: Der Code trug zuvor zwei zusätzliche Pfade – einen „Shared Master“, bei dem mehrere Projekte in derselben Datenbank koexistierten, nur durch Diagramme isoliert, und eine postgrest_dedicated_shared_db-Variante. Eine dedizierte Migration entfernte sie und verschärfte die Einschränkung der Tabelle projects auf nur die beiden verbleibenden Werte, gerade weil das gemeinsame Schemamodell die Quelle des unten beschriebenen Fehlers war.

#
Sicherheitsgrenze

Warum eine dedizierte Basis eine von Kunden gemeinsam genutzte EPIRB übertrifft

Eine separate Postgres-Datenbank ist eine Grenze auf Verbindungsebene, keine Grenze auf Zeilenebene. Eine mit der Datenbank von Projekt A verbundene Anwendungsrolle kann die Tabellen von Projekt B einfach nicht abfragen – für sie ist keine Sitzung geöffnet. Diese Eigenschaft gilt auch dann, wenn eine RLS-Richtlinie schlecht geschrieben ist, in einer Tabelle fehlt oder von einer hohen Rolle umgangen wird: Im schlimmsten Fall bleibt sie auf eine einzelne Datenbank beschränkt.

Auch diese Ablagerung trägt die Spur eines echten Käfers, was das gegenteilige Risiko verdeutlicht. Unter dem alten Shared-Schema-Modell (inzwischen zurückgezogen) gewährte provision_postgres_schema fälschlicherweise GRANT ALL ... TO PUBLIC-Rechte für jedes Projektschema – PUBLIC galt für alle-Rollen in der Datenbank ohne Mitgliedschaftsbedingungen, ein pro Projekt isolierter Login konnte im Schema eines anderen lesen und schreiben. Durch eine korrigierende Migration (066) wurden diese Rechte aus dem bestehenden entfernt.

Die gelernte Lektion

Der Patch fügte keine weitere RLS-Richtlinie hinzu, um das Leck zu schließen – er beseitigte die Möglichkeit, dass zwei Projekte eine Datenbank gemeinsam nutzen. Zu den beiden aktuellen Architekturen dokumentiert es ein Kommentar von provisioning.rs schwarz auf weiß: „Jedes Projekt verfügt bereits über seine eigene physische Postgres-Datenbank“. Eine Grenze auf Basisebene macht eine ganze Klasse solcher Fehler einfach unerreichbar, anstatt sich darauf zu verlassen, dass jede Richtlinie immer korrekt geschrieben ist.

Ein Patch vom 23. August 2026 geht in die gleiche Richtung: Ein vom Provisioner bedingungslos platzierter REVOKE ALL ON SCHEMA public wurde von der Topologie abhängig gemacht, da er nur auf dem alten Shared-Database-Modell für echte Isolation sorgte – auf den beiden aktuellen Architekturen blockierte er ohne Nutzen den Import von SQL-Dumps, die explizit auf public.<table>verweisen.

#
RLS in der Praxis

EPIRB bleibt dort – in Ihrer Datenbank, für Ihre Benutzer

Keines der oben genannten Dinge macht EPIRB nutzlos – es verändert nur den Boden. Sobald Sie sich in Ihrer-Projektdatenbank befinden, stellt Aurabase genau die PostgREST-Konvention bereit, die von Supabaseübernommen wurde: drei SQL-Funktionen, die die vom Gateway in request.jwt.claimsfestgelegten JWT-Ansprüche lesen.

libs/aura-migrations/golden/auth_global.sqlsql
create function auth.uid() returns uuid
    language sql stable security definer
    set search_path to 'pg_catalog', 'pg_temp'
    as $$
    select nullif(nullif(current_setting('request.jwt.claims', true), '')::json->>'sub', '')::uuid
$$;

Diese Helfer werden in den eigentlichen Richtlinien von Aurabase selbst verwendet – und nicht nur für Sie dokumentiert. Hier ist die Richtlinie, die storage_objectsschützt, wenn sie im Repository abgelegt wird (zum Lesen in mehrere Zeilen neu formatiert):

libs/aura-migrations/golden/storage.sqlsql
alter table storage_objects enable row level security;

create policy storage_objects_select on storage_objects
  for select using (
    (owner_id = auth.uid())
    or (
      exists (
        select 1 from storage_buckets b
        where (b.name = storage_objects.bucket_name and b.public)
      )
    )
  );

In Ihrem eigenen project_<uuid>-Schema, das Ihre Anwendungstabellen enthält, platziert Aurabase bewusst keine Richtlinien in Ihrem Namen – der Code dokumentiert dies als „Supabase-Modell“: Die RLS Ihrer Tabellen liegt weiterhin in Ihrer Verantwortung, mit denselben Funktionen und derselben Syntax.

#
BYPASSRLS angenommen

service_role umgeht RLS – absichtlich, nicht zufällig

Postgres bietet nativ ein -Rollenattribut, BYPASSRLS, das alle Richtlinien ignoriert. Aurabase verwendet es freiwillig für zwei Rollenfamilien: aura_service_role (die Serverrolle, die niemals auf der Browserseite verfügbar gemacht wird) und die für jedes Projekt spezifische Verwaltungsrolle, die bei DDL-Vorgängen wie ALTER SCHEMA ... OWNER TOverwendet wird.

provisioning/roles.sqlsql
create role aura_service_role nologin bypassrls;
-- Serverrolle: niemals auf der Browserseite verfügbar gemacht, niemals Mitglied
-- Rollen aus einem anderen Projekt.

Die Rolle, die Ihre Anfragen bedient anon/authenticated – tenant_<uuid> – hat kein BYPASSRLS: Das RLS gilt ausnahmslos normal für sie. Als Bonus erhalten die für jedes Projekt spezifischen Systemdiagramme (_auth, _storage, _platform) ein aktiviertes RLS ohne Richtlinie – daher standardmäßig eine vollständige Ablehnung für jede Nicht-Bypass-Rolle, eine Tiefenverteidigung für den Fall, dass ein Anwendungspfad eines Tages versehentlich darauf zugreift.

Infos

Das Umgehen des RLS mit einer erhöhten Serverrolle gibt es nicht nur bei Aurabase – es ist das gleiche Konstrukt wie service_role auf der Supabase-Seite. Es geht nicht darum, BYPASSRLSzu vermeiden, sondern es niemals einer Rolle zuzuweisen, auf die von einem Client aus zugegriffen werden kann, und es auf ein einzelnes Projekt zu beschränken.

Diese Serverrolle ist Teil eines umfassenderen Ansatzes – vordefinierte Rollen, benutzerdefinierter RBAC, Überwachungsprotokolle –, der auf der Seite Sicherheit und RBACausführlich beschrieben wird.

#
Verteidigung in der Tiefe

In einem gemeinsam genutzten Cluster erledigt die Datenbank nicht die gesamte Arbeit alleine

Auf der SharedClusterDedicated-Ebene koexistieren mehrere Projekte derselben Organisation auf einem einzigen CNPG-Cluster. Die physische Datenbank trennt die Projekte bereits voneinander, aber die PostgreSQL-Rollen – sie – sind globale Objekte für den Cluster, nicht für die Datenbank. Aurabase fügt daher eine Ebene hinzu: ein separates PostgreSQL-Login pro Projekt.

libs/aura-core/src/lib.rsrust
pub fn project_authenticator_role(project_id: &str) -> String {
    format!("project_{}_authenticator", project_id.replace('-', '_'))
}

// Standardmäßig aktiv (F013_PER_PROJECT_AUTHENTICATOR), deaktivierbar
// ausdrücklich als Notflucht.

Jedes Projekt stellt eine Verbindung mit seinem eigenen Login her und ist nur Mitglied seiner eigenen tenant_<uuid> / tenant_<uuid>_admin-Rollen – niemals die eines anderen Projekts im selben Cluster. Die Datenbank isoliert die Daten bereits; Dieser Login pro Projekt isoliert auch die Identität, die eine Verbindung herstellt, sodass ein Vorfall in einem Projekt seinem Login keine Mitgliedschaft verleiht, die er an ein anderes vererben kann.

#
Für Ihre Architektur

RLS allein oder dedizierte Basis: So entscheiden Sie sich für Ihr eigenes SaaS

Die Wahl von Aurabase ist keine universelle Regel – es ist ein Kompromiss für einen bestimmten Fall: die Isolierung von Kunden voneinander, möglicherweise mit unterschiedlichen Compliance-Anforderungen, auf einer Plattform, die sie nicht kontrollieren. Wenn Sie Ihr eigenes SaaS aufbauen, stellt sich für Sie die gleiche Frage, allerdings in einem anderen Maßstab.

  • RLS mit tenant_id in einer gemeinsamen Basis – relevant, wenn Ihre Mieter zahlreich sind, einzeln einen geringen Anteil haben und die Kosten einer Basis pro Mieter unverhältnismäßig wären. Testen Sie jede Richtlinie ausnahmslos mit pg_provefür jede Tabelle.
  • Dedizierte Basis oder Diagramm – relevant, wenn ein Mandant ein eigenes Compliance-Problem hat (Gesundheit, Personalwesen, öffentlicher Sektor), ein Volumen, das eine Leistungsisolation rechtfertigt, oder die Kosten eines Lecks zwischen zwei bestimmten Clients in keinem Verhältnis zu den Kosten zusätzlicher Infrastruktur stehen würden.

Das Aurabase-Preisniveau wendet dasselbe Schlichtungsverfahren auf seine eigenen Kunden an: standardmäßig gemeinsame Basis durch die Organisation, dedizierter Cluster, wenn die Herausforderung des Projekts dies rechtfertigt. Für RLS-Muster in Ihrer eigenen Datenbank – Besitz, Mandantenfähigkeit nach Organisation, Rollenhierarchie – werden im RLS-Leitfaden in der Produktion die drei Fälle mit pgTAP-Tests detailliert beschrieben. Und wenn Sie die automatisch generierte API in Ihrem Diagramm über REST hinaus interessiert, deckt der Vergleich von pg_graphql mit Hasura und PostGraphile die andere Hälfte der von Aurabase bereitgestellten Postgres-Oberfläche ab.

#
Häufig gestellte Fragen

FAQs

Reicht RLS allein aus, um Mandanten in einer einzigen Postgres-Datenbank zu isolieren?+
Technisch gesehen ja, wenn jede Tabelle eine korrekte Richtlinie trägt und keine Verbindung der Nicht-Bypass-Rolle entgeht. Dies ist genau das operative Risiko, das Aurabase zwischen verschiedenen Projekten nicht eingegangen ist – jeder Richtlinienfehler würde auf eine einzelne Basis beschränkt bleiben. Innerhalb eines einzelnen Projekts bleibt RLS +mieter_id für Ihre eigenen Mieter eine legitime und weit verbreitete Wahl.
Warum verfügen kostenlose Projekte nicht über einen dedizierten Postgres-Cluster wie die Enterprise-Ebene?+
Ein dedizierter CloudNativePG-Cluster pro Projekt, auch für kostenlose Projekte, würde die reservierte Rechenleistung vervielfachen, ohne dass es einen Bezug zur tatsächlichen Nutzung der meisten Projekte gäbe. Stattdessen stellt Aurabase jedem Nicht-Unternehmensprojekt eine eigene physische Postgres-Datenbank im CNPG-Cluster der eigenen Organisation zur Verfügung, die niemals mit einer anderen Organisation geteilt wird, und nicht ein Schema in einer gemeinsamen Datenbank mehrerer einander unbekannter Clients.
Woher weiß auth.uid() technisch gesehen, wer ich bin?+
Das Aurabase-Gateway überprüft Ihr JWT und platziert seine Ansprüche dann für die Dauer der Transaktion im Postgres-Sitzungsparameter request.jwt.claims. auth.uid() tut nichts weiter, als das Unterfeld aus diesem JSON zu extrahieren und es in uuid umzuwandeln – ohne dass Ansprüche geltend gemacht werden (anonyme Anfrage oder direkte Verbindung außerhalb eines Gateways), gibt current_setting() NULL zurück und auth.uid() gibt daher NULL zurück, was den Zugriff auf eine Richtlinie mit (owner_id = auth.uid()) schließt.

BEREIT ZUM EINSATZ?

Ihr Backend in fünf Minuten.

Keine Kreditkarte erforderlich · 500 MB kostenlos · 50.000 MAU