DexIdP - Wie du in 5 Minuten einen OIDC IdP aufsetzt und dich via GitHub authentifizierst

27.03.2024Tom Trapp
DevOps Identity Provider Authorization / Authentication oidc github oauth Single Sign On

Banner

Gut neues TechUp, Dex, gesehen beim Erkan auf LinkedIn, wie immer, erstmal auf YouTube ein oder zwei Talks dazu anschauen. Mist, es gibt keinen einzigen Talk in einer Sprache, die ich verstehe. Gut, back to the roots, lesen, lesen, lesen.

Folgende Fragen stelle ich mir:

  • Was ist Dex❓
  • Wie funktioniert Dex❓
  • Kann ich Dex einfach lokal aufsetzen und testen❓
  • Was macht Dex anders oder cooler als andere IdPs❓
  • Dex oder weiterhin Keycloak❓

Was ist Dex?

Dex ist ein OIDC & OAuth2 Identitätsprovider (IdP), welcher Teil der Cloud Native Computing Foundation (CNCF) ist und seit 2020 den Sandbox-Status hat. Dex selbst als IdP kann nur via OIDC angebunden werden, genau das ist auch das Ziel dahinter! Dex abstrahiert zahlreiche Authentifizierungsmöglichkeiten, dadurch muss nur ein Standard-Protokoll implementiert werden, um mit Dex zu kommunizieren, nämlich OIDC.

IdP? –> siehe mein TechUp

OIDC / OAuth2? –> siehe mein TechUp

Dex verspricht selbst, dass es sich um einen Provider für alles handelt. Es gibt sogenannte Connectors, mit diesen kann man Dex mit zahlreichen anderen Identitätsanbietern oder Authentication-Systemen verbinden. Dazu gehören LDAP, SAML, OAuth 2.0, GitHub, GitLab, Google und viele mehr.

An dieser Stelle ist zu erwähnen, dass Dex in Go geschrieben ist und voll containerisiert zur Verfügung steht.

Wie funktioniert Dex?

Dex fungiert als Abstraktionsschicht für Authentifizierung mittels OIDC. Ein Client redet so nur mit Dex und Dex redet mit dem eigentlichen Identitätsanbieter. Das bedeutet, dass der Client nicht mehr wissen muss, wie er sich bei einem bestimmten Identitätsanbieter authentifizieren muss. Das ist die Aufgabe von Dex. Diesen nachgelagerten IdP kann man auch, wie in folgendem Bild zu sehen, Upstream-IdP nennen.

img.png

Hier ist schön zu sehen, dass so auch der IdP getauscht werden kann, ohne, dass die Clients davon etwas mitbekommen oder anpassen müssen. Mit Clients sind hier unterschiedlichste Applikationen gemeint, wie Web-Apps, Mobile-Apps, CLI-Tools, etc.

Die Kommunikation von Dex hin zum Upstream-IdP läuft über sogenannte Connectors, welche die Authentifizierungsmethoden der Upstream-IdP implementieren. Eine Liste aller Connectors ist hier zu finden.

Hands On - kann ich Dex einfach lokal aufsetzen und testen?

Und los gehts, wir checken uns erstmal das Repo aus, bauen die Beispiele und starten Dex via Docker-Compose.

1
2
3
4
git clone https://github.com/dexidp/dex.git

make examples
make up

Mist, no matching manifest for linux/arm64/v8 in the manifest list entries. Aufgrund meines M1 Macs gibt es wohl kein passendes Docker Image.

Build from source it is.

1
make build

Und nun hoppla, starten wir Dex.

1
./bin/dex serve examples/config-dev.yaml

Ok perfekt, Dex läuft, und nun? Jetzt starten wir die Beispiel-App. Die Beispiel-App ist eine einfach Webanwendung, welche sich gegen Dex authentifiziert.

1
./bin/example-app

Nun können wir unter http://localhost:5555 eine Web-UI aufrufen, mit der wir uns anmelden können.

Wir sehen nun unterschiedliche Felder, wo wir unseren OIDC Flow noch weiter konfigurieren können, aber wir starten erstmal mit dem Standard-Flow. Sobald wir auf Login klicken gelangen wir auf die nächste Seite.

img_1.png

Dort werden wir gefragt, wie wir uns einloggen wollen, als ersten wählen wir Log in with Example.

img_2.png

Anschliessend kommt der klassische Consent-Screen, den wir bestätigen.

img_3.png

Und wir sind eingeloggt, wir haben einen ID-Token, einen Access-Token und ein Refresh-Token erhalten. Somit haben wir einen kompletten OIDC Flow durchgespielt.

img_4.png

Auch der Email-Login funktioniert, die Beispielkonfiguration legt uns einen User mit der Mail admin@example.com an, das Passwort ist password. In diesem einfachen Beispiel haben wir nun keinen echten Connector genutzt, sondern statische Daten, aber das Prinzip ist das gleiche.

