Skalierbares RBAC mit Keycloak
Im letzten Beitrag habe ich gezeigt, wie ein skalierbares RBAC auf konzeptioneller Ebene modelliert werden kann. Damit klar ist, welche Bedeutungen Basisrecht, Basisrolle, lokales Berechtigungsprofil und globales Berechtigungsprofil haben, solltet ihr zumindest den Abschnitt des letzten Beitrags lesen, in dem ich die Begriffe erkläre. In diesem Beitrag geht es darum, wie ihr dieses Konzept in Keycloak umsetzen könnt.
Keycloak bringt standardmäßig alle Funktionalitäten mit, die wir für RBAC benötigen. Für die Umsetzung werden wir die folgenden Keycloak-Konzepte nutzen:
- Clients
- Client Roles
- Composite Client Roles
- Groups
- Users
An dieser Stelle sei kurz erwähnt: Konzepte wie Client Scopes und Protocol Mapper klammern wir hier bewusst aus. Diese werden erst relevant, wenn es darum geht, die konkreten Inhalte des ausgestellten Tokens zu steuern. Im Beitrag Konfiguration von Access Tokens in Keycloak, haben wir uns damit beschäftigt. Hier geht es ausschließlich darum, die organisatorische Struktur des skalierbaren RBAC-Modells in Keycloak aufzubauen.
Begriffsdefinitionen
Das schwierigste bei der Arbeit mit Keycloak ist in meinen Augen, dass Begriffe wie Clients innerhalb von Keycloak anders definiert sind als in gängigen Spezifikationen wie z.B. RFC 6749: The OAuth 2.0 Authorization Framework. Damit ein einheitliches Verständnis als Grundlage für den Beitrag existiert, definiere ich zunächst die relevanten Rollen aus der Spezifikation und grenze sie von den Keycloak-Konzepten ab.
Der Resource Server, der Authorization Server und der Client sind im Kontext der OAuth 2.0 Spezifikation lediglich als Rollen zu verstehen. Es werden also Verantwortlichkeiten und keine konkreten Entitäten definiert.
Resource Server: Server, der die geschützten Ressourcen bereitstellt. Nutzt Access Tokens, um die Requests zu den geschützten Ressourcen zu verarbeiten (Definition laut RFC 6749).
Authorization Server: Server, der die Access Tokens ausstellt, nachdem sich der Nutzer erfolgreich angemeldet hat (Definition laut RFC 6749). In diesem Beitrag besitzt Keycloak die Rolle des Authorization Servers.
(OAuth 2.0) Client: Eine Anwendung, die geschützte Ressourcen im Auftrag des Nutzers anfragt (Definition laut RFC 6749). Wichtig: wenn wir in Keycloak Clients anlegen, handelt es sich nicht in jedem Fall um einen Client mit der Rolle eines OAuth 2.0 Clients.
Die folgende Darstellung zeigt das Zusammenspiel dieser Rollen in vereinfachter Form.

Keycloak Clients vs. OAuth 2.0 Clients
Im RFC 6749 wird der Client als Rolle definiert, dessen Inhaber Access Tokens anfordert. In Keycloak ist ein Client jedoch eine konkret konfigurierte Entität. Um Keycloak effektiv zu nutzen, muss verstanden werden, an welchen Stellen der Keycloak Client über den OAuth 2.0 Standard hinausgeht.
Der Keycloak Client als Konfigurationsobjekt: In Keycloak wird ein Client als Konfigurationsobjekt verwendet, das die Identität einer Anwendung gegenüber Keycloak repräsentiert. Hier werden alle sicherheitsrelevanten Einstellungen wie erlaubte Redirect-URIs, Web-Origins für CORS sowie der verwendete Authorization Flow konfiguriert.
Der Keycloak Client als Namespace für Basisrechte, Basisrollen und lokale Berechtigungsprofile: In Keycloak können Client roles innerhalb eines Clients definiert werden. Basisrechte, Basisrollen und lokale Berechtigungsprofile lassen sich so für einen spezifischen Resource Server definieren und sauber kapseln. Wenn eine Client role andere Client roles enthält, spricht man von einer Composite client role. Diese Rollen werden für die Basisrollen und lokalen Berechtigungsprofile verwendet.
Integrierte Service Accounts: Laut RFC 6749 fragt eine Anwendung, die die Rolle des OAuth 2.0 Clients besitzt, Access Tokens im Auftrag eines Nutzers an. Keycloak Clients verfügen aber auch über integrierte Service Accounts. Ist diese Funktion aktiviert, kann eine Anwendung eigenständig, ohne externen Nutzer, Access Tokens anfordern.
Die folgende Abbildung zeigt den Zusammenhang zwischen einem Keycloak Client und der Rolle des Clients aus der OAuth 2.0 Spezifikation.

