11 Juli 2025

PostgreSQL 18 trifft OAuth2: So funktioniert die native Unterstützung mit Keycloak

Mit der Veröffentlichung der Beta-Version von PostgreSQL 18 wurde
eine spannende neue Funktion eingeführt: native Unterstützung für
OAuth2. Da ich im Netz weder eine Anleitung noch einen Blogbeitrag
gefunden habe, der zeigt, wie man diese Funktion nutzt, habe ich aus
Neugier beschlossen, es selbst auszuprobieren.

Ich habe ein neues Projektverzeichnis angelegt und mit dem
Experimentieren begonnen.

Umgebung und Zielsetzung

Ziel war es, PostgreSQL 18 Beta mit OAuth2-Authentifizierung
einzurichten, für den Identity Provider habe ich Keycloak gewählt.

Ich habe mich dazu entschieden Docker Compose zu verwenden, um beide
Dienste schnell und unkompliziert hoch fahren zu können.

Docker-Compose-Konfiguration

Hier ist das docker-compose.yml, das ich verwendet
habe:

services:
  mock-oauth2:
    image: quay.io/keycloak/keycloak:24.0
    command: start --https-port=8080 --https-key-store-file=/etc/x509/https/localhost.p12 --https-key-store-password=changeit --import-realm --hostname-strict=false --hostname-url=https://mock-oauth2:8080
    ports:
      - "8080:8080"
    environment:
      KEYCLOAK_ADMIN: admin
      KEYCLOAK_ADMIN_PASSWORD: admin
    volumes:
      - ./certs:/etc/x509/https
      - ./keycloak-realm.json:/opt/keycloak/data/import/realm.json
    networks:
      - pgnet

  postgres18:
    build: .
    ports:
      - "5432:5432"
    environment:
      POSTGRES_PASSWORD: postgres
    volumes:
      - ./postgres/postgresql.conf:/etc/postgresql/postgresql.conf
      - ./postgres/pg_hba.conf:/etc/postgresql/pg_hba.conf
    command: ["-c", "config_file=/etc/postgresql/postgresql.conf"]
    networks:
      - pgnet

networks:
  pgnet:
    driver: bridge

PostgreSQL erwartet eine Verbindung zum OAuth2-Issuer über HTTPS.
Dieselbe URL muss auch über den Host erreichbar sein, etwa bei der
Nutzung des Keycloak-UI. Das bedeutet: Das Zertifikat muss sowohl auf
dem Host als auch im Container gültig und vertrauenswürdig sein.