Config-Datei

Schauen wir uns nun die Example Config genauer an:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
issuer: http://127.0.0.1:5556/dex
storage:
  type: sqlite3
  config:
    file: examples/dex.db
web:
  http: 0.0.0.0:5556
telemetry:
  http: 0.0.0.0:5558
staticClients:
- id: example-app
  redirectURIs:
  - 'http://127.0.0.1:5555/callback'
  name: 'Example App'
  secret: ZXhhbXBsZS1hcHAtc2VjcmV0
connectors:
- type: mockCallback
  id: mock
  name: Example
enablePasswordDB: true

staticPasswords:
- email: "admin@example.com"
  hash: "$2a$10$2b2cU8CPhOTaGrs1HRQuAueS7JTT5ZHsHSzYiFPm1leZck7Mc8T4W"
  username: "admin"
  userID: "08a8684b-db88-4b73-90a9-3cd1661f5466"

Kurz zusammengefasst:

  • der Endpunkt für Dex wird definiert
  • Die Speicherung der Daten wird auf eine SQLite-DB gesetzt, mittels dex.db wird eine Beispiel-DB angelegt
    • Dex benötigt die Speicherung für Refresh Tokens, Signing Keys etc.
    • Aktuell werden Etcd, CRDs, SQL, Postgres, MySQL und SQLite3 unterstützt
  • Endpunkte für Web und Telemetry werden definiert
  • Es wird ein statischer OIDC Client angelegt
  • Zu guter Letzt wird ein statischer User angelegt, welcher sich mittels Email und Passwort authentifizieren kann

Schön und gut, aber das sind ja nur statische Daten, wie kann ich Beispielsweise einen neuen OIDC-Client zur Laufzeit anlegen? Auch hier bietet Dex eine Lösung, die Dex API, eine gRPC Schnittstelle. Damit kann Dex zur Laufzeit konfiguriert werden.

GitHub Connector

Nun wollen wir uns noch den GitHub-Connector anschauen und diesen für die Authentifizierung nutzen.

Zuerst müssen wir hier eine GitHub-App anlegen. Ich habe das über diesen Link gemacht.

  • Homepage-Url: http://localhost:5555/
  • Authorization-Callback-Url: http://localhost:5556/dex/callback

Anschliessend ist der OAuth-Client angelegt und wir haben die clientID und clientSecret.

Nun können wir Dex konfigurieren, um mit dieser GitHub-App zu kommunizieren.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
issuer: http://127.0.0.1:5556/dex
storage:
  type: sqlite3
  config:
    file: examples/dex.db
web:
  http: 0.0.0.0:5556
telemetry:
  http: 0.0.0.0:5558
staticClients:
  - id: example-app
    redirectURIs:
      - 'http://127.0.0.1:5555/callback'
    name: 'Example App'
    secret: ZXhhbXBsZS1hcHAtc2VjcmV0

connectors:
  - type: github
    id: github
    name: GitHub
    config:
      clientID: <your clientId>
      clientSecret: <your clientSecret>
      redirectURI: http://127.0.0.1:5556/dex/callback
      loadAllGroups: true
      teamNameField: slug
      useLoginAsID: false

Wenn wir diese Config-Datei beispielsweise mit dem Namen b-nova_github.yaml im Examples Ordner speichern, können wir Dex mit dieser Konfiguration starten.

1
./bin/dex serve examples/b-nova_github.yaml

Und schwups, schön können wir uns via OIDC gegen GitHub einloggen, ohne, dass wir etwas an der Applikation (dem Client) anpassen mussten.

Wir drücken wieder Login und landen, wenn wir noch nicht eingeloggt sind, direkt bei GitHub.

img_6.png

Hier sehen wir schön, dass wir uns via GitHub authentifizieren können, um dann anschliessend auf techup-dex Zugriff zu erhalten. Anschliessend kommt wieder der Consent unserer Example App, welchen wir bestätigen. Und voilà, wir sind eingeloggt und haben die bekannten OAuth & OIDC Tokens.

Schauen wir uns nun die Claims an, sehen wir, dass meine echten, realen GitHub Informationen zurückgegeben werden.

img_5.png

Dem Token an sich können wir aber nicht klar entnehmen, dass es sich um einen GitHub Login handelt, das ist auch gut so! Da Dex als Abstraktionsschicht fungiert muss unsere Web-App nicht wissen, wie der User sich authentifiziert hat.

Und so haben wir in 5 Minuten einen OIDC-IdP aufgesetzt und uns via GitHub authentifiziert. In einem produktiven Setup würde Dex sicherlich containerisiert laufen, die Secrets nicht plain in der Config liegen und das Setup durch weiteres Hardening abgesichert sein. Glücklicherweise bietet uns Dex unterschiedliche Container Images, Helm Charts und einen Kubernetes Operator. Mehr dazu in einem späteren TechUp! 🚀

