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

SQL Gruppe + Mitglieder + Rechte
-- 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

SQL
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:

SQL
SELECT pg_terminate_backend(pid)
FROM pg_stat_activity
WHERE usename = 'bob' AND pid <> pg_backend_pid();

Mitgliedschaft auditieren

Wer ist in welcher Gruppe?

SQL Vollständige Mitgliedschafts-Liste
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:

SQL
 member | member_of | admin_option
--------+-----------+--------------
 alice  | devs      | f
 bob    | devs      | f
 carol  | devs      | f

admin_option = t bedeutet: dieses Mitglied darf seinerseits andere zur Gruppe hinzufügen oder rauswerfen.

In psql kompakter:

SQL
myapp=# \du+
        List of roles
 Role name |    Attributes    | Member of   | Description
-----------+------------------+-------------+-------------
 alice     |                  | {devs}      |
 bob       |                  | {devs}      |
 carol     |                  | {devs}      |
 devs      | Cannot login     | {}          | Dev-Team

Die Description-Spalte (nur bei \du+) lässt sich pflegen mit:

SQL
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:

SQL Devs + Reporters
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-Zugang

Alice 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:

SQL
GRANT devs TO team_lead WITH ADMIN OPTION;

team_lead darf nun selbst:

SQL
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

/ Weiter

Zurück zu Server-Administration

Zur Übersicht