Files
Laufzettel/docs/anleitung/06-verzeichnis.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

9.8 KiB

Verzeichnis anbinden

Unter Admin → Verzeichnis wird ein Active Directory als Quelle der Personen eingerichtet. Dann muss beim Start eines Laufs nichts abgetippt werden, und {{vorname}}, {{upn}}, {{sam}} und {{abteilung}} stehen von selbst zur Verfügung.

Zwei Dinge vorweg:

  • Der Reiter gibt es nur im Modus Intern. Dort hat das Haus ein Verzeichnis, aus dem seine Leute kommen. Im Modus Dienstleistung wären es Verzeichnisse fremder Kunden, und die bindet Laufzettel ausdrücklich nicht an — dort kommen Personen von Hand oder per CSV.
  • Laufzettel schreibt nie ins Verzeichnis. Ein Dienstkonto mit Leserechten genügt. Gespeichert werden nur die zugeordneten Felder — keine Passwörter, keine Gruppenmitgliedschaften.

Wer im Verzeichnis verschwindet oder dort deaktiviert wird, wird hier inaktiv. Gelöscht wird nie, sonst verlöre die Historie ihre Namen.

Zwei Arten von Quelle

Laufzettel liest die Personen aus einem Verzeichnis. Dafür gibt es zwei Wege, und du wählst ihn beim Anlegen der Quelle:

Art Für wen
LDAP ein lokales Active Directory (oder ein anderes LDAP-Verzeichnis)
Microsoft Graph Entra ID, also Microsoft 365 — für Häuser ohne lokales AD

Beide verhalten sich danach gleich: anlegen, aktualisieren, deaktivieren, nie löschen. Was sie unterscheidet, sind die Zugangsdaten und zwei Platzhalter:

  • {{ou}} bleibt bei Graph leer. Entra ID hat keine OU. Steht an der Abteilung eine Ziel-OU gepflegt, nimmt Laufzettel die; sonst bleibt der Platzhalter stehen.
  • {{sam}} ist bei Graph leer, wenn der Mandant kein lokales AD synchronisiert — dort gibt es keinen Anmeldenamen in diesem Sinn.

Die Art lässt sich nachträglich nicht ändern. An ihr hängt, was die dauerhafte Kennung einer Person bedeutet; nach einem Wechsel würde niemand mehr wiedererkannt, und der nächste Abgleich legte alle neu an. Wer wechseln muss, legt eine zweite Quelle an und lässt die erste stehen.

Was in Entra ID einzurichten ist — App-Registrierung, Berechtigung, Einwilligung — steht in docs/betrieb/entra-id.md.

Eine Quelle anlegen

Die Seite Verzeichnis mit Quelle, Status und Formular

Das Formular Quelle anlegen steht unten auf der Seite. Die Felder:

Feld Was hinein gehört
Name wie du die Quelle nennst, etwa „Firmen-AD“
Adresse ldaps://dc01.firma.local:636 — nur Schema, Rechner und Port
Anmelde-DN das Dienstkonto, etwa CN=laufzettel,OU=Dienstkonten,DC=firma,DC=local
Passwort wird verschlüsselt gespeichert und nie wieder angezeigt
Basis-DN wo gesucht wird, etwa OU=Benutzer,DC=firma,DC=local
Filter (optional) leer lassen nimmt den Standard: aktive Personenkonten
Abgleich alle … Minuten zwischen 5 und 10080 (fünf Minuten bis eine Woche)
Nach Zeitplan abgleichen das Häkchen schaltet den Zeitplan ein

Für die Adresse gibt es drei Formen:

  • ldaps://host:636 — verschlüsselt ab dem ersten Byte. Die richtige Wahl.
  • ldap+starttls://host:389 — unverschlüsselt verbunden und dann hochgestuft.
  • ldap://host:389 — im Klartext. Sobald du das eintippst, warnt das Formular: dann geht auch das Bind-Passwort im Klartext über das Netz. Für ein Dienstkonto im Active Directory ist das keine gute Idee.

In die Adresse gehören kein Pfad und keine Zugangsdaten. Der Basis-DN hat sein eigenes Feld, Bind-DN und Passwort ebenso; Laufzettel weist eine Adresse mit / oder @ dahinter ausdrücklich ab.

Der Standardfilter schließt deaktivierte Konten aus. Das ist der Sinn: wer aus dem Ergebnis verschwindet, wird hier deaktiviert. Ein eigener Filter engt weiter ein, etwa auf eine einzelne OU.

Dann Quelle anlegen.

Attributzuordnung

Hinter Attributzuordnung anpassen steht, welches Verzeichnis-Attribut auf welches Feld geht. Die Vorgaben sind die Namen eines Active Directory:

Feld Vorgabe
Vorname givenName
Nachname sn
Anzeigename displayName
E-Mail mail
UPN userPrincipalName
Anmeldename (sam) sAMAccountName
Abteilung department
Titel title
Vorgesetzter manager
Kennung (dauerhaft) objectGUID

Ein OpenLDAP heißt an einigen Stellen anders — dort ist die dauerhafte Kennung etwa entryUUID. Leer gelassene Felder bekommen die Vorgabe zurück.

Die Kennung ist das eine Feld, das später nicht mehr geändert werden sollte. An ihr erkennt der Abgleich eine Person wieder. Ein anderer Wert legt beim nächsten Lauf alle Personen neu an.

Eigenes CA-Zertifikat

Nur nötig, wenn der Domänencontroller ein Zertifikat aus einer eigenen CA trägt. Hinter Eigenes CA-Zertifikat hinterlegen fügst du den PEM-Text ein, beginnend mit -----BEGIN CERTIFICATE-----. Ohne Eintrag gelten die Wurzelzertifikate des Systems.

