Single Sign-On im Homelab ist ein zweischneidiges Schwert: Man will einen Login für alles, handelt sich damit aber schnell einen Identity-Provider ein, der schwerer wiegt als die Dienste, die er absichert. Genau an diesem Punkt habe ich meinen bisherigen
Authentik
-Stack gegen Pocket-ID
getauscht — erreichbar unter auth.this-is-fine.io und seitdem der zentrale OIDC-Provider für mein gesamtes Lab.
Warum Authentik weichen musste#
Authentik ist exzellente Software und ein vollwertiger Identity-Provider: SAML, OAuth2/OIDC, LDAP, ausgefeilte Authentication-Flows, Policy-Engine, Outposts für Proxy-Auth. Genau diese Mächtigkeit hat aber ihren Preis. Im Cluster bedeutete Authentik einen server, einen worker, eine PostgreSQL-Datenbank und einen Redis-kompatiblen Cache — ein kleiner verteilter Stack, nur damit ich mich irgendwo einloggen kann.
Für eine Organisation mit hunderten Nutzern, SAML-Zwang und komplexen Föderationsanforderungen ist das angemessen. Für mein Lab, in dem genau ein Mensch und eine Handvoll Dienste OIDC sprechen, war es schlicht überdimensioniert. Die Erkenntnis: Ich nutzte vielleicht fünf Prozent der Features und betrieb hundert Prozent der Komplexität.
Was Pocket-ID anders macht#
Pocket-ID dreht die Prioritäten um: Es ist ein reiner OIDC-Provider, bewusst auf das Nötigste reduziert. Kein SAML, kein LDAP, keine Flow-Engine — dafür ein einzelner Prozess, der seinen Zustand in einer SQLite-Datei hält. Kein externer Datenbank-Cluster, kein Cache-Deployment, keine Outposts.
Der zweite, eigentlich charmante Aspekt ist die Authentifizierung selbst: Pocket-ID ist von Grund auf passkey-zentriert und setzt auf WebAuthn /FIDO2. Statt Passwörter zu verwalten, melde ich mich mit einem Hardware- oder Plattform-Authenticator an — phishing-resistent und ohne Passwort-Datenbank, die geleakt werden könnte.
Im Cluster ist das Deployment entsprechend unspektakulär: ein Container, eine APP_URL, fertig.
1image: ghcr.io/pocket-id/pocket-id:v2.5.0
2env:
3 - name: APP_URL
4 value: "https://auth.${EXTERNAL_DOMAIN}"
Nach außen hängt der Dienst über eine HTTPRoute am Envoy-Gateway
unter auth.this-is-fine.io, mit TLS aus cert-manager. Das war der gesamte operative Aufwand.
Ein Provider für alles#
Der eigentliche Gewinn zeigt sich erst im Zusammenspiel: Pocket-ID ist heute die eine Stelle, an der sich Menschen im Lab ausweisen. Jeder Dienst, der OIDC spricht, hängt als Client daran:
- Headscale nutzt Pocket-ID für das Tailnet-Enrollment von Menschen — keine manuellen Pre-Auth-Keys mehr, nur noch OIDC-Login, Maschinen behalten ihre getaggten Keys.
- Die Zot-Registry bindet Pocket-ID für den Web-UI-Login der Menschen an, während Maschinen weiterhin über htpasswd authentifizieren.
- Das Envoy-Gateway kann über eine SecurityPolicy sogar Diensten ein OIDC-Login vorschalten, die selbst gar kein SSO können — die Anmeldung passiert dann am Gateway, lange bevor der Request die App erreicht.
Wie ein Dienst andockt#
Spricht eine Anwendung OIDC nativ, braucht sie überraschend wenig: die Issuer-URL, eine client_id, exakt hinterlegte Redirect-URIs und ein Client-Secret. Alles Weitere — Endpunkte, Schlüssel, unterstützte Scopes — holt sie sich selbst über die Discovery unter /.well-known/openid-configuration. Bei der Zot-Registry
steht im Kern nur das hier; Pocket-ID ist der Issuer, die Gruppen aus dem Token mappen auf Registry-Rollen:
1"openid": {
2 "providers": {
3 "oidc": {
4 "issuer": "https://auth.this-is-fine.io",
5 "scopes": ["openid", "profile", "email", "groups"],
6 "claimMapping": { "username": "preferred_username" }
7 }
8 }
9}
Der Login selbst ist der klassische Authorization-Code-Flow — die App übernimmt Session und Consent, ohne dass ein Auth-Proxy davor sitzt:
redirect_uri_mismatch ist der mit Abstand häufigste First-Login-Fehler, und die Meldung kommt aus der IdP-UI, nicht aus den Logs der App.Fazit#
Der Wechsel von Authentik zu Pocket-ID hat mir nicht ein einziges Feature genommen, das ich tatsächlich genutzt habe — wohl aber einen PostgreSQL-Cluster, einen Cache und einen Worker erspart. Übrig bleibt ein einzelner, passkey-erster Prozess, der genau eine Aufgabe erfüllt und sie aus dem Weg geht. Manchmal ist die beste Architekturentscheidung schlicht, das kleinere Werkzeug zu nehmen.
