pg-harden — Sicherheitsprüfung und Härtung für PostgreSQL mit Änderungsplan und Rückweg

pg-harden prüft eine PostgreSQL-Instanz gegen einen Katalog von 72 Sicherheitsregeln (61 für den Server, 11 für den Rechner, von dem aus verbunden wird), schreibt einen Änderungsplan mit Rückweg, vergleicht Berichte vor und nach einer Änderung und führt auf ausdrücklichen Befehl ausgewählte Korrekturen aus — mit Sicherung und einem Anmeldetest gegen das Aussperren. Ein PHP-Werkzeug ohne Composer-Abhängigkeiten (PHP 8.3 mit pdo_pgsql und mbstring); Lauffähigkeit geprüft mit PostgreSQL 14 bis 18 und 19rc1 unter Debian 13 sowie mit PostgreSQL 18 unter Windows 11. Das Werkzeug wird ohne Gewähr bereitgestellt: ein Lauf ohne Befund ist keine Freigabe. Bestimmt ist es für die Härtung eigener oder ausdrücklich beauftragter Systeme.

Open Source auf GitHub

Quelloffen unter MIT-Lizenz. Prüfung von postgresql.conf, pg_hba.conf, TLS, Passwörtern, Rollen und Rechten, Änderungsplan mit Rückweg, README auf Deutsch (vollständig) und Englisch (Kurzfassung); die Ausgabe des Werkzeugs ist deutsch.

Praxishinweis: pg-harden ist ein Hilfsmittel, keine Freigabe. Befunde fachlich bewerten, jede Änderung in einer Testumgebung erproben und erst dann produktiv einspielen. Die Nutzungsrechte und den Haftungsausschluss regelt die MIT-Lizenz (Datei LICENSE im Repository).

Zum GitHub-Repository →

Seminar: PostgreSQL Security und Härtung

Der fachliche Hintergrund zu den Regeln: Authentifizierung, pg_hba.conf, TLS, Rollen, Rechte und Betrieb — für DBAs und Sicherheitsverantwortliche.

PostgreSQL Security und Härtung →


Das Problem: Härtung ohne Plan und ohne Rückweg

Eine PostgreSQL-Installation ist nach dem Setup selten so abgesichert, wie es der Betrieb später verlangt. Typische Lücken stehen verstreut in mehreren Dateien und Katalogen:

  • pg_hba.conf: Einträge mit trust, md5 oder password, Netzzugänge ohne TLS, all für alle Adressen.
  • Passwörter: Rollen mit dem Rollennamen, postgres oder Passwort1 als Passwort — der Server speichert nur Prüfwerte, ein Blick in pg_authid zeigt das nicht.
  • Rechte: PUBLIC darf in public Objekte anlegen, sich mit jeder Datenbank verbinden und temporäre Tabellen erzeugen; SECURITY DEFINER-Funktionen ohne festen search_path.
  • Betriebssystem: zu offene Rechte auf Datenverzeichnis, Konfiguration, TLS-Schlüssel und Socket; Passwörter in Umgebungsvariablen, Skripten und .pgpass.

Eine Checkliste findet das. Sie sagt aber nicht, was eine Änderung am laufenden System bricht — und ein falscher Eintrag in pg_hba.conf sperrt im schlimmsten Fall alle aus. pg-harden verbindet deshalb Prüfung, Plan und Ausführung mit einem Rückweg.


Funktionsumfang & Kernkonzepte

  1. Prüfen (check): 72 Regeln mit Schweregrad, Begründung und Maßnahme. Jede Datenbankprüfung läuft als einzelne Anweisung in einer schreibgeschützten Transaktion (BEGIN TRANSACTION READ ONLY … ROLLBACK). Ausgabe als Text, HTML oder JSON.
  2. Planen (plan): Das Werkzeug schreibt einen Änderungsplan als Dateien: Parameter für conf.d, SQL-Korrekturen je Datenbank mit Rückweg als Kommentar und eine Liste der Befunde, die von Hand zu klären sind. Es verändert dabei nichts am Server.
  3. Vergleichen (verify): Vorher-/Nachher-Bericht — ein Befund gilt nur als behoben, wenn genau diese Stelle erneut geprüft wurde.
  4. Ausführen (apply) und zurücknehmen (rollback): zuerst ein Probelauf, dann mit --execute. Sicherung in ein Journal, Prüfung der geänderten Dateien durch den Server selbst, neuer Anmeldetest nach dem Neuladen, automatische Wiederherstellung bei Fehlern. Das Werkzeug ist so angelegt, dass es den Server nie neu startet. Der Anmeldetest prüft die Anmeldung des Werkzeugs, nicht Ihre Anwendungen; rollback überschreibt spätere Änderungen Dritter an denselben Dateien. Auswirkungen vorab in einer Testumgebung prüfen.
  5. Passwortprüfung ohne Anmeldeversuch: Die gespeicherten SCRAM-SHA-256- und md5-Prüfwerte werden für eine kleine, feste Kandidatenliste nachgerechnet, optional ergänzt um bis zu 100 Begriffe des eigenen Betriebs. Ausgegeben wird nur die Rolle — nie das Passwort.
  6. Betriebssystem und Client: check prüft, wenn es auf dem Server selbst läuft, auch Dateirechte von Datenverzeichnis, Konfiguration, TLS-Schlüsseln und Socket sowie das Dienstkonto (Linux und Windows). client prüft ohne Datenbankverbindung den Rechner, von dem aus verbunden wird: Passwortdateien, Umgebung, Skripte, Cron, Dienste. Die Prüfung der Konten anderer Benutzer (--user) braucht eine Berechtigung und bei Beschäftigten eine Rechtsgrundlage.
  7. Rechte-Rolle mit wenig Rechten: Fast alle Regeln laufen auch mit einer Rolle ohne Superuser-Recht; ausgelassene Regeln meldet der Bericht als „übersprungen“.

