Ein Haus ohne lokales Active Directory hat kein LDAP, auf das sich zeigen liesse. Eine Verzeichnisquelle hat jetzt eine **Art** — LDAP oder GRAPH —, und beide laufen durch **denselben** Abgleich: anlegen, aktualisieren, deaktivieren, nie loeschen. Nur das Holen der Eintraege unterscheidet sich; zwei Abgleiche nebeneinander wuerden auseinanderdriften, und die Zusage „es wird nichts geloescht“ gaelte dann fuer eine Art und fuer die andere nicht mehr ganz. Gelesen wird mit dem Client-Credentials-Flow, seitenweise ueber @odata.nextLink, der Vorgesetzte ueber $expand=manager($select=id). Das Client-Secret wird verschluesselt gespeichert wie das Bind-Passwort und erreicht keine Antwort und keinen Protokolleintrag. Die Art ist **unveraenderlich**, und das steht nicht im Issue: an ihr haengt, was `externeId` bedeutet. Im AD eine objectGUID, in Entra ID eine andere GUID — nach einem Wechsel wuerde kein einziger Mitarbeiter wiedererkannt, der naechste Abgleich legte die ganze Belegschaft neu an und setzte die alten Zeilen auf aktiv = false, mit allen Laeufen und Geraeten daran. Der teuerste Fund beim Bauen: „in Entra ID deaktiviert“ als *uebersprungen* zu melden haette die Leute **aktiv** gelassen. Uebersprungen heisst im Abgleich „nicht zuordenbar“, und solche Eintraege werden seit #016 absichtlich nicht abgeschaltet. Gefiltert wird deshalb serverseitig mit `$filter=accountEnabled eq true`, als Gegenstueck zum LDAP-Standardfilter. Gefunden hat es der Test — aber nur, weil der Doppelgaenger den Filter wirklich auswertet statt ihn bloss zu empfangen. {{ou}} bleibt bei einer Graph-Quelle leer: Entra ID hat keine OU, und etwas hineinzudeuten waere ein Wert, den kein PowerShell-Befehl brauchen kann — er saehe nur richtig aus. Steht an der Abteilung eine Ziel-OU gepflegt, greift die. Gegen einen echten Entra-Mandanten ist das **nicht** gelaufen. Geprueft ist es gegen einen HTTP-Doppelgaenger mit aufgezeichneten Antworten; die Pruefliste fuer den ersten echten Lauf steht am Ende von docs/betrieb/entra-id.md. Closes #48 Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
72 lines
4.6 KiB
Markdown
72 lines
4.6 KiB
Markdown
# Laufzettel betreiben
|
|
|
|
Diese Sammlung richtet sich an den, der Laufzettel betreibt, aber nicht gebaut hat. Sie führt von
|
|
einem leeren Server bis zur ersten Anmeldung, und danach durch Aktualisierung, Sicherung und
|
|
Fehlersuche. Wer die Anwendung *benutzen* will, liest stattdessen die
|
|
[Anleitung](../anleitung/README.md).
|
|
|
|
Es gibt zwei Wege in den Betrieb. Beide sind gleichwertig und führen zum selben Stand.
|
|
|
|
| Weg | Für wen | Was du mitbringen musst |
|
|
|---|---|---|
|
|
| **[Docker Compose](inbetriebnahme.md)** | Es gibt schon einen Docker-Host, und weitere Dienste laufen dort ebenso. Aktualisieren heißt neu bauen. | Docker mit Compose-Plugin |
|
|
| **[Nativ im Proxmox-LXC](proxmox.md)** | Es gibt einen Proxmox-Host und keinen Docker. Ein Skript legt den Container an und installiert darin alles — PostgreSQL, Node, die Anwendung, einen systemd-Dienst. | Proxmox VE 8 oder 9, oder ein leeres Debian 13 |
|
|
|
|
Nimm den Compose-Weg, wenn du schwankst: er ist der Weg, gegen den hier entwickelt und getestet
|
|
wird. Der `pct`-Teil des Proxmox-Skripts ist ungetestet — das steht so, und warum, in
|
|
[`proxmox.md`](proxmox.md).
|
|
|
|
## Was auf beiden Wegen gilt
|
|
|
|
Vier Dinge sind keine Empfehlung, sondern Teil des Aufbaus. Sie zu übergehen heißt, einen anderen
|
|
Stand zu betreiben als den beschriebenen.
|
|
|
|
**Die Datenbank ist von außen nicht erreichbar.** Im Compose-Stand hat `postgres` kein
|
|
`ports:`-Mapping und hängt nur im Netz `intern`, das `internal: true` ist — ein Netz ohne Gateway.
|
|
Nativ läuft PostgreSQL mit `listen_addresses = ''`, also nur am Unix-Socket. Dieselbe Regel, zwei
|
|
Mittel. Daraus folgt, dass jede Sicherung und jeder Blick in die Daten über den Dienstnamen
|
|
beziehungsweise den Socket läuft, nie über `psql -h localhost`. `tests/betriebsstand.test.ts` hält
|
|
das für den Compose-Stand fest, damit ein `ports:`-Mapping nicht versehentlich zurückkommt.
|
|
|
|
**Die Anwendung bindet auf `127.0.0.1`** und spricht kein HTTPS. Davor gehört ein Reverse Proxy, der
|
|
das Zertifikat hält — siehe [`reverse-proxy.md`](reverse-proxy.md). Ohne Proxy erreicht die
|
|
Anwendung niemand außer dem Host selbst, und das ist die richtige Voreinstellung: ein Dienst, der
|
|
aus Versehen im LAN steht, fällt keinem auf.
|
|
|
|
**`APP_URL` ist die öffentliche Adresse und wird nicht geraten.** Aus ihr entstehen die QR-Adressen
|
|
auf den gedruckten Aufklebern und die OIDC-Rücksprungadresse. Sie später zu ändern ist möglich, aber
|
|
teuer — der Grund steht am Anfang von [`reverse-proxy.md`](reverse-proxy.md). Leg die Adresse fest,
|
|
bevor der erste Aufkleber gedruckt wird.
|
|
|
|
**Geheimnisse entstehen im Zielsystem.** `APP_SECRET`, das Datenbank-Passwort und das erste
|
|
Admin-Passwort werden dort erzeugt, wo sie gelten, und stehen in keinem Repository und in keiner
|
|
Vorlage. `APP_SECRET` gehört mit in die Sicherung: ohne ihn sind nach dem Zurückspielen alle
|
|
Sitzungen ungültig *und* die verschlüsselt gespeicherten LDAP-Bind-Passwörter unlesbar. Siehe
|
|
[`sicherung.md`](sicherung.md).
|
|
|
|
## Die Kapitel
|
|
|
|
- **[Inbetriebnahme mit Docker Compose](inbetriebnahme.md)** — von null bis zur ersten Anmeldung,
|
|
mit der vollständigen Tabelle der Umgebungsvariablen, dem Seed und der Aktualisierung
|
|
- **[Der native Weg im Proxmox-LXC](proxmox.md)** — `deploy/proxmox/laufzettel.sh` und
|
|
`deploy/install.sh`, was sie anlegen, wie ein zweiter Aufruf aktualisiert, und die Prüfliste für
|
|
den ersten echten Lauf
|
|
- **[Reverse Proxy](reverse-proxy.md)** — Caddy und nginx als vollständiges Beispiel, TLS,
|
|
Weiterleitungen, welche Kopfzeilen nötig sind und welche schaden
|
|
- **[Anmeldung über authentik](authentik.md)** — OIDC-Provider, Gruppen auf Rollen, Notfallzugang
|
|
- **[Sichern und Zurückspielen](sicherung.md)** — auf beiden Wegen, was in die Sicherung gehört und
|
|
was nicht, und wie du prüfst, dass das Zurückspielen wirklich funktioniert
|
|
- **[Entra ID als Verzeichnisquelle](entra-id.md)** — App-Registrierung, `User.Read.All`,
|
|
Administratoreinwilligung, und was anders ist als bei einem lokalen AD
|
|
- **[Benachrichtigungen](benachrichtigungen.md)** — SMTP einrichten, den Webhook prüfen, die
|
|
Signatur nachrechnen, und wo man nachsieht, wenn keine Mail mehr ankommt
|
|
|
|
## Wo sonst noch etwas steht
|
|
|
|
- [`../../README.md`](../../README.md) — Kurzfassung für Entwickler, Betriebsmodi, Seed-Inhalt
|
|
- [`../../.env.example`](../../.env.example) — jede Umgebungsvariable mit Kommentar, zum Kopieren
|
|
- [`../architektur.md`](../architektur.md) — warum es so gebaut ist; Abschnitt 6 fasst die
|
|
Betriebsregel zusammen
|
|
- [`../anleitung/08-fehlerbehebung.md`](../anleitung/08-fehlerbehebung.md) — Fehlermeldungen der
|
|
Oberfläche. Wer eine Meldung im Browser sieht, ist dort besser bedient als hier
|