Der verwendete Hostname (z. B. https://mock-oauth2:8080)
muss in beiden Umgebungen korrekt auflösbar sein.

Dazu habe ich folgende Zeile in meiner /etc/hosts-Datei
auf dem Host ergänzt:

127.0.0.1 mock-oauth2

So konnten sowohl der PostgreSQL-Container als auch mein Host den
Keycloak-Service unter https://mock-oauth2:8080
erreichen.

TLS-Zertifikat für Keycloak

Keycloak benötigt zwingend einen HTTPS-Endpunkt, damit die
OAuth2-Issuer-URL von PostgreSQL akzeptiert wird.

Dafür habe ich ein selbstsigniertes Zertifikat erstellt und es in ein
.p12-Keystore-Paket umgewandelt, das Keycloak verwenden
kann.

Das .p12-Zertifikat wird über folgenden Mount in den
Container eingebunden:

volumes:
  - ./certs:/etc/x509/https

Im certs-Verzeichnis liegt die Datei
localhost.p12, welche ich aus meinem selbstsignierten
Schlüssel und Zertifikat folgendermaßen erstellt habe:

openssl req -x509 -nodes -days 365 \
  -newkey rsa:2048 \
  -keyout server.key \
  -out server.crt \
  -subj "/CN=mock-oauth2" \
  -addext "subjectAltName = DNS:mock-oauth2,DNS:localhost,IP:127.0.0.1"

Keycloak-Realm-Konfiguration

Ich habe eine minimalistische Realm-Datei für Keycloak erstellt. Sie
enthält einen Client namens postgres und einen Benutzer mit
entsprechenden Anmeldedaten.

Inhalt von keycloak-realm.json:

{
  "realm": "pg",
  "enabled": true,
  "clients": [
    {
      "clientId": "postgres",
      "enabled": true,
      "publicClient": false,
      "redirectUris": ["*"],
      "protocol": "openid-connect",
      "secret": "postgres",
      "directAccessGrantsEnabled": true,
      "standardFlowEnabled": true
    }
  ],
  "users": [
    {
      "username": "postgres",
      "enabled": true,
      "credentials": [
        {
          "type": "password",
          "value": "postgres"
        }
      ]
    }
  ]
}

Nach dem Import des Realms war Keycloak bereit und der Standard-Scope
im UI sichtbar.

Installation
von libpq-oauth und oauth_validator

Die offizielle PostgreSQL-Image musste ich erweitern, um zusätzliche
Abhängigkeiten wie die Erweiterung libpq-oauth sowie den
Validator oauth_validator zu installieren.

PostgreSQL 18 unterstützt OAuth2-Authentifizierung experimentell.
Allerdings liefert PostgreSQL keine eigene
Validator-Bibliothek
mit. In der offiziellen Dokumentation
heißt es:

Die PostgreSQL-Distribution enthält keine Bibliotheken zur
Validierung von OAuth2-Token. Benutzer müssen eine eigene Lösung
bereitstellen oder selbst kompilieren.

PostgreSQL
Docs – oauth_validator_libraries

Für Tests habe ich folgende Open-Source-Implementierung
verwendet:

github.com/TantorLabs/oauth_validator

Diese minimalistische C-Bibliothek kann kompiliert und als
oauth_validator_library in PostgreSQL verwendet werden.

Verwendetes Dockerfile

FROM postgres:18beta1

USER root

RUN apt-get update \
    && apt-get install -y libpq-oauth build-essential libkrb5-dev \
       libsasl2-dev libcurl4-openssl-dev postgresql-server-dev-18 git \
    && git clone https://github.com/TantorLabs/oauth_validator.git /tmp/oauth_validator \
    && cd /tmp/oauth_validator \
    && make && make install \
    && rm -rf /tmp/oauth_validator \
    && apt-get remove -y build-essential git \
    && apt-get autoremove -y && rm -rf /var/lib/apt/lists/*

Dieses Image habe ich dann für den `postgres18`-Service in meinem
Docker-Compose-Setup verwendet.

PostgreSQL mit
der Keycloak-CA vertrauen lassen

PostgreSQL muss dem von Keycloak präsentierten Zertifikat vertrauen,
sonst wird die Verbindung zum OAuth2-Issuer abgelehnt.

Dazu habe ich die Datei `mock-oauth.crt` in den PostgreSQL-Container
kopiert und im typischen CA-Pfad abgelegt:

/usr/local/share/ca-certificates/

Dann habe ich innerhalb des Containers folgendes Kommando
ausgeführt:

update-ca-certificates

Danach wurde das Zertifikat akzeptiert und PostgreSQL konnte die
Verbindung zum HTTPS-Issuer erfolgreich überprüfen.

PostgreSQL-Konfiguration

In pg_hba.conf habe ich folgende Zeile ergänzt:

host all all all oauth scope="profile" issuer="https://mock-oauth2:8080/realms/pg" map="oauthmap"

In pg_ident.conf habe ich die vom Token bereitgestellte
Identität dem PostgreSQL-Benutzer zugeordnet:

oauthmap "postgresID" "postgres"

Diese Zuordnung muss ggf. angepasst werden – abhängig davon, wie dein
Keycloak-Client konfiguriert ist und welches Feld (z. B.
preferred_username oder sub) im Token
übergeben wird.

## Verbindungstest mit OAuth2

Zum Testen der Verbindung habe ich folgenden `psql`-Befehl
verwendet:

psql "host=localhost \
      port=5432 \
      dbname=postgres \
      user=postgres \
      oauth_issuer=https://mock-oauth2:8080/realms/pg \
      oauth_client_id=postgres \
      oauth_client_secret=changeme \
      oauth_scope=profile"

Nach dem Aufruf erscheint eine Device-Code-Meldung wie:

Besuchen Sie `https://mock-oauth2:8080/realms/pg/device` und geben
Sie den Code FBAD-XXYZ ein.

Nach Anmeldung mit den Benutzeranmeldedaten stellt `psql` erfolgreich
eine Verbindung zu PostgreSQL über OAuth2 her.

Erkenntnisse und Tipps

  • PostgreSQL 18 verlangt HTTPS für die
    OAuth2-Issuer-URL – selbst im lokalen Setup.
  • pg_hba.conf ist empfindlich gegenüber
    Formatierungsfehlern. Ich musste die Konfiguration mehrfach neu laden
    (SELECT pg_reload_conf();) und die Logs genau
    analysieren.
  • Um einer lokalen Zertifizierungsstelle zu vertrauen, reicht es, das
    .crt-Zertifikat in den Container zu kopieren und mit
    update-ca-certificates zu registrieren.
  • Keycloak eignet sich gut für Tests mit OAuth2, aber man muss evtl.
    mit Scopes, Claims und Secrets experimentieren, bis alles mit PostgreSQL
    zusammenpasst.

Fazit

Das war ein spannendes, praxisnahes Experiment mit einer
vielversprechenden neuen Funktion in PostgreSQL.
OAuth2-Integration bringt PostgreSQL näher an moderne
Identity-Management-Lösungen heran und vereinfacht den Betrieb in
Umgebungen mit zentralisierter Authentifizierung.

Kategorien: credativ® Inside

FA

über den Autor

Felix Alipaz-Dicke


Beitrag teilen: