Ein Lese-Zugang für BI-Tools, Reporting-Skripte oder Read-Replicas gehört zu den häufigsten Aufgaben in der DB-Administration. PostgreSQL bietet zwei sinnvolle Wege: kurz mit pg_read_all_data oder explizit per GRANT. Welcher passt, hängt davon ab, wie viel Kontrolle du über die Schemas brauchst.

Variante 1 — pg_read_all_data (PG 14+)

Die kurze Variante:

SQL Drei Zeilen, fertig
CREATE ROLE reporting LOGIN PASSWORD 'changeme'
    CONNECTION LIMIT 5;

GRANT pg_read_all_data TO reporting;
GRANT CONNECT ON DATABASE myapp TO reporting;

pg_read_all_data ist eine Predefined Role, die SELECT auf alle Tabellen, Views, Sequenzen und Materialized Views in allen Schemas der Datenbank umfasst — auch zukünftige.

Vorteile:

  • Wirklich nur drei Zeilen.
  • Keine ALTER DEFAULT PRIVILEGES nötig.
  • Funktioniert auch in zukünftigen Schemas.

Nachteile:

  • Wirklich alle Schemas. Wenn morgen jemand ein internal_admin-Schema mit Sensitive-Daten anlegt, kann der Reporting-User auch das lesen.
  • Funktioniert erst ab PG 14.

Faustregel: für interne Datenbanken mit klar getrennter Funktion (Webapp-DB, Analytics-DB) — gut. Für Multi-Tenant-Setups oder Datenbanken mit gemischtem Inhalt — lieber Variante 2.

Variante 2 — Explizite GRANTs

SQL Granular pro Schema
-- 1. Login-Rolle anlegen
CREATE ROLE reporting LOGIN PASSWORD 'changeme'
    CONNECTION LIMIT 5;

GRANT CONNECT ON DATABASE myapp TO reporting;

-- 2. Pro Schema, das gelesen werden soll:
GRANT USAGE ON SCHEMA app TO reporting;
GRANT SELECT ON ALL TABLES IN SCHEMA app TO reporting;
GRANT SELECT ON ALL SEQUENCES IN SCHEMA app TO reporting;

-- 3. Default-Privileges fuer ZUKUENFTIGE Objekte:
ALTER DEFAULT PRIVILEGES FOR ROLE app_owner IN SCHEMA app
    GRANT SELECT ON TABLES TO reporting;

ALTER DEFAULT PRIVILEGES FOR ROLE app_owner IN SCHEMA app
    GRANT SELECT ON SEQUENCES TO reporting;

-- 4. Search-path fuer den User
ALTER ROLE reporting SET search_path = app, public;

Wichtig: das FOR ROLE app_owner muss zur Rolle passen, die deine Migrationen ausführt. Wenn migrator neue Tabellen anlegt, brauchst du einen zusätzlichen Eintrag ALTER DEFAULT PRIVILEGES FOR ROLE migrator IN SCHEMA app GRANT SELECT ON TABLES TO reporting;. Sonst greifen die Defaults nicht (siehe Default Privileges).

Welche Variante wann?

SituationEmpfehlung
Einfache App-DB, ein Schema, PG 14+Variante 1 (pg_read_all_data)
Multi-Tenant-DB, Schema-pro-TenantVariante 2 — explizit pro Tenant-Schema
DB mit gemischten Sensitivitäts-LevelsVariante 2
Read-Replica für Drittanbieter-ToolsVariante 2 mit eingeschränkten Schemas
Quick-and-dirty für lokales ToolingVariante 1
PG 13 oder älterVariante 2 (Variante 1 nicht verfügbar)

Verifikation

Nach dem Anlegen prüfen, dass der User wirklich nur lesen kann:

Bash
$ psql -h localhost -U reporting -d myapp
Password for user reporting:
SQL
myapp=> SELECT count(*) FROM orders;
 count
-------
 42

myapp=> INSERT INTO orders (customer_id, total) VALUES (1, 100);
ERROR:  permission denied for table orders

myapp=> DROP TABLE orders;
ERROR:  must be owner of table orders

Schreibversuche und DDL werden sauber abgewiesen.

Sicherheits-Erweiterungen

default_transaction_read_only

Zusätzlich pro Rolle setzbar:

SQL
ALTER ROLE reporting SET default_transaction_read_only = on;

Damit beginnt jede Transaktion implizit als BEGIN READ ONLY. Falls reporting doch mal versehentlich Schreib-Rechte bekommt, können trotzdem keine Schreibvorgänge stattfinden — Defense in Depth.

statement_timeout

Reporting-Queries sind oft groß. Damit ein versehentlicher Cross-Join nicht den ganzen Server blockiert:

SQL
ALTER ROLE reporting SET statement_timeout = '5min';

Queries, die länger als 5 Minuten laufen, werden automatisch abgebrochen.

idle_in_transaction_session_timeout

Verhindert, dass eine BI-Tool-Session ihre Transaktion stundenlang offen lässt und dadurch VACUUM blockiert:

SQL
ALTER ROLE reporting SET idle_in_transaction_session_timeout = '5min';

FAQ

Sieht der Read-Only-User auch System-Tabellen?

Ja — pg_catalog-Tabellen sind grundsätzlich von jedem lesbar (das ist Postgres-Architektur). Mit pg_read_all_data kommen auch sonst eingeschränkte pg_stat_*-Views dazu. Wer das nicht will, sollte stattdessen Variante 2 mit explizit aufgezählten Schemas nutzen.

Was ist mit Functions — darf der User die ausfuehren?

pg_read_all_data umfasst kein EXECUTE auf Funktionen. In Variante 2 musst du explizit GRANT EXECUTE ON FUNCTION … TO reporting setzen, falls die Reporting-Tools das brauchen. Klassisch nicht nötig, aber bei BI-Tools wie Metabase, die manchmal Helper-Functions nutzen, kann es relevant werden.

Wie blockiere ich, dass der User mit pg_dump die ganze DB rauszieht?

Gar nicht zuverlässig. Wer SELECT auf alles hat, kann die Daten in irgendeiner Form exportieren — über pg_dump, eigene Scripts, Copy. Wenn das ein Problem ist, hilft nur Daten-Minimierung: Views, die nur die nötigen Spalten/Zeilen exponieren, und SELECT-Privilegien auf diese Views statt auf die Roh-Tabellen.

Wie verteile ich das Passwort an mehrere BI-Tools?

Nicht — sondern lieber pro Tool einen eigenen User anlegen, alle Mitglied einer NOLOGIN-Gruppe reporting_group. Damit kannst du Einzelne deaktivieren oder rotieren, ohne andere zu treffen. Im Zweifel sogar pro Mensch ein eigener User mit GRANT reporting_group TO ….

Reicht das fuer einen pg_dump-Backup-User?

Fast — aber pg_dump braucht zusätzlich Privilegien auf manche Sequenzen und ggf. auf Views, die er logisch rekonstruieren will. Für reine Backups ist ein dedizierter Backup-User mit pg_read_all_data plus REPLICATION der saubere Weg, siehe Backup-Benutzer.

Weiterführende Ressourcen

Externe Quellen

/ Weiter

Zurück zu Server-Administration

Zur Übersicht