Privilegien einzeln pro User zu pflegen wird ab dem zweiten User unangenehm. PostgreSQL kennt keine echten Gruppen — aber NOLOGIN-Rollen erfüllen denselben Zweck. Dieses Rezept zeigt das Standard-Pattern: Gruppe anlegen, Mitglieder hinzufügen, Rechte einmal an die Gruppe vergeben, fertig.
Standard-Pattern in vier Schritten
-- 1. Gruppen-Rolle (NOLOGIN, also reiner Container)
CREATE ROLE devs;
-- 2. Login-Rollen (User)
CREATE USER alice PASSWORD 'changeme';
CREATE USER bob PASSWORD 'changeme';
CREATE USER carol PASSWORD 'changeme';
-- 3. Mitgliedschaft: alle drei kommen in devs
GRANT devs TO alice, bob, carol;
-- 4. Rechte einmal an die Gruppe vergeben
GRANT USAGE ON SCHEMA app TO devs;
GRANT SELECT, INSERT, UPDATE ON ALL TABLES IN SCHEMA app TO devs;Damit haben alle drei User vollen Read-Write-Zugriff auf app. Kommt morgen ein vierter dazu, ein einzelner GRANT devs TO dave; reicht. Sollen die Rechte erweitert werden, wird einmal GRANT … TO devs geändert — alle Mitglieder profitieren automatisch.
Mitgliedschaft entziehen
REVOKE devs FROM bob;Bob ist nicht mehr in der Gruppe. Bestehende offene Sessions behalten ihre Rechte allerdings, bis sie sich neu authentifizieren — Postgres kicked sie nicht aktiv raus. Wenn das relevant ist (etwa nach dem Ausscheiden eines Mitarbeiters), zusätzlich Sessions beenden:
SELECT pg_terminate_backend(pid)
FROM pg_stat_activity
WHERE usename = 'bob' AND pid <> pg_backend_pid();Mitgliedschaft auditieren
Wer ist in welcher Gruppe?
SELECT
r.rolname AS member,
g.rolname AS member_of,
m.admin_option
FROM pg_auth_members m
JOIN pg_roles r ON r.oid = m.member
JOIN pg_roles g ON g.oid = m.roleid
WHERE NOT g.rolname LIKE 'pg\_%'
ORDER BY g.rolname, r.rolname;Beispiel-Ausgabe:
member | member_of | admin_option
--------+-----------+--------------
alice | devs | f
bob | devs | f
carol | devs | fadmin_option = t bedeutet: dieses Mitglied darf seinerseits andere zur Gruppe hinzufügen oder rauswerfen.
In psql kompakter:
myapp=# \du+
List of roles
Role name | Attributes | Member of | Description
-----------+------------------+-------------+-------------
alice | | {devs} |
bob | | {devs} |
carol | | {devs} |
devs | Cannot login | {} | Dev-TeamDie Description-Spalte (nur bei \du+) lässt sich pflegen mit:
COMMENT ON ROLE devs IS 'Dev-Team mit Read-Write auf app-Schema';Mehrere Gruppen, mehrere Schemas
Realistischer Setup: zwei Schemas, zwei Gruppen mit unterschiedlichen Rechten:
CREATE ROLE devs;
CREATE ROLE reporters;
-- Devs: voller Zugriff auf app-Schema
GRANT USAGE ON SCHEMA app TO devs;
GRANT SELECT, INSERT, UPDATE, DELETE ON ALL TABLES IN SCHEMA app TO devs;
-- Reporters: nur Lesen, dafuer in app UND analytics
GRANT USAGE ON SCHEMA app, analytics TO reporters;
GRANT SELECT ON ALL TABLES IN SCHEMA app, analytics TO reporters;
-- Mitgliedschaften
CREATE USER alice PASSWORD 'changeme';
CREATE USER bob PASSWORD 'changeme';
CREATE USER carol PASSWORD 'changeme';
GRANT devs TO alice, bob; -- Alice + Bob entwickeln
GRANT reporters TO alice, carol; -- Alice + Carol haben Reporting-ZugangAlice ist in beiden Gruppen — sie hat sowohl Schreib- als auch Lese-Rechte. Bob nur in devs. Carol nur in reporters. Mit INHERIT (Default) erbt jeder seine Rechte automatisch.
Gruppen-Mitgliedschaft delegieren — WITH ADMIN OPTION
In größeren Setups will der DBA nicht jede personelle Änderung selbst machen. WITH ADMIN OPTION delegiert das Recht, Mitglieder in eine Gruppe aufzunehmen oder zu entfernen:
GRANT devs TO team_lead WITH ADMIN OPTION;team_lead darf nun selbst:
GRANT devs TO new_intern;
REVOKE devs FROM ex_employee;…ohne dabei Superuser zu sein. Wer das Recht zurückzieht, kann mit CASCADE alle abgeleiteten Mitgliedschaften gleich mit aufräumen.
Interessantes
CREATE GROUP ist Legacy — bevorzugt CREATE ROLE.
CREATE GROUP devs; funktioniert noch, ist aber nur ein Alias für CREATE ROLE devs NOLOGIN;. Konsistenter ist es, immer CREATE ROLE zu schreiben — und das NOLOGIN-Verhalten ergibt sich automatisch (Default), wenn man kein LOGIN ergänzt.
Mitgliedschaft ist transitiv.
Wenn senior_devs Mitglied von devs ist und alice Mitglied von senior_devs, dann erbt alice auch alle Rechte von devs. Postgres folgt der Kette beliebig tief. Für Teams mit Hierarchie ist das praktisch — kann aber zu unerwartetem Privilege Creep führen, wenn zu viele Verschachtelungen entstehen.
Attribute werden NICHT durch Mitgliedschaft transportiert.
CREATEDB oder CREATEROLE sind Rollen-Attribute, keine Privilegien — sie fließen nicht über Membership. Wenn die Gruppe admins CREATEROLE hat, bedeutet das nicht, dass deren Mitglieder Rollen anlegen dürfen. Jeder Mitglied müsste das Attribut individuell bekommen.
Mitgliedschaftsänderungen wirken erst nach Neuverbindung.
Wenn du einen User aus einer Gruppe entfernst, sieht der User in seiner aktuellen psql-Session weiterhin die alten Rechte. Postgres cached die Privilegien-Auflösung pro Session. Wer wirklich „sofort” entziehen will, beendet die Session zusätzlich (siehe pg_terminate_backend).
COMMENT ON ROLE macht das Setup wartbar.
Bei drei Gruppen-Rollen weiß man noch, wofür welche steht. Bei dreißig nicht mehr. COMMENT ON ROLE devs IS '…'; schreibt eine Erklärung in den Katalog, die \du+ mitzeigt — minimaler Aufwand, große Wirkung beim Onboarding neuer DBAs.
Weiterführende Ressourcen
Externe Quellen
- Role Membership – PostgreSQL Documentation
- GRANT (Role Membership) – PostgreSQL Documentation
- pg_auth_members – PostgreSQL Documentation
- COMMENT – PostgreSQL Documentation