Concourse-CI-Authentifizierung mit Keycloak

1 Kommentar

Concourse CI ist ein flexibler Scheduler für CI-Pipelines, der in zahlreichen Open-Source-Projekten eingesetzt wird, darunter sind unter anderem Projekte aus dem Spring-Ökosystem sowie dem Cloud-Foundry-Universum, die mit teils stattlichen CI-Pipelines aufwarten. Getreu dem Motto „Eat Your Own Dog Food“ verwendet auch das Concourse-CI-Projekt selbst … Trommelwirbel … Concourse CI.

Mein Kollege Alexander Melnyk hat bereits 2017 an dieser Stelle von den Möglichkeiten mit Concourse CI berichtet, weshalb wir hier für einen tieferen Einblick auf den Vorgängerartikel verweisen.

Mittlerweile hat Concourse CI einige neue Tricks dazugelernt, und einen davon möchte ich heute vorstellen, nämlich die Unterstützung von OpenID Connect als Authentifizierungs­verfahren. Im Folgenden möchte ich daher beschreiben, wie ihr euren Concourse-CI-Server für eine Authentifizierung mit Keycloak über OpenID Connect konfigurieren könnt.

Konfiguration des Keycloak-Clients

In Keycloak definieren wir für unser Beispiel einen Realm mit dem Namen acme-dev. Diesen Realm werden wir später bei der Konfiguration von Concourse CI wieder benötigen.
Für die Verbindung mit Concourse CI definieren wir einen OpenID Connect-Client und geben infra-concourse als dessen Client-ID an. Als Root URL verwenden wir https://concourse.acme.local:18443.
Definition von Concourse-CI-Client in Keycloak

Als Access-Type definieren wir confidential, und bei den unterstützten OAuth2 Flows aktivieren wir nur den Standard Flow, der auch unter der Bezeichnung Authorization Code Flow bekannt ist.
Bei Valid Redirect URIs geben wir nur /sky/issuer/callback an. Dieser URI wird von Keycloak automatisch mit der angegebenen Root URL erweitert.
Als Base URL geben wir einfach nur / an. Auch dieser URL wird von Keycloak entsprechend erweitert und dient dazu, einen entsprechenden Link im Applications-Bereich der account-Anwendung für den Benutzer zu generieren.

Konfiguration von Concourse CI Client in Keycloak

Damit wir steuern können, welche Benutzer den Concourse Link in der Keycloak-account-Anwendung angezeigt bekommen, definieren wir eine explizite Rolle user, die wir später einem Benutzer oder einer Gruppe zuordnen können.
Definition der Rollen für den Concourse-CI-Client in Keycloak

Damit wir in Concourse CI auch den passenden Benutzernamen angezeigt bekommen, definieren wir einen entsprechenden Protocol Mapper vom Typ User Property mit dem Namen username, um den Benutzernamen als claim in das erzeugte IDToken zu generieren.
Dazu klicken wir unter dem Punkt mappers auf den Button Add Builtin und wählen den username Mapper aus.
Definition der Client Mapper für den Concourse-CI-Client in Keycloak

Da wir den erzeugten Protocol Mapper für unsere Zwecke noch etwas anpassen müssen, klicken wir bei dem Eintrag in der Liste auf edit.
Definition des Client Mappers für den Benutzernamen für den Concourse-CI-Client in Keycloak

In den Einstellungen zum Protocol Mapper geben wir bei property und Token claim name jeweils den Wert username an. Da dieser Claim nur im IDToken benötigt wird, wählen wir hier lediglich Add to ID token aus.
Konfiguration des Client Mappers für den Benutzernamen für den Concourse-CI-Client in Keycloak

Das war es auch schon. Mit ein paar Klicks und ein wenig Konfiguration haben wir den Concourse-CI-Client in Keycloak vollständig eingerichtet.

Nun fehlt uns nur noch ein Benutzer, der die entsprechende user-Rolle für den Concourse-CI-Client hat.

Nachdem wir einen entsprechenden Benutzer angelegt haben, können wir mit der Konfiguration des Concourse-CI-Web-Servers starten.

Konfiguration des Concourse-CI-Servers

Für unser Beispiel verwenden wir eine lokale Umgebung, wobei die Server unter folgenden URLs erreichbar sind:

  • Concourse-Webserver https://concourse.acme.local:18443
  • Keycloak-Server https://auth.acme.local:8443/auth

