Initial commit: Keycloak SSO for MischLabs

Keycloak 26.1 + PostgreSQL 16 Docker stack with pre-configured
realm containing 10 OIDC clients for all MischLabs services.
Includes integration guides for Tier 1-3 services.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Kroonk
2026-04-13 20:42:59 +02:00
commit 8a4beb879a
5 changed files with 504 additions and 0 deletions

172
Brain.md Normal file
View File

@@ -0,0 +1,172 @@
# Brain.md - Projekt auth.mischlabs.de (Keycloak SSO)
## Projektziel
Zentrales Single Sign-On (SSO) fuer alle MischLabs-Dienste ueber Keycloak. Laeuft als Docker-Container-Stack (Keycloak + PostgreSQL) auf MischNAS und ist ueber Cloudflare Tunnel erreichbar.
## Status
- [x] Git-Repo initialisiert und Remote verbunden (https://git.mischlabs.de/MrDiderot/auth.git)
- [x] docker-compose.yml mit Keycloak + PostgreSQL erstellt
- [x] Realm-Konfiguration als JSON (mischlabs-realm.json) mit 10 Clients
- [x] .env.example und .gitignore erstellt
- [ ] .env mit echten Passwoertern auf der NAS anlegen
- [ ] Erster Push zum Remote (Git-Auth-Fehler, muss manuell gepusht werden)
- [ ] Deployment auf MischNAS (docker compose up -d)
- [ ] Cloudflare Tunnel Route fuer auth.mischlabs.de -> localhost:8180
- [ ] Client Secrets aus Keycloak Admin-Console holen
- [ ] Tier-1-Dienste anbinden (Gitea, Nextcloud, Mealie, Docs)
- [ ] Tier-2-Dienste anbinden (Audiobookshelf, Vaultwarden, PocketBase)
- [ ] Tier-3-Dienste via Cloudflare Access (Jellyfin, MiChess)
## Dienste-Integration (9 + Cloudflare Access)
| # | Client ID | Subdomain | Tier | Status |
|---|-----------|-----------|------|--------|
| 1 | gitea | git.mischlabs.de | 1 - Nativ OIDC | Offen |
| 2 | nextcloud | drive.mischlabs.de | 1 - Nativ OIDC | Offen |
| 3 | mealie | foodlabs.mischlabs.de | 1 - Nativ OIDC | Offen |
| 4 | docs | docs.mischlabs.de | 1 - Nativ OIDC | Offen |
| 5 | audiobookshelf | audiobook.mischlabs.de | 2 - Teilweise | Offen |
| 6 | vaultwarden | password.mischlabs.de | 2 - Teilweise | Offen |
| 7 | pocketbase | tom.mischlabs.de | 2 - Teilweise | Offen |
| 8 | jellyfin | movies.mischlabs.de | 3 - CF Access | Offen |
| 9 | michess | michess.mischlabs.de | 3 - CF Access | Offen |
| 10 | cloudflare-access | Cloudflare Zero Trust | Proxy-Auth | Offen |
## Integrations-Anleitungen pro Dienst
### Tier 1: Native OIDC
**Gitea** (git.mischlabs.de)
- Admin > Authentication Sources > Add > OAuth2 > OpenID Connect
- Client ID: `gitea`, Secret: aus Keycloak
- Discovery URL: `https://auth.mischlabs.de/realms/mischlabs/.well-known/openid-configuration`
**Nextcloud** (drive.mischlabs.de)
- App `oidc_login` installieren, config.php:
```
'oidc_login_provider_url' => 'https://auth.mischlabs.de/realms/mischlabs',
'oidc_login_client_id' => 'nextcloud',
'oidc_login_client_secret' => '<aus-keycloak>',
'oidc_login_auto_redirect' => false,
'oidc_login_button_text' => 'MischLabs SSO',
```
**Mealie** (foodlabs.mischlabs.de)
- Environment Variables:
```
OIDC_AUTH_ENABLED=true
OIDC_CONFIGURATION_URL=https://auth.mischlabs.de/realms/mischlabs/.well-known/openid-configuration
OIDC_CLIENT_ID=mealie
OIDC_CLIENT_SECRET=<aus-keycloak>
OIDC_AUTO_REDIRECT=false
OIDC_PROVIDER_NAME=MischLabs SSO
OIDC_USER_GROUP=user
OIDC_ADMIN_GROUP=admin
```
**Docs** (docs.mischlabs.de) - BookStack Beispiel:
```
AUTH_METHOD=oidc
OIDC_NAME=MischLabs SSO
OIDC_CLIENT_ID=docs
OIDC_CLIENT_SECRET=<aus-keycloak>
OIDC_ISSUER=https://auth.mischlabs.de/realms/mischlabs
OIDC_ISSUER_DISCOVER=true
```
### Tier 2: Teilweise OIDC
**Audiobookshelf** (audiobook.mischlabs.de)
- Settings > Authentication > OpenID Connect
- Issuer URL: `https://auth.mischlabs.de/realms/mischlabs`
- WICHTIG: In Keycloak Admin > audiobookshelf Client > Advanced > User Info Signed Response Algorithm auf leer/none setzen
- Notfall-Login: `https://audiobook.mischlabs.de/login/?autoLaunch=0`
**Vaultwarden** (password.mischlabs.de)
- Environment Variables:
```
SSO_ENABLED=true
SSO_PKCE=true
SSO_AUTHORITY=https://auth.mischlabs.de/realms/mischlabs
SSO_CLIENT_ID=vaultwarden
SSO_CLIENT_SECRET=<aus-keycloak>
```
- HINWEIS: Master-Passwort bleibt weiterhin noetig!
**PocketBase** (tom.mischlabs.de)
- Admin > Settings > Auth Providers > OIDC konfigurieren
- Erstellt eigene User-Records, verlinkt mit OAuth2-Identitaet
### Tier 3: Cloudflare Access
**Jellyfin + MiChess** - Kein natives OIDC
1. In Cloudflare Zero Trust > Settings > Authentication > Add OpenID Connect:
- App ID: `cloudflare-access`, Secret: aus Keycloak
- Auth URL: `https://auth.mischlabs.de/realms/mischlabs/protocol/openid-connect/auth`
- Token URL: `https://auth.mischlabs.de/realms/mischlabs/protocol/openid-connect/token`
- Certificate URL: `https://auth.mischlabs.de/realms/mischlabs/protocol/openid-connect/certs`
2. Access > Applications > Self-hosted > movies.mischlabs.de / michess.mischlabs.de
3. Policy: Allow > Emails oder Gruppen definieren
## Technische Entscheidungen
- **Keycloak 26.1** (quay.io/keycloak/keycloak:26.1) - aktuelles stabiles Release
- **PostgreSQL 16-alpine** als Datenbank - leichtgewichtig, bewaehrt
- **Realm-Import via JSON** (`--import-realm`) - versionskontrolliert, reproduzierbar
- **`start` (nicht `start-dev`)** - Produktionsmodus mit sicheren Defaults
- **KC_PROXY_HEADERS=xforwarded** - fuer Cloudflare Tunnel
- **KC_HOSTNAME=https://auth.mischlabs.de** - volle URL inkl. Schema
- **KC_HTTP_ENABLED=true** - SSL wird von Cloudflare terminiert
- **Port 8180** - vermeidet Konflikte mit bestehenden Diensten
- **PostgreSQL nicht exponiert** - nur ueber Docker-Netzwerk erreichbar
- **Client Secrets nicht im JSON** - werden von Keycloak auto-generiert
## Docker-Setup
- **Container-Namen**: `auth` (Keycloak), `auth-db` (PostgreSQL)
- **Images**: quay.io/keycloak/keycloak:26.1, postgres:16-alpine
- **Port-Mapping**: 8180:8080 (Keycloak HTTP), 9000:9000 (Health/Metrics, nur lokal!)
- **Volumes**: `auth_pgdata` (PostgreSQL-Daten), `./realm` (Realm-Import, read-only)
- **Netzwerk**: `auth-network` (Bridge, nur intern)
- **Health-Checks**: PostgreSQL via pg_isready, Keycloak via /health/ready (Port 9000)
## Dateistruktur
```
auth/
docker-compose.yml - Keycloak + PostgreSQL Stack
.env.example - Vorlage fuer Secrets (in Git)
.env - Echte Secrets (NICHT in Git!)
realm/
mischlabs-realm.json - Realm mit allen 10 Clients
Brain.md - Dieses Dokument (KI-Uebergabe)
.gitignore - Schliesst .env und .claude/ aus
```
## Deployment-Workflow
1. Repo auf Gitea erstellen: `auth`
2. Code pushen: `git push -u origin master`
3. Auf MischNAS:
```
cd /volume2/docker
git clone https://git.mischlabs.de/MrDiderot/auth.git
cd auth
cp .env.example .env
nano .env # Echte Passwoerter eintragen (openssl rand -base64 32)
docker compose up -d
```
4. Cloudflare Tunnel: Route `auth.mischlabs.de` -> `http://localhost:8180`
5. Admin-Console: https://auth.mischlabs.de/admin/mischlabs/console/
6. Client Secrets holen und in Dienste konfigurieren
## Wichtige URLs
- Admin-Console: https://auth.mischlabs.de/admin/mischlabs/console/
- OIDC Discovery: https://auth.mischlabs.de/realms/mischlabs/.well-known/openid-configuration
- Health-Check: http://localhost:9000/health/ready (nur lokal)
## Erkenntnisse & Notizen
- KC_BOOTSTRAP_ADMIN_* wird nur beim allerersten Start verarbeitet
- Client Secrets muessen nach dem Start aus der Admin-Console geholt werden
- Audiobookshelf hat bekannte Bugs mit Keycloak (UserInfo Signing Algorithm)
- Vaultwarden SSO ersetzt NICHT das Master-Passwort (nur Authentifizierung)
- Jellyfin hat kein natives OIDC - Community-Plugin oder Cloudflare Access
- Port 9000 NICHT ueber Cloudflare Tunnel exponieren (nur Health/Metrics)
- Bei Realm-Import: `--import-realm` ueberspringt bereits existierende Realms
- Git-Push schlug fehl (Auth-Fehler) - muss manuell mit frischem Token gepusht werden
- Verwandtes Projekt: mischlabs Landing Page (d:\Vibecoding\Website\mischlabs)