Files
Laufzettel/docs/betrieb/README.md
T
Florian WildeandClaude Opus 5 76a61ec771
Prüfung / pruefung (push) Canceled after 0s
Prüfung / e2e (push) Canceled after 0s
feat(verzeichnis): Entra ID als Quelle ueber Microsoft Graph (#48)
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>
2026-10-06 23:36:36 +02:00

4.6 KiB

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.

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 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 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.

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. 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. 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.

Die Kapitel

  • Inbetriebnahme mit Docker Compose — von null bis zur ersten Anmeldung, mit der vollständigen Tabelle der Umgebungsvariablen, dem Seed und der Aktualisierung
  • Der native Weg im Proxmox-LXC — 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 — Caddy und nginx als vollständiges Beispiel, TLS, Weiterleitungen, welche Kopfzeilen nötig sind und welche schaden
  • Anmeldung über authentik — OIDC-Provider, Gruppen auf Rollen, Notfallzugang
  • Sichern und Zurückspielen — 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 — App-Registrierung, User.Read.All, Administratoreinwilligung, und was anders ist als bei einem lokalen AD
  • Benachrichtigungen — SMTP einrichten, den Webhook prüfen, die Signatur nachrechnen, und wo man nachsieht, wenn keine Mail mehr ankommt

Wo sonst noch etwas steht