An dieser Stelle geht es nicht darum, alles bereits im Detail zu verstehen. Es ist nur wichtig zu verinnerlichen, dass Keycloak Clients und die OAuth 2.0 Client Rolle unterschiedliche Konzepte auf unterschiedlichen Ebenen darstellen.
Keycloak-Konfiguration für skalierbares RBAC
(Hinweis: Für die folgenden Schritte nutze ich Keycloak in der Version 26+)
Damit die Basisrechte, Basisrollen und lokalen Berechtigungsprofile an einem Ort gebündelt sind, erstelle ich in Keycloak immer einen Client, der den Resource Server repräsentiert. Dieser Keycloak Client wird nicht dafür genutzt, Tokens auszustellen. Er dient uns ausschließlich für organisatorische Zwecke als Namespace.
Um einen neuen Client zu erstellen, klickt ihr in der linken Navigationsleiste auf Clients und anschließend auf Create Client.

Wir vergeben eine Client ID, einen Namen und eine Beschreibung. Die Client ID muss gesetzt werden. Da es sich um einen organisatorischen Keycloak Client handelt, sind die Felder Name und Description optional.
Ich unterscheide Keycloak Clients, die Resource Server repräsentieren und Clients, die Tokens ausstellen durch Suffixe in der Client ID. Für Resource Server nutze ich -rs und für OAuth 2.0 Clients -oauth.

Nach einem Klick auf Next gelangen wir zur Capability Config. Da dieser Keycloak Client keine Tokens ausstellen wird, deaktivieren wir hier alle Flows.

Auf der nächsten Seite können sowohl die Home URL als auch die Root URL konfiguriert werden. Diesen Schritt überspringen wir.
1) Basisrechte anlegen
Unter dem Reiter Roles innerhalb eures neuen Clients definiert ihr nun zunächst die Basisrechte eurer Anwendung. Für die Namens-Schemata verweise ich auf den letzten Beitrag: Skalierbares RBAC auf konzeptioneller Ebene.

Auf der folgenden Seite könnt ihr nun den Role name angeben und optional eine Beschreibung hinzufügen. Bei den Basisrechten wird nicht unbedingt eine Beschreibung benötigt. Die folgenden Basisrechte habe ich für dieses Beispiel erstellt:

2) Basisrollen bilden (Composite Client Roles)
Nun definieren wir zwei Basisrollen. Eine für lesende Zugriffe und eine für alle schreibenden Zugriffe. Erstellt die Basisrollen zunächst genau wie die Basisrechte über den Button Create role. Nutzt das Beschreibungsfeld, um kurz zusammenzufassen, was die Rolle ermöglicht.

Klickt anschließend auf die erstellte Basisrolle, um die Detailseite zu öffnen. Hier navigiert ihr zu Associated roles und weist der Basisrolle genau die Basisrechte zu, die sie bündeln soll.

Für eine schnelle Navigation könnt ihr die Suchleiste in dem Popup nutzen, das sich öffnet, wenn ihr auf Client roles (12) geklickt habt. Dort müsst ihr dann nur noch die entsprechenden Rollen wählen, die eure Basisrechte repräsentieren.

Sobald ihr das für alle Basisrollen gemacht habt, zeigt Keycloak an, dass es sich nun um eine Composite role handelt.