Was macht Dex anders oder cooler als andere IdPs?

Im Grunde genommen ist Dex ein IdP wie viele andere auch, aber es bietet eine sehr einfache Möglichkeit, um verschiedene Authentifizierungsmethoden zu abstrahieren und mittels OIDC zu konsolidieren. Dex ist die Cloud Native Alternative, wenn man schnell und einfach einen IdP für ein vorhandenes IDM-System wie LDAP, GitHub o.ä. benötigt. Die Konfiguration ist vollständig versioniert, kann aber auch mittels API zur Laufzeit angepasst werden.

Dex oder weiterhin Keycloak?

Schwer zu sagen! Keycloak bietet, als vollständiges Identity- und Access-Management-System, natürlich viel mehr Funktionalität als Dex. So kann KeyCloak beispielsweise custom Claims abbilden, hat eine WebUI, kann Realm basiert arbeiten, hat unterschiedliche Two Factor Möglichkeiten und andere Features.

Dex hingegen ist sehr schlank und einfach gehalten, es bietet nur das Nötigste, um einen IdP zu betreiben. Es ist vollständig containerisiert und bietet eine einfache Möglichkeit, um verschiedene Authentifizierungsmethoden zu abstrahieren und mittels OIDC zu konsolidieren. Solltest du also schon ein existierendes IDM oder gar IdP System haben und willst deine Clients über ein einziges OIDC Interface authentifizieren, dann ist Dex die richtige Wahl.

Solltest du weitere Features brauchen, würde die Wahl eher Richtung Keycloak oder gar zu einem anderen IdP wie ForgeRock oder Okta gehen.

Fazit

Ich persönlich finde Dex cool, es trifft genau den CNCF-Gedanken, einer kleiner Service mit flexiblen Konfigurationsmöglichkeiten für genau eine Aufgabe.

Sicherlich ist Dex eine super Alternative, wobei man den Sandbox Status noch deutlich merkt. Beispielsweise fehlt mir das Feature, bei local static Usern auch Gruppen angeben zu können, um unterschiedliche Testfälle abzubilden.

Nichtsdestotrotz, ein super Tool, um schnell und einfach einen IdP aufzusetzen und zu testen.

Stay tuned! 💡

Sum-Up

  • Was ist Dex?

    • Dex ist ein OIDC & OAuth2 Identitätsprovider (IdP), der als Teil der Cloud Native Computing Foundation (CNCF) fungiert und seit 2020 den Sandbox-Status hat. Es abstrahiert zahlreiche Authentifizierungsmöglichkeiten und erfordert nur die Implementierung von OIDC zur Kommunikation.
  • Wie funktioniert Dex?

    • Dex agiert als Abstraktionsschicht für Authentifizierung mittels OIDC, wobei es als Vermittler zwischen dem Client und dem eigentlichen Identitätsanbieter fungiert. Dadurch müssen Clients nicht wissen, wie sie sich bei verschiedenen Identitätsanbietern authentifizieren müssen.
  • Kann ich Dex einfach lokal aufsetzen und testen?

    • Ja, Dex lässt sich einfach lokal aufsetzen und testen. Der Blogbeitrag bietet eine Anleitung zum lokalen Deployment von Dex, einschließlich der Nutzung von Docker-Compose und dem Bauen aus dem Quellcode.
  • Was macht Dex anders oder cooler als andere IdPs?

    • Dex zeichnet sich durch seine Einfachheit und die Fähigkeit aus, verschiedene Authentifizierungsmethoden mittels OIDC zu konsolidieren. Es ist besonders geeignet für Umgebungen, die eine schnelle und einfache Einrichtung eines IdPs benötigen, mit der Flexibilität, diesen durch Connectors mit einer Vielzahl von Authentifizierungssystemen zu verbinden.
  • Dex oder weiterhin Keycloak?

    • Die Wahl zwischen Dex und Keycloak hängt von den spezifischen Anforderungen ab. Dex ist schlanker, einfacher und fokussiert sich auf die Abstraktion verschiedener Authentifizierungsmethoden mittels OIDC. Keycloak hingegen bietet eine breitere Funktionalität als vollständiges Identity- und Access-Management-System. Für einfache OIDC-Abstraktionen und die Integration bestehender Authentifizierungssysteme ist Dex eine gute Wahl, für umfangreichere IAM-Funktionen könnte Keycloak besser geeignet sein.
Tom Trapp

Tom Trapp – Problemlöser, Innovator, Sportler. Am liebsten feilt Tom den ganzen Tag an der moderner Software und legt viel Wert auf objektiv sauberen, leanen Code.