Worum geht’s
In den meisten Unternehmen ist Active Directory die Source of Truth für Identitäten, moderne Anwendungen erwarten aber OpenID Connect oder SAML. Keycloak schließt diese Lücke: Es föderiert das bestehende AD per LDAPS, wird zum zentralen Identity Provider für alle Anwendungen und legt MFA darüber, ohne dass AD umgebaut werden muss.
Spannend wird es, wenn nicht drei, sondern dreihundert Anwendungen dazukommen. Dann entscheidet nicht mehr die LDAP-Konfiguration über den Erfolg, sondern die Frage, wie Teams schnell und sicher an ihre OIDC-Clients kommen, ohne für jeden Client ein Ticket beim IAM-Team zu öffnen. Dieser Leitfaden zeigt beides: die AD-Anbindung, wie ich sie in Produktion aufbaue, und eine Client-Factory, über die Teams ihre Clients selbst verwalten. Alle Pfade beziehen sich auf Keycloak 26.
Das Wichtigste in Kürze
- Ein zentraler Realm mit AD-Anbindung, MFA und Rollenmodell, einmal sauber gebaut und von allen Anwendungen genutzt.
- Ausfallsicher: LDAPS gegen mindestens zwei Domain Controller, Nested Groups löst der DC selbst auf.
- MFA ohne Umbau in AD: OTP, Security Keys oder Passkeys, gesteuert über AD-Gruppen.
- Self-Service statt Tickets: Teams beschreiben ihre OIDC-Clients in Git, eine Pipeline legt sie per Terraform an.
- Leitplanken im Realm: Client Policies erzwingen PKCE, erlaubte Redirect-Domains und schlanke Tokens, egal wer den Client anlegt.
Architektur auf einen Blick
- Anwendungen sprechen ausschließlich OIDC oder SAML mit Keycloak. LDAP und AD bleiben für sie unsichtbar.
- Keycloak authentifiziert, führt die Authentication Flows inklusive MFA aus und stellt Tokens mit den passenden Claims aus.
- Active Directory bleibt das User-Verzeichnis. Passwörter prüft Keycloak per LDAP-Bind direkt am DC und importiert sie nie. Ein IGA-System wie Saviynt, SailPoint oder OpenText Identity Manager kann den Lifecycle der Identitäten verantworten.
Active Directory anbinden: fünf Entscheidungen, die zählen
Der LDAP Provider ist in einer Stunde konfiguriert. Ob er jahrelang stabil läuft, entscheiden diese fünf Punkte.
1. LDAPS gegen mindestens zwei Domain Controller
User federation → Add LDAP providers
Vendor: Active Directory
Connection URL: ldaps://dc1.example.com:636 ldaps://dc2.example.com:636
Use Truststore SPI: Always
Connection pooling: On
Connection timeout: 3000
Bind DN: CN=svc-keycloak,OU=Service Accounts,DC=example,DC=com
Bind credentials: ${vault.ldap_credential}
- DCs nur durch Leerzeichen trennen. Keycloak probiert sie von links nach rechts, der
Connection timeoutgilt pro nicht erreichbarem DC. Mit 3000 ms bleibt das Failover zügig. - Truststore: Die AD-Root-CA als PEM nach
conf/truststoreslegen oder überKC_TRUSTSTORE_PATHSeinbinden. Der FQDN aus der Connection URL muss im SAN der DC-Zertifikate stehen. - Vorher testen: Was mit
ldapsearchvom Keycloak-Host funktioniert, funktioniert auch in Keycloak.
LDAPTLS_CACERT=/etc/pki/ad-root-ca.pem ldapsearch -LLL -H ldaps://dc1.example.com:636 \
-D 'CN=svc-keycloak,OU=Service Accounts,DC=example,DC=com' -W \
-b 'OU=Users,DC=example,DC=com' '(sAMAccountName=jdoe)' mail memberOf
2. Vendor, Edit Mode und Username vor dem ersten Speichern
Vendor Active Directory ist der wichtigste Klick im ganzen Setup. Keycloak setzt damit die AD-Defaults (objectGUID, Object Classes) und legt die passenden Mapper an, allen voran MSAD account controls. Weil die Mapper aus Vendor, Edit Mode und Username-Attribut entstehen, gehören diese drei Werte ins erste Speichern:
| Edit Mode | Wann | Passwortänderung |
|---|---|---|
READ_ONLY | Ein IGA oder ein bestehendes Self-Service-Portal verantwortet den Lifecycle. | außerhalb von Keycloak |
WRITABLE | Die Keycloak Account Console wird zum Self-Service. | per LDAPS direkt nach AD |
Als Username LDAP attribute passt sAMAccountName für Logins wie jdoe, userPrincipalName für Logins im E-Mail-Format.
3. Den Scope per LDAP-Filter schneiden
Statt das halbe Verzeichnis zu importieren, holt ein Filter genau die User, die Zugriff haben sollen, inklusive verschachtelter Gruppen:
(&(objectCategory=person)(memberOf:1.2.840.113556.1.4.1941:=CN=APP-Keycloak-Users,OU=Groups,DC=example,DC=com))
1.2.840.113556.1.4.1941 ist LDAP_MATCHING_RULE_IN_CHAIN: Der DC löst die transitive Mitgliedschaft serverseitig auf. Dazu Search scope: Subtree und Pagination: On, denn AD liefert pro Anfrage maximal 1000 Einträge.
4. Sync und Cache
Periodic changed users sync: 3600 # stündlich
Periodic full sync: 86400 # nachts
Cache policy: MAX_LIFESPAN
Max lifespan: 180000 # 3 Minuten
Der nächtliche Full Sync hat einen konkreten Grund: Kommt ein User in AD in eine Gruppe, ändert sich das Gruppenobjekt, nicht das User-Objekt. Wer über den memberOf-Filter neu in den Scope fällt, erscheint deshalb erst beim Full Sync oder beim ersten Login. Der Cache mit drei Minuten Lebensdauer hält die Last auf den DCs klein, und Änderungen sind trotzdem planbar schnell sichtbar.
5. Deaktivierte Accounts zuverlässig sperren
Der Mapper MSAD account controls übersetzt userAccountControl in Keycloak-Verhalten: Ein in AD deaktivierter Account ist in Keycloak disabled. Mit Always Read Enabled Value From LDAP: On gilt das auch für Logins ohne Passwort-Bind, etwa mit Passkeys. In WRITABLE führt ein abgelaufenes AD-Passwort direkt zur Required Action Update Password.
Gruppen und Rollen aus AD
Ein group-ldap-mapper importiert die relevanten AD-Gruppen nach /ad:
LDAP Groups DN: OU=Groups,DC=example,DC=com
LDAP Filter: (cn=APP-*)
Preserve Group Inheritance: Off
User Groups Retrieve Strategy: LOAD_GROUPS_BY_MEMBER_ATTRIBUTE_RECURSIVELY
Groups Path: /ad
Mode: READ_ONLY
Die rekursive Strategie löst Nested Groups direkt auf dem DC auf. Preserve Group Inheritance: Off verhindert, dass Gruppen mit mehreren Eltern den Sync stoppen, und der LDAP Filter hält tausende irrelevante Gruppen draußen.
Daraus wird ein sauberes Rollenmodell: Die AD-Gruppe APP-Admins erscheint als /ad/APP-Admins, an der Gruppe hängt die Rolle app-admin. Die Mitgliedschaft wird in AD und den bestehenden Genehmigungsprozessen gepflegt, die Berechtigung in Keycloak. Im Token landen Rollen in realm_access.roles, Gruppen über einen Client Scope groups mit Group Membership Mapper:
{
"preferred_username": "jdoe",
"groups": ["APP-Admins", "APP-Users"],
"realm_access": { "roles": ["app-admin"] }
}
MFA, gesteuert über AD-Gruppen
Hier liegt der größte Mehrwert von Keycloak vor AD: eine MFA-Schicht für alle Anwendungen, ob OIDC oder SAML, ohne MFA-Infrastruktur in AD.
Authentication → browser → Action → Duplicatealsbrowser-mfa.- Im
forms-Subflow einen SubflowMFA enforcement(Conditional) anlegen:Condition - User Roleauf die Rollemfa-required,Condition - sub-flow executedauf den 2FA-Subflow mitnot-executed, darunterOTP Formals Required. Die zweite Condition verhindert, dass User mit bereits eingerichtetem OTP doppelt gefragt werden. - Die AD-Gruppe
APP-MFA-Requiredper Group Mapper importieren und anmfa-requiredbinden. Action → Bind flow → Browser flow.
Damit läuft der MFA-Rollout über die AD-Gruppenpflege, Abteilung für Abteilung, ohne einen Klick in Keycloak. Passkeys (Webauthn Register Passwordless) und Recovery Codes als Fallback ergänzt du im selben Flow. Die Brute Force Detection stellst du unter die Lockout-Schwelle von AD, damit Password-Spraying über die Login-Seite keine AD-Accounts sperren kann.
Client-Factory: Teams verwalten ihre OIDC-Clients selbst
Ein zentraler Realm entfaltet seinen Wert erst, wenn neue Anwendungen schnell andocken können. Der klassische Weg ist ein Ticket an das IAM-Team, eine manuelle Anlage in der Admin Console und ein Client Secret per Chat. Das skaliert nicht und ist das Gegenteil von sicher.
Die Lösung ist eine Client-Factory. Der Realm mit AD-Anbindung, MFA und Rollenmodell wird einmal zentral gebaut, und Teams verwalten ihre OIDC-Clients darin selbst, per Pull Request und innerhalb fester Leitplanken.
Teams in der Admin Console: nur die eigenen Clients
Mit den Fine-Grained Admin Permissions v2 (ab Keycloak 26.2, Realm settings → Admin Permissions) sehen und pflegen Team-Admins in der Admin Console genau ihre eigenen Clients. Auch das kommt aus der Factory: Die Ressource keycloak_openid_client_admin_permissions vergibt pro Team die Scopes view und manage auf dessen Clients, gebunden an die AD-Gruppe des Teams.
Auch die AD-Anbindung als Code
Was für die Clients gilt, gilt für den Realm selbst: Der Terraform Provider keycloak/keycloak beschreibt die komplette AD-Anbindung deklarativ. Drift zeigt terraform plan sofort an.
resource "keycloak_ldap_user_federation" "ad" {
name = "active-directory"
realm_id = data.keycloak_realm.corp.id
vendor = "AD"
edit_mode = "READ_ONLY"
import_enabled = true
connection_url = "ldaps://dc1.example.com:636 ldaps://dc2.example.com:636"
use_truststore_spi = "ALWAYS"
connection_timeout = "3s"
bind_dn = "CN=svc-keycloak,OU=Service Accounts,DC=example,DC=com"
bind_credential_wo = var.ad_bind_password
bind_credential_wo_version = 1
users_dn = "OU=Users,DC=example,DC=com"
username_ldap_attribute = "sAMAccountName"
uuid_ldap_attribute = "objectGUID"
user_object_classes = ["person", "organizationalPerson", "user"]
custom_user_search_filter = "(&(objectCategory=person)(memberOf:1.2.840.113556.1.4.1941:=CN=APP-Keycloak-Users,OU=Groups,DC=example,DC=com))"
search_scope = "SUBTREE"
pagination = true
full_sync_period = 86400
changed_sync_period = 3600
cache {
policy = "MAX_LIFESPAN"
max_lifespan = "3m"
}
}
bind_credential_wo ist ein Write-only Argument (ab Terraform 1.11): Das Bind-Passwort landet nie im State. vendor = "AD" erzeugt dieselben Default-Mapper wie in der UI, inklusive MSAD account controls.
Troubleshooting: die fünf häufigsten Fehler
| Symptom | Ursache | Lösung |
|---|---|---|
PKIX path building failed | AD-CA fehlt im Truststore | CA nach conf/truststores oder KC_TRUSTSTORE_PATHS, Neustart |
No subject alternative DNS name matching … | Connection URL nutzt IP oder Alias | FQDN aus dem DC-Zertifikat verwenden |
error code 49 … data 52e | Bind DN oder Passwort falsch | mit ldapsearch gegenprüfen |
| Sync liefert maximal 1000 User | Pagination ist aus | Pagination: On |
| Nested Groups fehlen | nicht-rekursive Strategie im Group Mapper | LOAD_GROUPS_BY_MEMBER_ATTRIBUTE_RECURSIVELY |
Für tiefere Analysen protokolliert --log-level="INFO,org.keycloak.storage.ldap:trace" jede LDAP-Query.
Checkliste für die Produktion
- LDAPS mit mindestens zwei DCs, AD-CA im Truststore, Bind Credential im Vault
- Vendor, Edit Mode und Username-Attribut beim ersten Speichern gesetzt
- User-Scope per LDAP-Filter,
Pagination: On, stündlicher und nächtlicher Sync - Group Mapper rekursiv, mit Filter und
Groups Path, Rollen an Gruppen gebunden - MFA-Flow gebunden, Recovery Codes aktiv, Brute Force unter der AD-Lockout-Schwelle
- Client-Factory mit Pull-Request-Review, Leitplanken per Client Policies und Secrets direkt im Secret Store
- Komplette Konfiguration per Terraform in Git, lokaler Notfall-Admin unabhängig von AD
Fazit
Keycloak vor Active Directory liefert in kurzer Zeit, was AD allein nie kann: OIDC und SAML für alle Anwendungen, MFA ohne Umbau und ein Rollenmodell, das auf den bestehenden AD-Prozessen aufsetzt. Mit der Client-Factory wird daraus eine Plattform: Teams docken in Minuten an, das IAM-Team behält die Leitplanken, und jede Änderung ist im Git nachvollziehbar.
Du planst eine Keycloak-Einführung oder willst eine bestehende Identity-Plattform auf Self-Service umstellen? Schreib mir: david@picillo.de