3) Lokale Berechtigungsprofile
Ein lokales Berechtigungsprofil ist auf technischer Ebene identisch zu einer Basisrolle. In unserem Beispiel erstellen wir ein Profil für einen "Besucher" (nur Leserechte) und einen "Bibliothekar" (Lese- und Schreibrechte). In dem Beschreibungsfeld für die Rolle sollte nun auf jeden Fall die Funktion der Rolle enthalten sein. In unserem Beispiel sind das dementsprechend Bibliothekar und Besucher. Die Zuweisung der Basisrollen zu den lokalen Berechtigungsprofilen ist ebenfalls identisch zum vorherigen Schritt.

4) Globale Berechtigungsprofile als Keycloak Groups abbilden
Der letzte Konfigurationsschritt besteht darin, die globalen Berechtigungsprofile zu erstellen. Hierfür navigiert ihr im Hauptmenü auf Groups und erstellt über Create group eine neue Gruppe.
Wichtig hierbei ist, dass der Name des lokalen Berechtigungsprofils mit dem Namen des globalen Berechtigungsprofils "verknüpft" ist. Wenn das lokale Berechtigungsprofil also den Namen oid:ba1:comp_role_1 besitzt, dann leitet sich der Name des globalen Berechtigungprofils daraus ab: oid:comp_role_1. Auch die Beschreibungen sollten identisch sein. Nur so bleibt die Struktur übersichtlich und skalierbar.


Klickt nun auf die erstellte Gruppe und wechselt in den Reiter Role mapping. Klickt auf Assign role und sucht nach dem zuvor erstellten lokalen Berechtigungsprofil aus eurem Resource Server Client.


Wenn ihr mehrere Anwendungen (Resource Server) betreibt, die alle die Rolle eines "Bibliothekars" kennen, weist ihr dieser einen globalen Gruppe einfach die lokalen Berechtigungsprofile aller relevanten Clients zu.
5) Nutzer zuweisen und Berechtigungen verifizieren
Um zu testen, ob unsere Architektur funktioniert, navigieren wir zu Users und legen einen Testnutzer an. Klickt auf euren Testnutzer, navigiert zum Reiter Groups und fügt ihn über Join Group eurem globalen Berechtigungsprofil (z.B. dem Bibliothekar) hinzu.
Das Schöne daran ist: wir können uns das Ergebnis in Keycloak direkt ansehen. Wechselt beim Nutzer in den Reiter Role Mapping. Standardmäßig seht ihr hier nur direkte Zuweisungen. Wenn ihr jedoch das Häkchen bei Hide inherited roles entfernt, seht ihr den gesamten Baum. Dadurch seht ihr auch, dass der Nutzer durch seine Mitgliedschaft in der Gruppe automatisch das lokale Berechtigungsprofil, die darin enthaltenen Basisrollen und letztendlich die Basisrechte zugewiesen bekommen hat.
Auf diese Weise lässt sich das skalierbare RBAC Modell in Keycloak in die Praxis umsetzen. Wenn Personen neue Aufgaben in der Organisation übernehmen, müssen sie lediglich anderen Keycloak-Gruppen zugewiesen werden. Eure Anwendungen bleiben von dieser Änderung völlig unberührt.
Natürlich gibt es Sonderfälle, die von dieser Struktur abweichen. Darauf gehe ich bei Bedarf gesondert ein. Im nächsten Beitrag schauen wir uns dann an, wie wir OAuth 2.0 Clients konfigurieren, damit wir Scopes und Protocol Mapper nutzen können, um genau diese Basisrechte sauber in ein Access Token zu schreiben.
Let's Connect
Wie ihr sicher wisst, gibt es in der Softwareentwicklung nicht den einen, richtigen Weg. Softwareentwicklung lebt von zahlreichen Ideen und offenem Austausch.
Also schreibt mir ne Mail oder kontaktiert mich auf Instagram/LinkedIn 🤓
- LinkedIn: https://www.linkedin.com/in/nicokuchling/
- Instagram: @nicokuchling
- Mail: kontakt@nicokuchling.de