Die Konfiguration von Concourse wird dabei in einer relationalen PostgreSQL-Datenbank gespeichert. Im Keycloak ist ein Realm mit dem Namen acme-dev hinterlegt. Die Zertifikate für die TLS/SSL-Konfiguration in der lokalen Umgebung haben wir übrigens mit dem nützlichen Tool mkcert erzeugt.

Im Setup & Operations Guide von Concourse CI findet man eine sehr anschauliche Erklärung zum Aufbau einer eigenen Concourse-CI-Testumgebung, auf die wir an dieser Stelle verweisen möchten.

Für unser Beispiel brauchen wir nur den web-Modus des Concourse-CI-Servers, den wir wie folgt konfigurieren:

./concourse web \
--add-local-user concourse:concourse123 \
--main-team-local-user concourse \
--log-level=debug \
--bind-port=18080 \
--tls-bind-port=18443 \
--tls-cert=./_wildcard.acme.local+3.pem \
--tls-key=./_wildcard.acme.local+3-key.pem \
--session-signing-key ./keys/session_signing_key \
--tsa-host-key ./keys/tsa_host_key \
--tsa-authorized-keys ./keys/authorized_worker_keys \
--postgres-host localhost \
--postgres-user concourse \
--postgres-password byebyejenkins \
--postgres-database concourse \
--external-url https://concourse.acme.local:18443 \
--oidc-display-name='Acme SSO' \
--oidc-client-id=infra-concourse \
--oidc-client-secret=5f200127-657e-43f0-a640-7e2b9a5f6ce2 \
--oidc-scope=profile \
--oidc-issuer=https://auth.acme.local:8443/auth/realms/acme-dev \
--main-team-oidc-group=main \
--main-team-oidc-user=infra-concourse

Die relevanten Parameter für die KeycloakOpenID-Connect-Konfiguration sind:

...
--external-url https://concourse.acme.local:18443 \
--oidc-display-name='Acme SSO' \
--oidc-client-id=infra-concourse \
--oidc-client-secret=5f200127-657e-43f0-a640-7e2b9a5f6ce2 \
--oidc-scope=profile \
--oidc-issuer=https://auth.acme.local:8443/auth/realms/acme-dev \
--main-team-oidc-group=main \
--main-team-oidc-user=infra-concourse
...

Dabei entspricht das oidc-client-secret dem Client Secret aus unserer OpenID-Connect-Client-Konfiguration. Weiterhin werden alle relevanten Endpoints, die für die Authentifizierung benötigt werden, von der oidc-issuer-URL abgeleitet. Diese zeigt auf den Base-URL des Realms acme-dev.

Für das Beispiel haben wir den Benutzer tester angelegt, der die Rolle user für den Client infra-concourse hat.

Et voilà: Nach ein paar einfachen Handgriffen können wir uns nun in unserer Concourse-CI-Umgebung über Keycloak authentifizieren. 🙂
Beispielablauf für die Authentifizierung mit Keycloak

Thomas Darimont

Thomas Darimont arbeitet als Fellow bei der codecentric AG in Münster. Dort hilft er Kunden bei der Implementierung zentralisierter Identity-Management-Plattformen. Davor arbeitete er als Principal Software Engineer im Spring Data Team bei Pivotal.
Er hat mehr als fünfzehn Jahre Erfahrung in der Entwicklung von Enterprise Applications und Open-Source-Projekten mit Java und .NET. Seine Arbeitsschwerpunkte liegen in den Bereichen Softwarearchitektur, Spring-Ökosystem, Performance Tuning und Security. In seiner Freizeit organisiert er gerne Community Meetups und arbeitet an Open-Source-Projekten wie Keycloak, Spring und Cloud Foundry mit.

Kommentare

  • Tolleiv N.

    5. Juni 2019 von Tolleiv N.

    Danke für die schöne und umfangreiche Dokumentation. Was eventuell fehlt ist, dass es einen „User Client Role“ Mapper braucht der den Claim Name „groups“ hat und die Client Roles entsprechend in die Token trägt. Alternativ könnte mal das Setting auch per CONCOURSE_OIDC_GROUPS_KEY auf einen bestehenden Claim biegen.

Kommentieren

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert.