11 Juli 2025

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

PostgreSQL trifft auf OAuth2Mit 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 PostgreSQL®
Tags: OAuth2 PostgreSQL®

FA

über den Autor

Felix Alipaz-Dicke


Beitrag teilen: