Files
da-HomeNetDocumentation/PI5/Konfiguration/docker/authelia.md
T
2026-06-19 23:18:04 +02:00

590 lines
20 KiB
Markdown
Raw Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Authelia SSO mit Passkey-Unterstützung
**Zusammenfassung**: Authelia als ForwardAuth-Provider für Traefik. Ermöglicht Single Sign-On (SSO) für alle Dienste hinter Traefik mit Passwort, Passkey (WebAuthn/FIDO2) oder beidem.
**Status**: ✅ aktiv Gitea-Login via OIDC funktioniert, Passkey-Config aktualisiert
**Zuletzt aktualisiert**: 2026-06-19 (Live-Daten 21:30)
---
## Architektur
```
Browser ──HTTPS──▶ Traefik (:443)
▼ (ForwardAuth-Middleware)
Authelia ───▶ Session-Check
┌───────┴──────────┐
▼ ▼
Unauthenticated Authenticated
│ │
Login-Seite Weiterleitung zum
(auth.*) eigentlichen Dienst
```
- Authelia läuft als **eigener Docker-Container** im `traefik`-Netzwerk
- Traefik fragt bei jedem Request via **ForwardAuth-Middleware** bei Authelia an:
- „Ist dieser Benutzer eingeloggt und darf auf diese Domain?“
- Bei **Nein** → Redirect zu `auth.da.home-webserver.de`
- Bei **Ja** → Request geht zum eigentlichen Dienst
- **Passkeys (WebAuthn)** werden von Authelia nativ unterstützt als 2FA oder passwordless
---
## Stack: `/opt/compose/authelia/`
### compose.yml
```yaml
services:
authelia:
image: authelia/authelia:latest
container_name: authelia
restart: unless-stopped
networks:
- traefik
volumes:
- ./config:/config
environment:
- TZ=Europe/Berlin
networks:
traefik:
external: true
```
> **Hinweis**: Authelia wird **ohne** Traefik-Labels betrieben, damit es nicht sich selbst durch die ForwardAuth-Middleware blockiert. Stattdessen bekommt es eine eigene Route im File Provider.
---
## Konfiguration
### `config/configuration.yml`
```yaml
###############################################################
# Authelia Konfiguration (v4.39+)
###############################################################
# Server-Adresse (ersetzt host + port)
server:
address: tcp://0.0.0.0:9091
# Logging
log:
level: info
# Speicher SQLite mit encryption_key (Pflicht seit v4.38)
storage:
encryption_key: <openssl rand -hex 32> # 32 Byte Hex für SQLite-Verschlüsselung
local:
path: /config/db.sqlite3
# Authentifizierungs-Backend (file-basiert)
authentication_backend:
file:
path: /config/users.yml
password:
algorithm: argon2id
iterations: 3
salt_length: 16
parallelism: 4
memory: 65536 # KiB = 64 MiB (muss mit CLI-Default übereinstimmen)
# Passkey (WebAuthn) Hauptfeature
# Passwordless-Login ist automatisch aktiv, sobald ein Passkey registriert wurde
webauthn:
enable_passkey_login: true # Neue v4.39-Option
attestation_conveyance_preference: 'direct' # Auf direct geändert (19.06.)
filtering:
prohibit_backup_eligibility: true
metadata:
enabled: true # Metadata-Validierung aktiv (19.06.)
validate_trust_anchor: true
validate_entry: true
validate_status: true
validate_entry_permit_zero_aaguid: false
timeout: 60s
display_name: RaspiPI5 Authelia
# Zugriffsregeln
access_control:
default_policy: deny
rules:
- domain: "auth.da.home-webserver.de"
policy: bypass
- domain: "cloud.da.home-webserver.de"
policy: bypass
- domain: "office.da.home-webserver.de"
policy: bypass
- domain: "git.da.home-webserver.de"
policy: bypass # Gitea: OIDC
- domain: "traefik.da.home-webserver.de"
policy: two_factor
- domain: "prometheus.da.home-webserver.de"
policy: two_factor
- domain: "*.da.home-webserver.de"
policy: one_factor
# Session-Konfiguration
session:
name: authelia_session
secret: <openssl rand -hex 64>
expiration: 8h
inactivity: 2h
remember_me: 30d
cookies:
- domain: da.home-webserver.de
authelia_url: https://auth.da.home-webserver.de
# Regulation Schutz vor Brute-Force
regulation:
max_retries: 5
find_time: 2m
ban_time: 5m
# 2FA (TOTP) optional
totp:
issuer: RaspiPI5
period: 30
skew: 1
# Notifier (Datei, da kein SMTP)
notifier:
filesystem:
filename: /config/notifications.yml
# Passwort-Reset
identity_validation:
reset_password:
jwt_secret: <openssl rand -hex 64>
```
### `config/users.yml`
```yaml
users:
dial:
password: <bcrypt/argon2-hash>
displayname: "Dial"
email: dial-master@gmx.de
groups:
- admins
```
Passwort-Hash erzeugen:
```bash
# Argon2id-Hash generieren (Default-Variante)
docker run --rm authelia/authelia:latest authelia crypto hash generate argon2 --password 'DeinPasswort'
# Mit expliziter Variante (optional):
# docker run --rm authelia/authelia:latest authelia crypto hash generate argon2 --variant argon2id --password 'DeinPasswort'
```
---
## Traefik File Provider: Middleware
### Neue Datei: `/opt/compose/traefik/conf.d/0020-authelia-middleware.yml`
```yaml
http:
middlewares:
# Standard-Auth-Middleware für alle Dienste
chain-authelia:
chain:
middlewares:
- security-headers
- authelia-forwardauth
authelia-forwardauth:
forwardAuth:
address: http://authelia:9091/api/verify?rd=https://auth.da.home-webserver.de/
trustForwardHeader: true
authResponseHeaders:
- Remote-User
- Remote-Groups
- Remote-Name
- Remote-Email
```
> Die Datei heißt `0020-` damit sie zwischen den globalen (`0000-`, `0010-`) und den Service-Routen (`0100-` …) einsortiert wird.
---
## Authelia-Route: `conf.d/0015-authelia-service.yml`
Authelia selbst muss erreichbar sein, **ohne** durch ForwardAuth geschützt zu werden:
```yaml
http:
routers:
authelia:
rule: "Host(`auth.da.home-webserver.de`)"
entryPoints:
- websecure
service: authelia
tls:
certResolver: le
services:
authelia:
loadBalancer:
servers:
- url: "http://authelia:9091"
```
---
## Bestehende Routen anpassen
### 1. `0100-traefik-dashboard.yml` Dashboard & Admin-Dienste
```yaml
# Vorher:
middlewares:
- chain-secure-admin
# Nachher:
middlewares:
- chain-authelia
```
### 2. Standard-App-Routen (`0110-nextcloud.yml`, `0120-paperless.yml`, usw.)
In jeder Service-Route wird die Middleware ausgetauscht:
| Route-Datei | Vorher | Nachher | |
| ---------------------------- | -------------------- | ------------------------------------------------------- | --- |
| `0100-traefik-dashboard.yml` | `chain-secure-admin` | `chain-authelia` | |
| `0110-nextcloud.yml` | `chain-app-standard` | `chain-nextcloud` *(bleibt cloud.* ist auf `bypass`)* | |
| `0120-paperless.yml` | `chain-app-standard` | `chain-authelia` | |
| `0130-immich.yml` | `chain-app-standard` | `chain-authelia` | |
| `0140-wikijs.yml` | `chain-app-standard` | `chain-authelia` | |
| `0150-stirling.yml` | `chain-app-standard` | `chain-authelia` | |
| `0160-plex.yml` | `chain-app-standard` | `chain-authelia` | |
| `0170-nginx.yml` | `chain-app-standard` | `chain-authelia` | |
| `0500-jenkins.yml` | `chain-jenkins` | `chain-authelia` | |
| `0510-gitea.yml` | *(gar keine)* | `chain-authelia` | |
**Beispiel** vorher in `0120-paperless.yml`:
```yaml
middlewares:
- chain-app-standard
```
**Nachher**:
```yaml
middlewares:
- chain-authelia
```
### Achtung: Nextcloud & Collabora
Nextcloud (`cloud.*`) und Collabora (`office.*`) sind in der `access_control`-Regel auf `bypass` gesetzt sie werden von Authelia **übersprungen**, da Nextcloud seinen eigenen Login hat und Collabora nur als iFrame embedded wird.
Trotzdem sollte die Middleware `chain-authelia` in der Route bleiben Traefik leitet dann einfach durch, weil Authelia `bypass` zurückgibt.
---
## OIDC-Integration (SSO für Apps mit OIDC-Support)
Authelia kann als **OpenID Connect (OIDC) Provider** dienen. Dienste wie Immich, Gitea und Wiki.js unterstützen OIDC nativ dann loggst Du Dich direkt über Authelia in der jeweiligen App ein, ohne separates ForwardAuth.
### Architektur (OIDC vs. ForwardAuth)
| ForwardAuth (einfach) | OIDC (für Apps mit Support) |
|---|---|
| Traefik fragt Authelia bei jedem Request | App (z.B. Immich) leitet zur Anmeldung an Authelia weiter |
| Für Dienste **ohne** eigenes Login-System | Für Dienste **mit** OIDC-Support |
| Plex, Stirling PDF, Nginx | Immich, Gitea, Wiki.js, Grafana |
### 1. Authelia als OIDC-Provider aktivieren
In `/opt/compose/authelia/config/configuration.yml` ergänzen:
```yaml
# OIDC-Provider-Konfiguration
identity_providers:
oidc:
hmac_secret: <openssl rand -hex 32>
jwks: # ⚠️ In v4.39 heißt der Key `jwks`, NICHT `issuer_private_keys`!
- key_id: rpid
algorithm: RS256
key: |
-----BEGIN PRIVATE KEY-----
<privater RSA-Key, siehe unten>
-----END PRIVATE KEY-----
clients:
# ---------------------------------------------------------------
# Gitea
# ---------------------------------------------------------------
- id: gitea
description: Gitea SSO
secret: <openssl rand -hex 32>
public: false
authorization_policy: one_factor
redirect_uris:
- https://git.da.home-webserver.de/user/oauth2/authelia/callback
- https://git.da.home-webserver.de/user/oauth2/Authelia/callback # Groß-/Kleinschreibung des Gitea-Provider-Namens!
scopes:
- openid
- profile
- email
consent_mode: pre-configured # Zustimmung vorab erteilt (19.06.)
pre_configured_consent_duration: '3 months'
# ---------------------------------------------------------------
# Immich
# ---------------------------------------------------------------
- id: immich
description: Immich SSO
secret: <openssl rand -hex 32>
public: false
authorization_policy: one_factor
redirect_uris:
- https://photos.da.home-webserver.de/auth/login
- https://photos.da.home-webserver.de/oauth2/callback
scopes:
- openid
- profile
- email
userinfo_signing_algorithm: RS256
# ---------------------------------------------------------------
# Wiki.js
# ---------------------------------------------------------------
- id: wikijs
description: Wiki.js SSO
secret: <openssl rand -hex 32>
public: false
authorization_policy: one_factor
redirect_uris:
- https://wiki.da.home-webserver.de/login
scopes:
- openid
- profile
- email
```
> **RSA-Key erzeugen**:
> ```bash
> openssl genrsa -out /tmp/private.pem 2048
> # Den Inhalt von /tmp/private.pem in die configuration.yml einfügen
> # ACHTUNG: Der Footer muss exakt `-----END PRIVATE KEY-----` (5 Striche) sein, nicht `----` (4 Striche)!
> # Sonst kann Authelia den PEM-Block nicht parsen ("no PEM block was supplied or it was malformed").
> ```
> **Breaking Change in v4.39**:
> - `issuer_private_keys` → `jwks` (wenn der alte Key verwendet wird, startet OIDC nicht)
> - `id` → `client_id` (deprecated)
> - `secret` → `client_secret` (deprecated)
> - `description` → `client_name` (deprecated)
> - Die Deprecation-Warnings sind aktuell noch funktional, werden aber in v5.0 entfernt.
> **redirect_uri Groß-/Kleinschreibung beachten**:
> Gitea verwendet den **Namen der Authentication Source** als Teil des Callback-Pfads:
> ```
> /user/oauth2/<Provider-Name>/callback
> ```
> Wenn der Provider z.B. `Authelia` heißt, ist die Callback-URL:
> ```
> https://git.da.home-webserver.de/user/oauth2/Authelia/callback
> ```
> → Beide Varianten (`authelia` und `Authelia`) in den `redirect_uris` eintragen!
> ✅ **Erledigt** auf dem Pi5 funktioniert seit 21:10.
### 2. Access-Rules anpassen
Dienste mit OIDC brauchen **kein** ForwardAuth mehr sie werden auf `bypass` gesetzt, weil die Authentifizierung direkt zwischen App und Authelia (OIDC) läuft:
```yaml
access_control:
default_policy: deny
rules:
- domain: "auth.da.home-webserver.de"
policy: bypass
- domain: "cloud.da.home-webserver.de"
policy: bypass # Nextcloud: eigener Login
- domain: "office.da.home-webserver.de"
policy: bypass # Collabora: iFrame
- domain: "git.da.home-webserver.de"
policy: bypass # Gitea: OIDC ✅ aktiv
- domain: "photos.da.home-webserver.de"
policy: bypass # Immich: OIDC (geplant)
- domain: "wiki.da.home-webserver.de"
policy: bypass # Wiki.js: OIDC (geplant)
- domain: "traefik.da.home-webserver.de"
policy: two_factor # Admin: ForwardAuth (geplant)
- domain: "prometheus.da.home-webserver.de"
policy: two_factor # Admin: ForwardAuth (geplant)
- domain: "*.da.home-webserver.de"
policy: one_factor # Rest: ForwardAuth
```
### 3. App-Seitige Konfiguration
#### Immich (`.env`)
```properties
# /opt/compose/immich/.env ergänzen
IMMICH_OIDC_ENABLED=true
IMMICH_OIDC_ISSUER_URL=https://auth.da.home-webserver.de
IMMICH_OIDC_CLIENT_ID=immich
IMMICH_OIDC_CLIENT_SECRET=<gleicher secret wie in Authelia>
IMMICH_OIDC_SCOPE=openid profile email
IMMICH_OIDC_AUTO_REGISTER=true
IMMICH_OIDC_SIGNING_ALGORITHM=RS256
```
Danach `docker compose down && docker compose up -d` auf dem Immich-Stack.
#### Gitea (Web-UI)
1. Einstellungen → `https://git.da.home-webserver.de/admin/auths`
2. **"Add Authentication Source"**
- Typ: **OAuth2**
- Name: `Authelia`
- Provider: **OpenID Connect**
- Client ID: `gitea`
- Client Secret: `<gleicher secret wie in Authelia>`
- OpenID Connect Issuer URL: `https://auth.da.home-webserver.de`
3. Speichern
#### Wiki.js (Web-UI)
1. Einstellungen → **"Security"** → **"Authentication"**
2. **"Add Strategy"** → **"OpenID Connect / OAuth2"**
3. Werte:
- Client ID: `wikijs`
- Client Secret: `<gleicher secret wie in Authelia>`
- Authorization URL: `https://auth.da.home-webserver.de/api/oidc/authorization`
- Token URL: `https://auth.da.home-webserver.de/api/oidc/token`
- User Info URL: `https://auth.da.home-webserver.de/api/oidc/userinfo`
- Issuer URL: `https://auth.da.home-webserver.de`
### 4. Traefik-Middleware bei OIDC-Diensten entfernen
Dienste, die auf OIDC umgestellt sind, brauchen **keine** `chain-authelia`-Middleware mehr andernfalls blockiert sich ForwardAuth und OIDC gegenseitig.
**In den conf.d-Dateien** die Middleware auf `bypass` setzen oder ganz entfernen:
```yaml
# /opt/compose/traefik/conf.d/0130-immich.yml
# Vorher:
# middlewares:
# - chain-authelia
# Nachher: keine Middleware (Immich macht OIDC)
```
### Übersicht: ForwardAuth vs. OIDC
| Dienst | Auth-Methode | Middleware in Traefik | policy in Authelia |
|---|---|---|---|
| Traefik-Dashboard | ForwardAuth | `chain-authelia` | `two_factor` |
| Prometheus | ForwardAuth | `chain-authelia` | `two_factor` |
| Paperless | ForwardAuth | `chain-authelia` | `one_factor` |
| Stirling PDF | ForwardAuth | `chain-authelia` | `one_factor` |
| Plex | ForwardAuth | `chain-authelia` | `one_factor` |
| Nginx | ForwardAuth | `chain-authelia` | `one_factor` |
| Jenkins | ForwardAuth | `chain-authelia` | `one_factor` |
| **Immich** | **OIDC** | **keine** | `bypass` |
| **Gitea** | **OIDC** | **keine** | `bypass` |
| **Wiki.js** | **OIDC** | **keine** | `bypass` |
| Nextcloud | eigener Login | `chain-nextcloud` | `bypass` |
| Collabora | iFrame-Bypass | `collabora-headers` | `bypass` |
---
## Optional: `.htpasswd`-Auth entfernen
Sobald Authelia läuft, können diese Konfigurationen entfallen:
- Admin-Benutzer aus `auth/.htpasswd`
- Middleware `auth-admin` (Basic-Auth) in `0010-middlewares.yml`
- Middleware-Chain `chain-secure-admin`
---
## Passkey-Registrierung (erster Benutzer)
1. **Authelia starten**`docker compose up -d`
2. **Erstmalig einloggen** unter `auth.da.home-webserver.de`
3. Nach Login → **"Security"** → **"Register Security Key"** klicken
4. Passkey via Touch ID / Windows Hello / YubiKey registrieren
5. Ab sofort reicht beim Login **Benutzername + Passkey** (Passwort optional)
---
## Migrationsplan (Fortschritt)
| Schritt | Aktion | Status |
| ------- | -------------------------------------------------------------------- | ------ |
| 1 | Compose + Config bereitstellen | ✅ **erledigt** |
| 2 | `0020-authelia-middleware.yml` + `0015-authelia-service.yml` anlegen | ✅ **erledigt** |
| 3 | OIDC-Provider aktivieren (`jwks` statt `issuer_private_keys`) | ✅ **erledigt** (20:01, 18.06.) |
| 4 | Gitea OIDC-Auth-Source einrichten | ✅ **erledigt** (Login funktioniert) |
| 5 | Stirling PDF als ersten Dienst via ForwardAuth schützen | ✅ **erledigt** (`chain-authelia` aktiv) |
| 6 | WebAuthn-Passkey-Config überarbeitet (direct attestation + metadata) | ✅ **erledigt** (19.06.) |
| 7 | OIDC consent_mode auf pre-configured gesetzt | ✅ **erledigt** (19.06.) |
| 8 | Immich OIDC konfigurieren | ⏳ geplant |
| 9 | Wiki.js OIDC konfigurieren | ⏳ geplant |
| 10 | Traefik-Dashboard, Prometheus auf ForwardAuth umstellen | ⏳ geplant |
| 11 | Paperless, Plex, Nginx, Jenkins auf ForwardAuth umstellen | ⏳ geplant |
| 12 | `.htpasswd` und `auth-admin` entfernen | ⏳ geplant |
### Aktuelle Routing-Übersicht (Live vom 18.06., 20:00)
| Dienst | Route | Auth-Methode | Status |
|---|---|---|---|
| Authelia (Portal) | `auth.*` | keine (bypass) | ✅ |
| Nextcloud | `cloud.*` | kein Auth (bypass) | ✅ |
| Collabora | `office.*` | kein Auth (bypass) | ✅ |
| Gitea | `git.*` | OIDC (ohne Middleware) | 🔄 Gitea-WebUI-Konfiguration ausstehend |
| Stirling PDF | `pdf.*` | ForwardAuth (`chain-authelia`) | ✅ |
| Immich | `photos.*` | `chain-app-standard` (offen) | ⏳ |
| Wiki.js | `wiki.*` | `chain-app-standard` (offen) | ⏳ |
| Paperless | `paperless.*` | `chain-app-standard` (offen) | ⏳ |
| Plex | `music.*` | `chain-app-standard` (offen) | ⏳ |
| Nginx | `web.*` | `chain-app-standard` (offen) | ⏳ |
| Jenkins | `jenkins.*` | `chain-jenkins` (offen) | ⏳ |
| Traefik Dashboard | `traefik.*` | Basic-Auth | ⏳ |
| Prometheus | `prometheus.*` | Basic-Auth | ⏳ |
| Grafana | `grafana.*` | Grafana-intern | |
---
## Backup / Wiederherstellung
Das SQLite-DB enthält alle Benutzer-Sessions und registrierte Passkeys:
```bash
# Sichern
cp /opt/compose/authelia/config/db.sqlite3 /backup/authelia-db.sqlite3
# Wiederherstellen
cp /backup/authelia-db.sqlite3 /opt/compose/authelia/config/db.sqlite3
```
Die Users-Datei und Config sind YAML ideal für Git-Versionierung.
---
## Ressourcenverbrauch (geschätzt)
| Metrik | Wert |
|---|---|
| RAM | ~5080 MB |
| CPU | vernachlässigbar (Go-Binary) |
| Speicher | ~50 MB (SQLite + Config) |
| Image-Größe | ~75 MB (linux/arm64) |
---
## Verwandte Seiten
- [traefik](./traefik.md) Reverse-Proxy-Grundkonfiguration
- [docker-services](../docker-services.md) Alle Dienste im Überblick
- [Authelia Dokumentation](https://www.authelia.com/configuration/)