Ist eines hinterlegt, sagt die Seite das. Das Feld bleibt beim Bearbeiten trotzdem leer: Text eintragen ersetzt es, leer lassen behält es, und das Häkchen Hinterlegtes Zertifikat entfernen nimmt es weg. Beides zugleich ergibt keinen Sinn und wird abgewiesen.

Dasselbe gilt für das Passwort: leer lassen behält das gespeicherte. Sonst nähme jede Namensänderung der Quelle ihre Anmeldung.

Verbindung testen

Das Ergebnis eines Verbindungstests: „Die Verbindung steht. 4 Einträge gelesen, 1 übersprungen“ und darunter die ersten drei Einträge mit UPN, Mail, DN, sam und Abteilung

Verbindung testen liest die ersten Einträge und zeigt sie so, wie sie ankämen — gespeichert wird nichts. Mach das immer vor dem ersten Abgleich. Klappt es nicht, steht der Grund in Rot darunter; die häufigsten stehen in Kapitel 08.

Der Wert steckt nicht im „geht“, sondern in der Liste darunter: erst an den zugeordneten Feldern siehst du, ob die Zuordnung stimmt. Ein grünes „Verbindung erfolgreich“ sähe genauso aus, wenn sam und upn vertauscht wären — und der Fehler fiele erst auf, wenn ein PowerShell-Befehl den falschen Anmeldenamen trägt.

Prüf also Zeile für Zeile: Steht unter UPN wirklich der UPN? Unter sam der Anmeldename? Ist die Abteilung genau der Name, unter dem du die Abteilung gepflegt hast?

Ein Vorgesetzter erscheint im Test nur, wenn er zufällig unter diesen Einträgen ist. Beim vollständigen Abgleich wird er aufgelöst.

Zeitplan und „Jetzt abgleichen“

Ist Nach Zeitplan abgleichen gesetzt, läuft der Abgleich von selbst im gewählten Intervall; an der Quelle steht dann „alle 60 min“, sonst „kein Zeitplan“.

Jetzt abgleichen startet ihn sofort — nach einer Änderung am Filter will niemand bis zur nächsten vollen Stunde warten. Es ist derselbe Vorgang, den auch der Zeitplan ruft, es gibt also keinen zweiten Weg mit eigenen Regeln.

Läuft für diese Quelle gerade schon ein Abgleich, sagt Laufzettel das und tut nichts: „Für … läuft gerade schon ein Abgleich. Bitte das Ergebnis abwarten.“

Was der Abgleich tut

  1. Er liest das Verzeichnis in Seiten von je tausend Einträgen.
  2. Jeder Eintrag wird über die Kennung wiedererkannt und aktualisiert, oder neu angelegt.
  3. Eine von Hand angelegte Person wird über upn oder sam gefunden und übernommen, nicht verdoppelt. Genau so ist das Onboarding gedacht: die Person entsteht hier, das AD-Konto danach.
  4. Erst nach einem vollständigen Durchlauf wird deaktiviert, wer nicht wiedergesehen wurde. Ein Netzwerkfehler nach der halben Liste soll nicht die andere Hälfte der Firma abschalten.

Drei Sicherungen, die alle denselben Fehler verhindern — dass eine kaputte Eingabe wie „alle sind gegangen“ aussieht:

  • Ließ sich kein einziger Eintrag zuordnen, gilt der Abgleich als gescheitert und es wird niemand deaktiviert. Die Meldung sagt: „Niemand wurde deaktiviert. Prüf die Attributzuordnung, besonders das Kennungsattribut.“
  • Übersprungene Einträge sind nicht verschwunden und werden aus der Abschaltung herausgenommen.
  • Eine Person, die schon eine andere Quelle führt, wird nie übernommen.

Der Abgleich läuft nicht in einer Transaktion. Bricht er in der Mitte ab, bleiben die bis dahin geschriebenen Personen stehen — ein zweiter Lauf holt den Rest.

Das Abgleich-Log

Das aufgeklappte Abgleich-Log mit Zeitpunkt, Bilanz und Fehlermeldung eines Laufs

An der Quelle steht der letzte Stand: „Zuletzt abgeglichen am …“ oder „Letzter Abgleich gescheitert“ mit der Meldung dazu.

Hinter Abgleich-Log stehen die letzten Läufe mit Zeitpunkt, wer sie ausgelöst hat (steht dort Zeitplan, war es niemand von Hand — das ist der Regelfall) und der Bilanz:

Zahl Bedeutung
gelesen Einträge, die aus dem Verzeichnis kamen
angelegt neue Personen
übernommen von Hand angelegte Personen, die jetzt am Verzeichnis hängen
aktualisiert vorhandene Personen mit geänderten Feldern
deaktiviert nicht mehr wiedergesehene Personen
übersprungen Einträge, die sich nicht zuordnen ließen

Nullen werden gezeigt. „0 angelegt, 0 aktualisiert“ ist die Auskunft, dass der Abgleich lief und sich im Verzeichnis nichts geändert hat. Fehlte die Zeile, sähe ein erfolgreicher Lauf ohne Änderung aus wie ein Lauf, der nie stattfand.

Übersprungene Einträge sind kein Fehler der Quelle, sondern einzelne krumme Konten — sie stehen deshalb als Hinweis und nicht als Fehler da. Steigt die Zahl, prüf die Attributzuordnung.

Ohne Verzeichnis

Eine Quelle ist keine Voraussetzung. Personen lassen sich von Hand anlegen oder aus einer CSV-Datei einlesen — ein Verzeichnis nimmt nur die Arbeit ab. Siehe Kapitel 05.