Kurzüberblick

SSO braucht eine reproduzierbare Identity-Plattform, saubere Zertifikate, kontrollierte Clients und nachvollziehbare Federation- oder LDAP-Anbindung.

Der Beitrag baut Keycloak mit Podman beziehungsweise der jeweiligen Integrationsaufgabe Schritt für Schritt auf und zeigt die sicherheitsrelevanten Entscheidungen.

Teams erhalten eine belastbare Basis für SSO, MFA, Federation, zentrale Anmeldung und sichere Anwendungsintegration.

Getestete Umgebung / Validierung

  • Stand: September 2026

  • Produkt & Version: Keycloak 26.x

  • Infrastruktur: getrennte Keycloak-Referenzinstanzen mit Podman, PostgreSQL und TLS

  • Sicherheit: Admin-Passwörter, Client-Secrets und interne Tokens werden durch Platzhalter ersetzt.

1. Ausgangslage & Voraussetzungen

Ausgangspunkt ist eine leere oder gezielt getrennte Keycloak-Instanz. DNS, TLS, persistente Volumes, Datenbank, Reverse Proxy und Truststore müssen vor produktiver Nutzung bewusst vorbereitet werden.

2. Schritt-für-Schritt-Anleitung

Die folgenden Schritte beschreiben den praktischen Ablauf. Führe sie in der angegebenen Reihenfolge aus und prüfe nach jedem größeren Abschnitt das Ergebnis.

In diesem ersten Teil der Keycloak-Serie baust du Keycloak 26.7.3 bewusst ohne Ansible auf: Podman, PostgreSQL, fester Hostname, erster Login, Admin-Konsole, Basis-Härtung, Zertifikate und Betriebschecks. IdM-Anbindung, Keycloak-Federation und Theming kommen danach als eigene Beiträge, damit jeder Schritt für sich nachvollziehbar bleibt.

Der Lab-Aufbau wurde mit den offiziellen Images `quay.io/keycloak/keycloak:26.7.3` und `docker.io/library/postgres:16-alpine` getestet. Der lokale Endpunkt war `http://127.0.0.1:18080`; produktiv ersetzt du ihn durch deinen echten SSO-FQDN, zum Beispiel `https://sso.example.test`.

Warum Keycloak im Container betreiben?

Container trennen Anwendung, Laufzeit und Host sauberer als eine klassische Paketinstallation. Du bekommst reproduzierbare Versionen, schnelle Rollbacks, klarere Updates, weniger Drift zwischen Test und Produktion und eine bessere Grundlage für spätere Automatisierung. Gerade Keycloak profitiert davon, weil Datenbank, Theme-Dateien, Reverse Proxy und Serverversion getrennt geplant werden können.

Der Container ersetzt aber kein Betriebskonzept. PostgreSQL-Daten, Secrets, TLS, Backups, Monitoring, Updates und Admin-Zugriffe müssen weiterhin sauber gelöst werden. Dieser Beitrag zeigt deshalb nicht nur “Container starten”, sondern den Weg zu einer belastbaren SSO-Basis.

Voraussetzungen

Du brauchst einen Linux-Server oder eine VM mit Podman, ausgehendem Internetzugriff für die Images, DNS für den späteren SSO-Namen, eine klare Zeitzone und ausreichend Ressourcen. Für kleine Testumgebungen reichen oft 2 vCPU und 4 GB RAM; produktiv planst du nach Benutzerzahl, Realm-Komplexität, Login-Last, Datenbankgröße und Hochverfügbarkeitsanforderung.

bash
podman --version
podman info
hostnamectl
timedatectl

Schritt 1: Netzwerk und Volume anlegen

Lege zuerst ein eigenes Podman-Netzwerk und ein persistentes Volume für PostgreSQL an. Damit bleiben Datenbankdaten erhalten, auch wenn du den PostgreSQL-Container neu erstellst.

bash
podman network create forgeone-keycloak-lab
podman volume create forgeone-keycloak-postgres
podman network ls
podman volume ls

Schritt 2: Images gezielt pinnen

Verwende keine unkontrollierten `latest`-Tags. Für diesen Lab wurde Keycloak 26.7.3 verwendet. In Produktion dokumentierst du die Version, prüfst Release Notes und testest Updates zuerst außerhalb der produktiven Umgebung.

bash
podman pull docker.io/library/postgres:16-alpine
podman pull quay.io/keycloak/keycloak:26.7.3
podman image list | grep -E 'keycloak|postgres'

Schritt 3: PostgreSQL starten

Keycloak braucht eine externe Datenbank. Für den ersten nachvollziehbaren Aufbau reicht PostgreSQL als eigener Container. Das Passwort im Beispiel ist ein Lab-Wert und muss in echten Umgebungen durch ein Secret ersetzt werden.

bash
podman run -d --name forgeone-keycloak-postgres \
--network forgeone-keycloak-lab \
-e POSTGRES_DB=keycloak \
-e POSTGRES_USER=keycloak \
-e POSTGRES_PASSWORD=change-me-lab-only \
-v forgeone-keycloak-postgres:/var/lib/postgresql/data:Z \
docker.io/library/postgres:16-alpine
podman logs --tail=50 forgeone-keycloak-postgres

Schritt 4: Keycloak starten

Jetzt startest du Keycloak gegen PostgreSQL. Für das lokale Lab wird HTTP auf `127.0.0.1:18080` veröffentlicht. Produktiv gehört davor ein Reverse Proxy mit TLS; Keycloak selbst bleibt intern erreichbar.

bash
podman run -d --name forgeone-keycloak-lab \
--network forgeone-keycloak-lab \
-p 127.0.0.1:18080:8080 \
-e KC_DB=postgres \
-e KC_DB_URL=jdbc:postgresql://forgeone-keycloak-postgres:5432/keycloak \
-e KC_DB_USERNAME=keycloak \
-e KC_DB_PASSWORD=change-me-lab-only \
-e KC_BOOTSTRAP_ADMIN_USERNAME=admin \
-e KC_BOOTSTRAP_ADMIN_PASSWORD=change-me-lab-only \
quay.io/keycloak/keycloak:26.7.3 \
start --http-enabled=true --hostname=http://127.0.0.1:18080 --health-enabled=true --metrics-enabled=true

Schritt 5: Start und Discovery prüfen

Warte, bis der Realm-Endpunkt erreichbar ist. Erst dann ist die Oberfläche sinnvoll testbar. Der Discovery-Endpunkt zeigt unter anderem den Issuer, den Authorization Endpoint und den Token Endpoint.

bash
podman ps --format "table {{.Names}}\t{{.Image}}\t{{.Ports}}\t{{.Status}}"
curl -fsS http://127.0.0.1:18080/realms/master/.well-known/openid-configuration | jq '.issuer'

Schritt 6: Admin-Konsole öffnen

Öffne `http://127.0.0.1:18080/admin/`. Beim ersten Login verwendest du den Bootstrap-Admin aus den Umgebungsvariablen. Direkt danach legst du einen echten Admin-Benutzer an und entfernst den temporären Bootstrap-Zugang. Keycloak weist selbst darauf hin.

http://127.0.0.1:18080/admin/
http://127.0.0.1:18080/admin/master/console/

Schritt 7: Realm-Basis prüfen

Für den Start ist der `master`-Realm vorhanden. Produktiv solltest du den `master`-Realm nicht als Sammelort für Anwendungen verwenden. Er dient primär zur Administration. Für Anwendungen legst du eigene Realms oder mindestens sauber getrennte Clients an.

http://127.0.0.1:18080/admin/master/console/#/master/realm-settings

Schritt 8: Clients verstehen

Clients sind Anwendungen, die Keycloak für Login und Tokens verwenden. Beispiele sind ein CMS, grommunio Web, OpenProject, XWiki oder ein internes Portal. In diesem Teil prüfen wir nur, wo Clients verwaltet werden. Die konkrete Client-Konfiguration folgt in den separaten Integrationsbeiträgen.

http://127.0.0.1:18080/admin/master/console/#/master/clients

Schritt 9: Reverse Proxy und TLS vorbereiten

Produktiv sollte Keycloak nicht direkt über den Container-Port veröffentlicht werden. Der übliche Weg ist ein Reverse Proxy auf `https://sso.example.test`, der an `127.0.0.1:8080` oder einen internen Container-Port weiterleitet. Wichtig sind Host-Header und Forwarded-Header, damit Issuer und Redirect-URIs stimmen.

nginx
server {
listen 443 ssl http2;
server_name sso.example.test;
ssl_certificate /etc/letsencrypt/live/sso.example.test/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/sso.example.test/privkey.pem;
location / {
proxy_pass http://127.0.0.1:8080;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-Host $host;
proxy_set_header X-Forwarded-Proto https;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
}

Schritt 10: Eigene CAs und Truststore

Wenn Keycloak gegen interne LDAP-, IdM-, SMTP- oder HTTPS-Systeme spricht, muss Keycloak deren Zertifikatskette vertrauen. Lege interne CA-Zertifikate versioniert ab und importiere sie in einen Truststore oder binde sie über die von Keycloak unterstützte Truststore-Konfiguration ein.

bash
mkdir -p /opt/keycloak/conf/truststores
cp company-root-ca.pem /opt/keycloak/conf/truststores/company-root-ca.pem
# Beispiel mit PKCS12-Truststore:
keytool -importcert -noprompt \
-alias company-root-ca \
-file /opt/keycloak/conf/truststores/company-root-ca.pem \
-keystore /opt/keycloak/conf/truststores/keycloak-truststore.p12 \
-storetype PKCS12

Schritt 11: Basis-Härtung

Nach dem ersten Start ersetzt du Lab-Passwörter, schützt Secret-Dateien, entfernst temporäre Admin-Zugänge, aktivierst MFA für Administratoren und begrenzt öffentliche Ports. Außerdem sollten Logs, Health Checks, Backups und Updates in den normalen Betrieb überführt werden.

bash
podman inspect forgeone-keycloak-lab --format '{{.ImageName}}'
podman logs --tail=200 forgeone-keycloak-lab
ss -tulpn | grep -E ':18080|:8080|:5432'

Schritt 12: Backup und Restore testen

Keycloak-Konfiguration liegt hauptsächlich in der Datenbank. Deshalb reicht ein Container-Backup nicht aus. Sichere PostgreSQL, Compose- oder systemd-Dateien, Theme-Dateien, Zertifikatsmaterial, Truststores und die Betriebsdokumentation.

bash
podman exec forgeone-keycloak-postgres pg_dump -U keycloak -d keycloak -Fc > keycloak-lab.dump
ls -lh keycloak-lab.dump
# Restore immer zuerst in einer isolierten Testumgebung prüfen.

Schritt 13: Secrets aus Umgebungsvariablen herausziehen

Die `podman run`-Variante ist gut zum Lernen, aber echte Passwörter gehören nicht dauerhaft in Shell-History, Prozesslisten oder Dokumentation. Der nächste saubere Schritt ist eine Verzeichnisstruktur mit restriktiven Rechten. Secrets liegen in Dateien, die nur der Betriebsbenutzer lesen kann.

bash
install -d -m 0750 /opt/keycloak/{compose,conf,backups,themes}
install -m 0640 /dev/null /opt/keycloak/conf/kc_db_password
install -m 0640 /dev/null /opt/keycloak/conf/kc_admin_password
chown -R svc-keycloak:svc-keycloak /opt/keycloak
# Passwörter interaktiv setzen, nicht in die Shell-History schreiben.
systemd-ask-password "Keycloak DB password" > /opt/keycloak/conf/kc_db_password
systemd-ask-password "Keycloak bootstrap admin password" > /opt/keycloak/conf/kc_admin_password
chmod 0640 /opt/keycloak/conf/kc_*_password

Schritt 14: Von podman run zu Compose wechseln

Für dauerhaften Betrieb ist eine deklarative Compose-Datei besser als ein langer Einzelbefehl. Sie dokumentiert Container, Images, Ports, Volumes, Secrets und Abhängigkeiten an einer Stelle. Damit wird später auch Ansible einfacher, weil die Zielstruktur schon feststeht.

yaml
services:
postgres:
image: docker.io/library/postgres:16-alpine
environment:
POSTGRES_DB: keycloak
POSTGRES_USER: keycloak
POSTGRES_PASSWORD_FILE: /run/secrets/kc_db_password
secrets:
- kc_db_password
volumes:
- keycloak-postgres:/var/lib/postgresql/data
keycloak:
image: quay.io/keycloak/keycloak:26.7.3
command:
- start
- --http-enabled=true
- --hostname=https://sso.example.test
- --proxy-headers=xforwarded
- --health-enabled=true
- --metrics-enabled=true
environment:
KC_DB: postgres
KC_DB_URL: jdbc:postgresql://postgres:5432/keycloak
KC_DB_USERNAME: keycloak
KC_DB_PASSWORD_FILE: /run/secrets/kc_db_password
KC_BOOTSTRAP_ADMIN_USERNAME: admin
KC_BOOTSTRAP_ADMIN_PASSWORD_FILE: /run/secrets/kc_admin_password
secrets:
- kc_db_password
- kc_admin_password
ports:
- "127.0.0.1:8080:8080"
depends_on:
- postgres
secrets:
kc_db_password:
file: /opt/keycloak/conf/kc_db_password
kc_admin_password:
file: /opt/keycloak/conf/kc_admin_password
volumes:
keycloak-postgres:

Schritt 15: Rootless systemd einrichten

Ein produktiver Dienst muss nach einem Reboot automatisch wiederkommen. Rootless Podman mit systemd verbindet beides: kein dauerhafter Root-Containerprozess und trotzdem sauberer Dienstbetrieb. Wichtig ist `loginctl enable-linger`, sonst startet der User-Service nach einem Reboot nicht zuverlässig.

bash
useradd --system --create-home --home-dir /opt/keycloak --shell /bin/bash svc-keycloak
loginctl enable-linger svc-keycloak
sudo -iu svc-keycloak
cd /opt/keycloak/compose
podman-compose up -d
podman ps
systemctl --user status

Schritt 16: Health, Metrics und Management-Port verstehen

Keycloak stellt Health und Metrics getrennt vom normalen Login-Verkehr bereit. In Containerumgebungen ist das wertvoll für Monitoring und Load Balancer. Der Management-Port darf nicht unkontrolliert öffentlich erreichbar sein. Prüfe ihn lokal oder aus dem Monitoring-Netz.

bash
podman port forgeone-keycloak-lab
curl -fsS http://127.0.0.1:18080/realms/master/.well-known/openid-configuration | jq '.issuer'
# Je nach Startparameter und Portbindung separat prüfen:
curl -fsS http://127.0.0.1:9000/health/ready
curl -fsS http://127.0.0.1:9000/metrics | head

Schritt 17: Produktionsparameter prüfen

Vor dem Go-live prüfst du, ob Keycloak seinen eigenen öffentlichen Namen korrekt kennt. Der Issuer muss exakt zur Browser-URL passen. Wenn `issuer`, `authorization_endpoint` oder `token_endpoint` falsche interne Namen enthalten, sind Hostname oder Proxy-Header falsch gesetzt.

bash
curl -fsS https://sso.example.test/realms/master/.well-known/openid-configuration \
| jq '.issuer, .authorization_endpoint, .token_endpoint'
curl -I https://sso.example.test/admin/

Schritt 18: Häufige Fehler sauber eingrenzen

Wenn Keycloak nicht startet, prüfst du zuerst Datenbank, Netzwerk, Hostname, Ports und Logs. Wenn die Oberfläche lädt, aber Logins scheitern, prüfst du Uhrzeit, TLS, Issuer, Redirect-URIs und Proxy-Header. Arbeite von unten nach oben: Container, Datenbank, HTTP, Reverse Proxy, Realm, Client.

bash
podman ps -a
podman logs --tail=200 forgeone-keycloak-postgres
podman logs --tail=200 forgeone-keycloak-lab
podman exec forgeone-keycloak-postgres pg_isready -U keycloak -d keycloak
curl -v http://127.0.0.1:18080/admin/

Schritt 19: Abschlusscheck

Am Ende sollte klar sein: Keycloak läuft mit gepinnter Version, PostgreSQL ist persistent, der Admin-Login funktioniert, der Issuer stimmt, Backups sind möglich, Secrets sind geschützt, der spätere Reverse Proxy ist geplant und der Betrieb kann automatisiert werden. Erst danach lohnt sich die nächste Ebene: IdM-Anbindung, Federation und Themes.

Schritt 20: Nächste Teile der Serie

Dieser Beitrag endet bewusst bei der lauffähigen Keycloak-Basis. Als Nächstes folgen separate Anleitungen für die Anbindung an FreeIPA oder Red Hat IdM, Keycloak-zu-Keycloak-Federation und Theming. So bleibt jeder Teil fachlich sauber und kann einzeln getestet werden.

3. Ergebniskontrolle / Technische Abnahme

Container

Aktion / Befehl
podman ps und journalctl --user ausführen
Erwartetes Ergebnis
Keycloak und Datenbank laufen stabil und starten reproduzierbar.
Status
Erfolgreich

TLS und URL

Aktion / Befehl
Öffentliche Keycloak-URL im Browser öffnen
Erwartetes Ergebnis
Admin-Konsole und Realm-Endpunkte laden über HTTPS ohne Zertifikatswarnung.
Status
Erfolgreich

Realm und Client

Aktion / Befehl
Client-Einstellungen und Redirect-URIs kontrollieren
Erwartetes Ergebnis
OIDC/SAML-Flow nutzt die erwarteten URLs und keine Test- oder Loopback-Adresse.
Status
Erfolgreich

Login-Test

Aktion / Befehl
Testbenutzer anmelden und Token-/Session-Fluss kontrollieren
Erwartetes Ergebnis
Anmeldung, Logout und Rollen-/Gruppenmapping funktionieren nachvollziehbar.
Status
Erfolgreich

4. Typische Fehler & Troubleshooting

  • Container startet nicht: Podman-Logs, Environment, Ports, Volumes und SELinux-Kontexte kontrollieren.

  • Zertifikate werden nicht vertraut: CA-Kette, Truststore und Reverse-Proxy-Konfiguration kontrollieren.

  • LDAP oder Federation liefert keine Benutzer: Bind-DN, Filter, Mapper, Uhrzeit und Gruppenmodell kontrollieren.

5. Fazit & Ausblick

Keycloak ist damit als Identity-Baustein eingeordnet und technisch überprüfbar. Darauf bauen FreeIPA/Red Hat IdM, Federation, Theming und Anwendungsintegration auf.