Datenbanknamen vor anderen Rollen verbergen — und wo das endet

Standardmäßig kann jede angemeldete Rolle alle Datenbank- und Rollennamen lesen (\l, \du, Oberflächen von Datenbank-Werkzeugen) — auch die von Datenbanken, in die sie sich nicht verbinden darf. Das kann bei mehreren Anwendungen oder Mandanten auf einem Server Kundennamen preisgeben. Die Regel db.catalog_visibility entzieht PUBLIC das Leserecht auf acht Systemkataloge, mit Rückweg.

Gemessen in PostgreSQL 14 bis 19rc1:

  • Das Recht gilt je Datenbank einzeln (auch für template1, damit neue Datenbanken es erben).
  • Danach schlagen \l, \du und pg_dump ohne Superuser-Recht fehl, außer die Rolle hat ein eigenes SELECT. Monitoring und Treiber, die diese Kataloge lesen, brauchen vorher ein gezieltes Recht.
  • Der Entzug überstand im Test pg_upgrade (von 17 auf 18 und von 14 auf 19rc1) und die Wiederherstellung eines pg_dumpall; nach jedem Upgrade oder jeder Wiederherstellung trotzdem erneut prüfen. Eine Datenbank, die mit TEMPLATE template0 angelegt wird, trägt den Entzug nicht, erscheint aber beim nächsten Lauf als Befund.
  • Das ist keine Geheimhaltung: Rollennamen lassen sich weiter über ihre Kennung ermitteln, die Fehlermeldung beim Verbinden verrät, ob eine Datenbank existiert, und pg_stat_activity zeigt laufende Sitzungen. Wer Mandanten wirklich trennen muss, betreibt getrennte Cluster.

Beispielausgaben: genau sehen, was entsteht

Im Repository liegen die echten, unbearbeiteten Ausgaben aller Befehle gegen eine Beispielinstanz mit absichtlich schwacher Konfiguration: Bericht als Text und HTML, die Dateien des Änderungsplans, Probelauf, Ausführung mit Journal, Vorher-/Nachher-Vergleich, Rückweg, Regelkatalog, Prüfung des Client-Rechners und der Aussperrschutz. Veröffentlicht ist das nur, weil die Instanz fiktiv ist — echte Berichte sind vertraulich. Ein Skript erzeugt sie jederzeit neu.

Auszug aus dem Bericht (check) — die Befunde stehen nach Schwere sortiert, jede Fundstelle darunter:

BEFUNDE — HOCH (7)
  tls.ssl_enabled               TLS ist eingeschaltet
                                - ssl: ist 'off', erwartet 'on'
  auth.md5_passwords            Keine Rolle hat noch ein MD5-Passwort
                                - reporting: Passwort als MD5-Hash gespeichert
  auth.weak_passwords           Kein Passwort einer anmeldefähigen Rolle stammt aus der Prüfliste
                                (naheliegende Werte, optional Betreiberbegriffe)
                                → Geprüft wurde nur eine kurze Liste naheliegender Werte — das sagt nichts
                                  über die Stärke der übrigen Passwörter.
                                - reporting: Passwort stammt aus der Prüfliste (wird nicht ausgegeben)
                                - shop_app: Passwort stammt aus der Prüfliste (wird nicht ausgegeben)

Auszug aus dem Änderungsplan (harden_shop.sql) — jede Korrektur mit ihrem Rückweg:

-- code.secdef_search_path: public.order_total(p_id bigint)
-- BESTÄTIGEN: ALTER ROUTINE public.order_total(p_id bigint) SET search_path = public, pg_temp;
-- Rückweg: ALTER ROUTINE public.order_total(p_id bigint) RESET search_path;

Und der Aussperrschutz: Die Umstellung von trust auf scram-sha-256 lehnt apply ab, solange Rollen ohne SCRAM-Passwort sich danach nicht mehr anmelden könnten — pg_hba.conf bleibt unverändert:

NICHT AUSGEFÜHRT
  hba.trust                     Rollen ohne SCRAM-Passwort würden sich nicht mehr anmelden können: postgres,
                                reporting — erst Passwörter neu setzen

Alle Beispielausgaben im GitHub-Repository


Getestete Versionen

PostgreSQL Getestet mit
14, 15, 16, 17, 18 Docker, Debian 13
19rc1 (Release Candidate) Docker, Debian 13 — Vorabprüfung
18 Windows 11

Die Testmatrix zeigt, dass das Werkzeug auf diesen Versionen läuft und wo sich die Versionen unterscheiden — nicht, wie gut jede Regel Probleme erkennt. Details stehen in der Versionsmatrix auf GitHub (deutsch).


Schnellstart

Voraussetzung: PHP 8.3 oder neuer mit pdo_pgsql und mbstring. Das Passwort kommt über PGPASSWORD oder die pgpass-Datei, nie über die Kommandozeile.

git clone --branch v0.3.0 https://github.com/glueck-it/pg-harden.git
cd pg-harden
php pg-harden.php check --host=db1 --user=postgres --sslmode=verify-full                       # Bericht im Terminal
php pg-harden.php plan  --host=db1 --user=postgres --sslmode=verify-full --dir=plan-1          # Änderungsplan als Dateien
php pg-harden.php apply --host=db1 --user=postgres --sslmode=verify-full                       # Probelauf: zeigt, was geschähe

Schreibende Läufe (apply --execute, rollback) und die Passwortprüfung verlangen über eine entfernte Verbindung --sslmode=verify-full. Wer mit einer Rolle ohne Superuser-Recht prüfen möchte:

CREATE ROLE pgharden LOGIN;                                 -- der Präfix pg_ ist für Systemrollen reserviert
GRANT pg_monitor TO pgharden;
GRANT EXECUTE ON FUNCTION pg_hba_file_rules() TO pgharden;
GRANT SELECT ON pg_hba_file_rules TO pgharden;
-- nach db.catalog_visibility zusätzlich in jeder Datenbank (sonst bricht der Lauf ab):
-- GRANT SELECT ON TABLE pg_catalog.pg_database, pg_catalog.pg_roles TO pgharden;

Häufige Fragen (FAQ)

Welche PostgreSQL-Versionen werden unterstützt?

Auf Lauffähigkeit geprüft ist pg-harden mit PostgreSQL 14, 15, 16, 17 und 18 sowie mit 19rc1 (Release Candidate) unter Debian 13; unter Windows 11 mit PostgreSQL 18. Die Ausgabe des Werkzeugs und die Versionsmatrix sind deutsch. Regeln für Parameter, die es erst in neueren Versionen gibt, werden bei älteren Versionen übersprungen.

Schreibt das Werkzeug etwas auf den Server?

Die Befehle check, plan, verify, client und rules sind so angelegt, dass sie nichts auf den Server schreiben. Nur apply und rollback verändern den Server, und apply zeigt ohne --execute nur, was es tun würde. Konfigurationsdateien ändert apply nur, wenn es auf dem Server selbst läuft.

Ist pg-harden ein Benchmark-Scanner?

Nein. pg-harden ist keine Umsetzung eines veröffentlichten Benchmarks und ersetzt weder einen solchen noch die Prüfung der eigenen Anforderungen. Es bietet einen Änderungsplan mit Rückweg, die Prüfung des Client-Rechners und einen kontrollierten Ausführungsschritt.

Erfüllt mein System danach eine Norm wie ISO 27001?

Nein. Das Werkzeug liefert technische Prüfergebnisse, die in einem Audit als Beleg dienen können. Eine vorläufige Zuordnung der Regeln zu ISO/IEC 27001:2022 Anhang A liegt bei (die Kennungen sind noch ungeprüft) — sie ist keine Aussage darüber, dass eine Anforderung erfüllt ist. Ein Lauf ohne Befund heißt nur, dass die Regeln des Katalogs nichts gefunden haben.

Was passiert mit den Berichten?

Berichte können Rollen-, Objekt- und Netznamen enthalten, die auf Personen bezogen sein können. Sie sind vertraulich zu behandeln, nur zur Behebung zu verwenden und nach Ablauf einer vorab festgelegten Aufbewahrungsfrist zu löschen; wer sie als Audit-Beleg aufhebt, beschränkt den Zugriff. Wo Rollen Beschäftigten zugeordnet sind, sind Datenschutz und Mitbestimmung zu beachten.

Wo finde ich Quellcode und Dokumentation?

Das vollständige Projekt mit Changelog, Tests und Dokumentation auf Deutsch und Englisch liegt auf GitHub: https://github.com/glueck-it/pg-harden.


Passende Seminare & Beratung

Die Prüfung ist der erste Schritt. In den Seminaren geht es um den sicheren und stabilen Betrieb von PostgreSQL: