8045e22873
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
187 lines
9.0 KiB
Markdown
187 lines
9.0 KiB
Markdown
# Authelia OIDC fuer Apps - Plan & Runbook
|
|
|
|
Stand: 2026-06-06. Authelia-Version: **v4.39.20**.
|
|
|
|
Ziel: App-uebergreifendes Single-Sign-On ueber Authelia als OpenID-Connect-Provider
|
|
(`https://auth.kaleschke.info`). Statt pro App eigener Logins meldet man sich einmal
|
|
bei Authelia an (inkl. 2FA) und wird per OIDC an die App durchgereicht.
|
|
|
|
> **Status:** aktives Runbook. Grafana und Mealie sind seit 2026-06-06 live
|
|
> und per Login-Smoke verifiziert. Der weitere Rollout bleibt additiv: lokale
|
|
> App-Logins bleiben als Fallback aktiv.
|
|
|
|
---
|
|
|
|
## Grundregeln (wichtig)
|
|
|
|
- **Secrets gehoeren nie ins Repo.** OIDC-Client-Secrets (Klartext und pbkdf2-Hash)
|
|
liegen ausschliesslich in der Host-Config `/mnt/user/appdata/authelia/config/configuration.yml`
|
|
(Hash) und im jeweiligen App-Stack (Klartext, via Komodo Stack-ENV / Secret-Datei),
|
|
plus optional Vaultwarden. Dieses Dokument enthaelt nur Schema und Variablennamen.
|
|
- **OIDC-Clients leben host-seitig**, wie der bestehende `beszel`-Client. Die Repo-Baseline
|
|
`security/authelia/configuration.yml` haelt nur die nicht-geheime Struktur
|
|
(`access_control` etc.); `services/authelia-diff.sh` vergleicht standardmaessig nur
|
|
`access_control`, OIDC-Clients auf dem Host loesen also keinen Drift-Alarm aus.
|
|
- **Issuer/Endpoints** (Authelia OIDC):
|
|
- Issuer: `https://auth.kaleschke.info`
|
|
- Authorization: `https://auth.kaleschke.info/api/oidc/authorization`
|
|
- Token: `https://auth.kaleschke.info/api/oidc/token`
|
|
- Userinfo: `https://auth.kaleschke.info/api/oidc/userinfo`
|
|
- JWKS: `https://auth.kaleschke.info/jwks.json`
|
|
- Discovery: `https://auth.kaleschke.info/.well-known/openid-configuration`
|
|
- **PKCE an, wo moeglich** (`require_pkce: true`, `S256`), wie beim Beszel-Client.
|
|
|
|
---
|
|
|
|
## Client-Schema (Authelia v4.39, gespiegelt vom bestehenden `beszel`-Client)
|
|
|
|
Pro App ein Block unter `identity_providers.oidc.clients` in der **Host-Config**:
|
|
|
|
```yaml
|
|
identity_providers:
|
|
oidc:
|
|
clients:
|
|
- client_id: '<app>'
|
|
client_name: '<App-Name>'
|
|
client_secret: '<pbkdf2-sha512-Hash - NUR auf dem Host>'
|
|
public: false
|
|
authorization_policy: 'two_factor' # admin-Apps: two_factor; Familien-Apps: s.u.
|
|
require_pkce: true
|
|
pkce_challenge_method: 'S256'
|
|
redirect_uris:
|
|
- 'https://<app>.kaleschke.info/<oidc-callback-pfad>'
|
|
scopes:
|
|
- 'openid'
|
|
- 'profile'
|
|
- 'email'
|
|
- 'groups'
|
|
response_types:
|
|
- 'code'
|
|
grant_types:
|
|
- 'authorization_code'
|
|
token_endpoint_auth_method: 'client_secret_basic'
|
|
userinfo_signed_response_alg: 'none'
|
|
```
|
|
|
|
### Client-Secret erzeugen (auf dem Host)
|
|
|
|
```bash
|
|
docker exec authelia authelia crypto hash generate pbkdf2 \
|
|
--variant sha512 --random --random.length 72 --random.charset rfc3986
|
|
```
|
|
|
|
- Ausgabe: **Random Password** (Klartext) + **Digest** (pbkdf2-Hash).
|
|
- **Hash** -> Host-Config `client_secret`.
|
|
- **Klartext** -> App-Stack (Komodo Stack-ENV/Secret) + optional Vaultwarden.
|
|
- Klartext **nicht** ins Repo, nicht in Logs.
|
|
|
|
---
|
|
|
|
## Reihenfolge / Rollout
|
|
|
|
| Stufe | App | Domain | OIDC-Support | Policy | Risiko | Begruendung |
|
|
|---|---|---|---|---|---|---|
|
|
| **1 (Proof) ERLEDIGT 2026-06-06** | Grafana (monitoring) | `monitoring.kaleschke.info` | nativ (`generic_oauth`) | `two_factor` | niedrig | **Live + Login verifiziert.** Authelia-Client `grafana` (host), Secret als Datei `/mnt/user/appdata/secrets/grafana_oidc_client_secret` via `__FILE`, ForwardAuth-Middleware durch OIDC ersetzt, lokaler Admin bleibt Fallback |
|
|
| 2 | Immich | `immich.kaleschke.info` | nativ (Admin-UI/Config-File) | s. u. (Familie) | mittel | **GEPARKT bis Onboarding (Entscheidung 2026-06-06):** nur `micha` hat Authelia-Account, Familien-SSO-Nutzen entsteht erst mit Familien-Accounts; Immich ist mobil-lastig (hoechste Stoeranfaelligkeit) und braucht UI/Config-File. Erst nach Onboarding gezielt. Runbook bereit. |
|
|
| 3 | Nextcloud | `cloud.kaleschke.info` | App `user_oidc` (+occ) | s. u. | mittel | **GEPARKT bis Onboarding (Entscheidung 2026-06-06):** wie Immich; braucht `user_oidc`-App-Install + `occ`. Lokaler Login bleibt. Erst nach Onboarding. Runbook bereit. |
|
|
| **4 ERLEDIGT 2026-06-06** | Mealie | `mealie.kaleschke.info` | nativ | `one_factor` | niedrig | **Live + Login verifiziert.** OIDC-Env additiv (lokaler Login bleibt), Secret als Stack-ENV `${MEALIE_OIDC_CLIENT_SECRET}`, `extra_hosts` noetig (s. Gotchas) |
|
|
| 5 | Paperless-ngx | `paperless.kaleschke.info` | `django-allauth` (Umgebungsvariablen) | `two_factor` | mittel | dokumentenlastig, Operator-nah |
|
|
|
|
**Nicht OIDC:** Vaultwarden hat kein Standard-Endnutzer-OIDC (SSO ist Enterprise/Bitwarden-Feature) -> bleibt eigener Login. ntfy bleibt wie gehabt.
|
|
|
|
### Policy Familien-Apps
|
|
|
|
- Admin-Apps (Grafana, Paperless): `authorization_policy: two_factor`.
|
|
- Familien-Apps (Immich, Nextcloud, Mealie): Start mit `one_factor` und lokalen
|
|
App-Logins als Fallback. 2FA fuer Familie erst spaeter, sobald TOTP-Enrollment
|
|
pro Person eingerichtet ist; sonst entsteht unnoetiges Lockout-Risiko.
|
|
|
|
---
|
|
|
|
## Stufe 1 konkret: Grafana (empfohlener Erststart)
|
|
|
|
### A) Authelia (Host) - Client anlegen
|
|
1. Secret erzeugen (Befehl oben). Klartext + Hash notieren.
|
|
2. In `/mnt/user/appdata/authelia/config/configuration.yml` unter
|
|
`identity_providers.oidc.clients` neuen Block einfuegen:
|
|
```yaml
|
|
- client_id: 'grafana'
|
|
client_name: 'Grafana'
|
|
client_secret: '<HASH>'
|
|
public: false
|
|
authorization_policy: 'two_factor'
|
|
require_pkce: true
|
|
pkce_challenge_method: 'S256'
|
|
redirect_uris:
|
|
- 'https://monitoring.kaleschke.info/login/generic_oauth'
|
|
scopes: ['openid', 'profile', 'email', 'groups']
|
|
response_types: ['code']
|
|
grant_types: ['authorization_code']
|
|
token_endpoint_auth_method: 'client_secret_basic'
|
|
userinfo_signed_response_alg: 'none'
|
|
```
|
|
3. `docker restart authelia`, Health + Log pruefen (`Startup complete`, keine Fehler).
|
|
|
|
### B) Grafana (Komodo Stack-ENV) - generic_oauth
|
|
Im `monitoring`-Stack (Grafana) setzen (Klartext-Secret aus Schritt A):
|
|
```
|
|
GF_AUTH_GENERIC_OAUTH_ENABLED=true
|
|
GF_AUTH_GENERIC_OAUTH_NAME=Authelia
|
|
GF_AUTH_GENERIC_OAUTH_CLIENT_ID=grafana
|
|
GF_AUTH_GENERIC_OAUTH_CLIENT_SECRET=<KLARTEXT-SECRET>
|
|
GF_AUTH_GENERIC_OAUTH_SCOPES=openid profile email groups
|
|
GF_AUTH_GENERIC_OAUTH_AUTH_URL=https://auth.kaleschke.info/api/oidc/authorization
|
|
GF_AUTH_GENERIC_OAUTH_TOKEN_URL=https://auth.kaleschke.info/api/oidc/token
|
|
GF_AUTH_GENERIC_OAUTH_API_URL=https://auth.kaleschke.info/api/oidc/userinfo
|
|
GF_AUTH_GENERIC_OAUTH_USE_PKCE=true
|
|
GF_AUTH_GENERIC_OAUTH_ALLOW_SIGN_UP=true
|
|
# optional Rollen-Mapping ueber groups:
|
|
# GF_AUTH_GENERIC_OAUTH_ROLE_ATTRIBUTE_PATH=contains(groups[*], 'admins') && 'Admin' || 'Viewer'
|
|
```
|
|
- `GF_AUTH_GENERIC_OAUTH_CLIENT_SECRET` als Stack-ENV-only (kein `_FILE`-Support) -> in
|
|
`docs/SECRETS_MAP.md` als `grafana_oidc_client_secret` (Stack-ENV) nachziehen.
|
|
|
|
### C) Test + Rollback
|
|
- Test: `monitoring.kaleschke.info` -> "Sign in with Authelia" -> Authelia-Login (2FA) -> zurueck in Grafana, eingeloggt.
|
|
- **Fallback bleibt:** lokaler Grafana-Admin-Login (`/login`) ist weiter aktiv -> kein Lockout.
|
|
- Rollback: `GF_AUTH_GENERIC_OAUTH_ENABLED=false` (Grafana redeploy) und/oder Client-Block in Authelia entfernen + `docker restart authelia`.
|
|
|
|
---
|
|
|
|
## Doku-Nachzug bei jedem neuen Client
|
|
|
|
- `docs/SECRETS_MAP.md`: pro App `<app>_oidc_client_secret` (Stack-ENV) + Hinweis "Hash in Authelia-Host-Config".
|
|
- `docs/SERVICE_CATALOG.md`: App-Zeile um "OIDC via Authelia" ergaenzen.
|
|
- Dieses Dokument: Rollout-Tabelle abhaken.
|
|
- `docs/MASTER_TODO.md`: Fortschritt im OIDC-Punkt nachziehen.
|
|
|
|
---
|
|
|
|
## Gotchas (aus dem realen Rollout 2026-06-06)
|
|
|
|
- **`extra_hosts` ist Pflicht fuer App-Container, die selbst zu Authelia connecten**
|
|
(OIDC-Discovery/Token sind Server-zu-Server): Der App-Container loest
|
|
`auth.kaleschke.info` per Docker-DNS oft nicht auf -> `httpx.ConnectTimeout` /
|
|
500 beim OAuth-Start. Fix wie Komodo:
|
|
```yaml
|
|
extra_hosts:
|
|
- "auth.kaleschke.info:192.168.178.58"
|
|
```
|
|
Cert validiert weiter (SNI/Hostname bleibt gleich, nur die IP wird gemappt).
|
|
Gilt fuer Mealie (bestaetigt) und sehr wahrscheinlich Paperless/Immich/Nextcloud.
|
|
- **Additiv heisst additiv:** OIDC als zusaetzlichen Login aktivieren, lokalen
|
|
Login NICHT abschalten, `AUTO_REDIRECT`/Force-OIDC aus -> kein Lockout.
|
|
- **Account-Linking per E-Mail:** Apps verknuepfen den OIDC-User i. d. R. per
|
|
E-Mail-Claim. Stimmt die Authelia-E-Mail mit dem App-Account, wird verknuepft;
|
|
sonst legt die App (bei aktivem Signup) einen neuen User an.
|
|
- **Secret-Mechanik je App verschieden:** Grafana `__FILE` (Docker-Secret),
|
|
Mealie Stack-ENV `${...}`. Hash immer in der Authelia-Host-Config, Klartext nie ins Repo.
|
|
|
|
## Spaetere Feinschliffe vor breitem Rollout
|
|
|
|
1. Gruppen/Rollen-Mapping: braucht es Authelia-Gruppen (z. B. `admins`, `family`) fuer
|
|
App-Rollen (Grafana Admin/Viewer, Nextcloud-Gruppen)? Wenn ja, in der Authelia
|
|
User-Datenbank Gruppen pflegen.
|
|
2. Familien-2FA spaeter neu bewerten, nachdem echte Familien-Accounts in Authelia
|
|
angelegt und TOTP pro Person verstanden ist.
|