keycloak_bootstrap: parametrisierbar für baremetal-Prod
Das Bootstrap-Skript funktioniert jetzt gegen jede Keycloak-Instanz (Dev-Docker wie baremetal-Prod) und nimmt Realm + Server-Adresse als Parameter: - --url <basis-inkl-port>, --realm <name> (überschreibt den Namen in der JSON-Payload), --admin/--admin-password. - --provisioner-secret <s>: ersetzt das Dev-Secret in der Payload (Prod). - --no-test-user: entfernt "testfahrer" aus der Payload (Prod). - Docker wird per Default NICHT mehr angefasst (Prod=baremetal); nur via --up. - Alle Optionen auch via Env; CLI hat Vorrang. README: parametrisierte Nutzung (Dev + Prod-Beispiel) + Abschnitt "Wie die Authentifizierung funktioniert" (Skript→Keycloak Admin-Grant; Laufzeit App↔Backend↔Keycloak: PKCE-Login, JWKS-JWT-Validierung mit aud/iss, Provisioner client-credentials, X-Admin-Api-Key für /admin). Verifiziert gegen Dev-Keycloak: custom Realm + überschriebenes Secret + --no-test-user erzeugt korrekten Realm; Test-Realm danach wieder entfernt. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
57
README.md
57
README.md
@ -47,20 +47,61 @@ Admin-UI Änderungen macht, sollte sie **in die JSON zurückspielen**.
|
||||
|
||||
**Wichtig:** Das compose-`--import-realm` greift nur beim **ersten** Start
|
||||
(solange das `keycloak-data`-Volume leer ist) — spätere JSON-Änderungen landen
|
||||
NICHT automatisch in Keycloak. Zum Anwenden/Bootstrappen:
|
||||
NICHT automatisch in Keycloak. Realm anwenden/bootstrappen geht daher über
|
||||
`tool/keycloak_bootstrap.sh` (spricht nur die Admin-REST-API an, funktioniert
|
||||
gegen **Dev-Docker wie baremetal-Prod**):
|
||||
|
||||
```bash
|
||||
# Importiert den Realm über die Admin-REST-API (idempotent, startet Keycloak
|
||||
# bei Bedarf via docker compose). Tut nichts, falls der Realm schon existiert.
|
||||
./tool/keycloak_bootstrap.sh
|
||||
# Dev (lokales Docker mit hochfahren, Default-Realm "holzleitner")
|
||||
./tool/keycloak_bootstrap.sh --up
|
||||
|
||||
# Production (baremetal Keycloak, eigener Realm, frisches Secret, kein Test-User)
|
||||
./tool/keycloak_bootstrap.sh \
|
||||
--url https://auth.holzleitner.de \
|
||||
--realm holzleitner-prod \
|
||||
--admin kc-admin --admin-password "$KC_PW" \
|
||||
--provisioner-secret "$(openssl rand -hex 24)" \
|
||||
--no-test-user
|
||||
|
||||
# Sauberer Neu-Import (LÖSCHT den Realm inkl. provisionierter Fahrer-Konten):
|
||||
./tool/keycloak_bootstrap.sh --reset
|
||||
./tool/keycloak_bootstrap.sh --url ... --realm ... --reset
|
||||
```
|
||||
|
||||
Das Skript gibt am Ende die `[keycloak]`-Werte aus, die in die `config.toml`
|
||||
gehören (issuer_url, audience, provisioner-secret …). Overrides via
|
||||
`KC_URL` / `KC_ADMIN` / `KC_ADMIN_PASSWORD` / `REALM_FILE`.
|
||||
Wichtigste Optionen: `--url` (Keycloak-Basis inkl. Port), `--realm` (Realm-Name),
|
||||
`--admin`/`--admin-password`, `--provisioner-secret`, `--no-test-user`, `--reset`,
|
||||
`--up`. Alles auch via Env (`KC_URL`, `REALM`, `KC_ADMIN`, `KC_ADMIN_PASSWORD`,
|
||||
`PROVISIONER_SECRET`, `REALM_FILE`). Default ohne `--up` wird **kein** Docker
|
||||
angefasst. Das Skript gibt am Ende die passenden `[keycloak]`-Werte für die
|
||||
`config.toml` aus.
|
||||
|
||||
### Wie die Authentifizierung funktioniert
|
||||
|
||||
Es gibt zwei getrennte Auth-Kontexte:
|
||||
|
||||
**a) Bootstrap-Skript → Keycloak (einmalig/selten).** Das Skript meldet sich am
|
||||
`master`-Realm über den eingebauten Client `admin-cli` per Passwort-Grant an
|
||||
(`--admin`/`--admin-password`) und nutzt das Admin-Token nur, um den Realm
|
||||
anzulegen. In Prod ein echtes Admin-Konto + HTTPS verwenden; das Passwort besser
|
||||
über die Env-Variable `KC_ADMIN_PASSWORD` setzen (nicht in der History).
|
||||
|
||||
**b) Laufzeit — App ↔ Backend ↔ Keycloak.**
|
||||
1. Die Flutter-App loggt sich per **OIDC Authorization Code + PKCE** gegen
|
||||
`{KC_URL}/realms/{realm}` ein und erhält ein **Access-Token (JWT, RS256)** mit
|
||||
`aud=holzleitner-api`, Claim `personalnummer` und Realm-Rolle `driver`.
|
||||
2. Das Backend **validiert das JWT public-key-basiert**: es holt die Realm-JWKS
|
||||
von `{issuer}/protocol/openid-connect/certs`, prüft Signatur, `iss` (==
|
||||
`config.toml [keycloak] issuer_url`), `aud` (enthält `holzleitner-api`) und
|
||||
Ablauf. Kein gemeinsames Secret nötig — nur der öffentliche Schlüssel.
|
||||
3. Die `/admin`-Maschinen-Endpunkte des Backends laufen NICHT über Keycloak,
|
||||
sondern über den statischen `X-Admin-Api-Key` (siehe `[admin] api_key`).
|
||||
4. Der **Provisioner** (`holzleitner-provisioner`, confidential, Client-
|
||||
Credentials-Grant mit `manage-users`) wird vom ERP-Sync genutzt, um neue
|
||||
Fahrer-Konten im Realm anzulegen — dafür gilt das `provisioner_client_secret`.
|
||||
|
||||
Damit b) klappt, müssen `issuer_url`/`realm`/`admin_url` in der `config.toml`
|
||||
**exakt** auf denselben Server + Realm zeigen, den das Skript angelegt hat — und
|
||||
`issuer_url` muss dem von Keycloak ausgestellten `iss`-Claim entsprechen (in
|
||||
Prod also Keycloaks Frontend-/Hostname-URL korrekt setzen, sonst `invalid issuer`).
|
||||
|
||||
### Token für Dev-Tests holen
|
||||
|
||||
|
||||
Reference in New Issue
Block a user