Grundlage: ARCHITEKTUR-identity-zitadel.md (der Schnitt gegen die Produkte),
ARCHITEKTUR-devops.md (der Identity-Spoke).
Was dieses Dokument zusätzlich leistet: Es entwirft das Sicherheitsmodell aus dem Bedrohungsmodell heraus und leitet daraus die Tickets ab — nicht umgekehrt.
Die Angriffskette ist kurz:
Konto kompromittiert (release-manager)
→ Artefakt hochladen
→ Signing Service signiert (er signiert, was autorisierte Aufrufer verlangen)
→ Channel publizieren
→ jedes Gerät der Flotte lädt und installiert
→ Signatur ist gültig, weil WIR sie erzeugt haben
Der Bootloader schützt hier nicht. Er prüft Ed25519 gegen den eFuse-Anker, und die Signatur ist echt. Anti-Rollback greift nicht, weil die SVN höher ist. Das Gerät tut genau das, wofür es gebaut wurde.
Konsequenz für den Entwurf: Es genügt nicht, Kontoübernahme schwer zu machen. Ein einzelnes übernommenes Konto darf nicht ausreichen, um Firmware auszuliefern. Das ist der Unterschied zwischen einem gut konfigurierten IdP und einem, der dieser Verantwortung gerecht wird.
| # | Klasse | Konkret | Gegenmaßnahme |
|---|---|---|---|
| A1 | Credential | Spraying, Stuffing, Wiederverwendung | Kein Passwort für privilegierte Rollen |
| A2 | Phishing | AiTM-Proxy (Evilginx), relayed TOTP/Push | WebAuthn — Origin-gebunden, nicht relaybar |
| A3 | Wiederherstellung | „Passwort vergessen" → E-Mail → Übernahme | Keine Selbstbedienung für privilegierte Rollen |
| A4 | Sitzung | Token-Diebstahl, Replay, XSS | Kurze TTL, Step-up, Token-Bindung |
| A5 | Registrierung | Selbstregistrierung, Enumeration | Einladung mit Ablauf, Genehmigung durch Owner |
| A6 | Föderation | GitHub-Übernahme, Account-Linking-Angriff | Upstream reicht nicht für privilegierte Rollen |
| A7 | Admin-Ebene | IAM_OWNER kann alles in allen Orgs |
Break-Glass-Konto, nie im Alltag |
| A8 | Insider | Toob-Mitarbeiter sehen Kundendaten | Zeitbegrenzte Impersonation, Kunde wird benachrichtigt |
| A9 | Infrastruktur | Masterkey, DB, Backups | Vault, Verschlüsselung, getrennte Sicherung |
| A10 | Lieferkette | Ein Konto → ganze Flotte | Vier Augen + Verzögerung |
Die letzte Zeile ist die wichtigste. A1 bis A9 machen Übernahme schwer; A10 macht sie unzureichend.
Ein Hardware-Schlüssel als Voraussetzung für den ersten Login klingt sicher und ist es nicht: Wer die Anmeldung zu schwer macht, erzeugt geteilte Konten. Ein Konto, das sich drei Personen teilen, ist schlechter als drei Konten mit Passwort.
Deshalb ein Stufenmodell — die Stufe bestimmt, was man darf und was man sieht:
| Stufe | Faktoren | Darf | Sieht |
|---|---|---|---|
| L1 | Passwort und TOTP, E-Mail verifiziert | nichts verändern | nur Aggregate: „847 Geräte, 94 % aktuell" |
| L2 | ein Passkey | Releases vorbereiten, Reports, Mitglieder ansehen | vollständige Lesesicht |
| L3 | zwei Passkeys | operator, release-manager, admin, owner |
alles der Rolle entsprechend |
Der reduzierte Sichtbereich auf L1 ist der eigentliche Kniff. Statt den Zugang zu
verweigern, bekommt L1 weniger zu sehen. Das nimmt den Anreiz zum Kontoteilen und ist trotzdem
sicher — denn ein viewer in einem Flottenprodukt ist nicht harmlos. Er sieht Geräte-IDs,
ausgerollte Firmware-Versionen, SBOM-Digests (also welche bekannten Schwachstellen im Feld
leben) und Verschleißdaten (also welche Geräte nahe am Lebensende sind). Für einen Angreifer,
der einen Lieferkettenangriff vorbereitet, ist genau das die Aufklärung, die er braucht.
Ein L1-Konto liefert diese Karte nicht.
Von L1 auf L2 kommt man in zwanzig Sekunden: Passkey registrieren. Kein Ticket, keine Freigabe. Von L2 auf L3 ebenso — zweiten Authentikator registrieren.
Die Rolle bekommt man dadurch nicht. operator und höher vergibt ein Org-Owner mit
frischem Step-up (IDP-033). L3 ist die Voraussetzung für die Rolle, nicht ihre Ursache.
Hier liegt die Falle im naheliegenden Entwurf „ohne Passkey anmelden, und beim Klick auf Publish fragt das System nach einem".
Das Registrieren eines Authentikators ist selbst eine privilegierte Operation — es ist genau der Schritt, mit dem sich ein Angreifer nach einer Übernahme Persistenz verschafft. Wer erlaubt, aus einer schwachen Sitzung heraus einen Passkey anzulegen, hat die Stärke des Passkeys an die Stärke der schwachen Sitzung gekoppelt.
Der Ablauf ist deshalb umgekehrt:
Nicht: Publish klicken → „bitte Passkey einrichten" → Passkey aus L1-Sitzung anlegen
Sondern: Passkey vorher anlegen → L3 erreicht → Owner vergibt Rolle → Publish möglich
Das Anlegen des ersten Passkeys aus einer L1-Sitzung ist zulässig — mehr Schaden als L1
ohnehin anrichten kann, entsteht dadurch nicht. Jeder weitere Authentikator erfordert
Bestätigung mit einem bereits registrierten Passkey, und alle Org-Owner werden benachrichtigt
(IDP-071).
Wer einmal L3 hatte, fällt nicht auf L1 zurück. Sonst lautet der Angriff: Operator verliert seine Schlüssel, das Konto fällt auf Passwort zurück, das Passwort wird angegriffen.
Verliert ein L3-Konto seine Authentikatoren, greift der Wiederherstellungsprozess aus
IDP-021 — nicht der Passwort-Pfad. Ein Konto, das jemals eine Geräterolle trug, kennt den
Passwort-Login nicht mehr.
TOTP und Push sind gegen einen AiTM-Proxy wirkungslos: Der Proxy leitet den Code in Echtzeit
weiter, der Nutzer merkt nichts. WebAuthn bindet die Assertion an den Origin — ein Proxy auf
id.the-toob.corn bekommt keine gültige Signatur.
Für L3 gilt WebAuthn ohne Rückfallebene. Eine Rückfallebene macht die Maßnahme wertlos, weil der Angreifer sie wählt. Auf L1 ist TOTP zulässig, weil dort weder etwas veränderbar noch etwas Verwertbares sichtbar ist.
Der am häufigsten ausgenutzte Pfad in freier Wildbahn. Wer MFA erzwingt und dann einen Reset per E-Mail erlaubt, hat MFA nicht erzwungen — er hat sie an das E-Mail-Konto delegiert.
- Zwei Authentikatoren sind für L3 ohnehin Pflicht. Verlust eines Schlüssels ist damit kein Notfall, sondern ein Dienstagnachmittag.
- Verlust beider: Verifikation außerhalb des Kanals, technisch erzwungene Wartezeit von 24 Stunden, Benachrichtigung an alle Org-Owner. Die Wartezeit ist der eigentliche Schutz — sie gibt dem echten Inhaber Zeit zu widersprechen.
- Wiederherstellung senkt das Niveau nicht (siehe E4).
Eine Sitzung ist nicht dasselbe wie eine Freigabe. Selbst ein gestohlenes L3-Session-Token soll nicht ausreichen, um Firmware zu publizieren.
Vor Publish, Channel-Wechsel und Rollout-Start: frische Re-Authentifizierung mit dem Passkey, maximal fünf Minuten alt. Der Angreifer mit gestohlenem Token kann lesen — ausliefern kann er nicht.
Das ist der Mechanismus, den „erst wenn man etwas Kritisches berührt" eigentlich meint. Er wirkt auf die Aktion, nicht auf die Faktor-Ausstattung — die muss vorher stehen (E3).
Für Produktions-Channels mit Geräten im Feld:
- Vier-Augen-Prinzip: zwei verschiedene
release-managermüssen freigeben, beide mit frischem Step-up. - Soak-Zeit: zwischen Freigabe und Beginn der Auslieferung liegen mindestens 30 Minuten, in denen jeder Org-Owner abbrechen kann. Ein erfolgreicher Angriff hat damit ein Erkennungsfenster, bevor das erste Gerät installiert.
Beides ist pro Mandant konfigurierbar, aber Default an für jeden Mandanten mit Geräten in Produktion.
Ehrlichkeit gehört zum Entwurf: Kein IdP ist unangreifbar. Was dieser Aufbau erreicht:
- Kontoübernahme erfordert physischen Besitz eines registrierten Authentikators.
- Ein übernommenes Konto reicht nicht für Firmware-Auslieferung (E5).
- Jeder erfolgreiche Angriff hat ein Erkennungsfenster vor der Wirkung.
- Der Radius eines kompromittierten Toob-Mitarbeiters ist begrenzt und sichtbar.
Was bleibt: ein Angreifer mit physischem Zugriff auf zwei Authentikatoren einer Person, oder
zwei kollaborierende Insider, oder eine Schwachstelle in Zitadel selbst. Gegen die ersten
beiden hilft nur Organisation, gegen die dritte nur zeitnahes Patchen (IDP-090).
Legende
Prio: P0 muss vor dem ersten echten Nutzer · P1 vor Produktivgang · P2 vor dem ersten
Kunden mit Flotte · P3 danach
Typ: security config feature infra process detect
Reihenfolgeprinzip: Alles, was sich nicht ohne Zeitfenster nachrüsten lässt, kommt zuerst. Eine MFA-Policy nachträglich auf bestehende Konten anzuwenden, hinterlässt genau die Lücke, die ein Angreifer sucht.
| ID | Titel | Prio | Typ |
|---|---|---|---|
| EPIC A — Fundament, vor dem ersten Nutzer | |||
| IDP-001 | Masterkey aus Vault, nie aus Datei | P0 | security |
| IDP-002 | Datenbank: eigene Instanz, verschlüsselte Backups, getrennter Bucket | P0 | infra |
| IDP-003 | Netz- und Edge-Härtung des Identity-Spokes | P0 | infra |
| IDP-004 | Selbstregistrierung aus, Enumeration verhindern | P0 | config |
| IDP-005 | Instanz-Policies vor der ersten Org festschreiben | P0 | config |
| EPIC B — Authentifizierung | |||
| IDP-010 | Stufenmodell L1/L2/L3 umsetzen | P0 | config |
| IDP-011 | Sichtbereich an die Stufe binden | P0 | feature |
| IDP-011b | WebAuthn ohne Rückfallebene für L3 | P0 | config |
| IDP-011c | Registrierung weiterer Faktoren absichern | P0 | security |
| IDP-012 | Kein Abstieg für Konten, die L3 hatten | P0 | feature |
| IDP-013 | Rollenabhängige Authentifizierungsanforderung durchsetzen | P1 | feature |
| IDP-014 | Sitzungsdauer, Token-TTL, Refresh-Rotation | P1 | config |
| IDP-015 | Token-Bindung (DPoP oder mTLS) prüfen und aktivieren | P2 | security |
| EPIC C — Wiederherstellung und Notfallzugang | |||
| IDP-020 | Selbstbedienungs-Reset für privilegierte Rollen abschalten | P0 | config |
| IDP-021 | Wiederherstellungsprozess mit Wartezeit und Benachrichtigung | P1 | process |
| IDP-022 | IAM_OWNER als Break-Glass-Konto |
P0 | security |
| IDP-023 | Break-Glass-Übung und Protokoll | P2 | process |
| EPIC D — Organisationen, Einladungen, Rollen | |||
| IDP-030 | Projekt- und Rollenmodell anlegen | P1 | config |
| IDP-031 | Einladungsfluss: einmalig, ablaufend, E-Mail-gebunden | P1 | feature |
| IDP-032 | Org-Namensregeln über Action durchsetzen | P1 | feature |
| IDP-033 | Rollenvergabe erfordert Owner-Genehmigung | P1 | feature |
| IDP-034 | Org-Spiegel in die Produkte pushen | P1 | feature |
| EPIC E — Step-up und Freigabe | |||
| IDP-040 | Step-up-Authentifizierung vor Geräteoperationen | P1 | feature |
| IDP-041 | Vier-Augen-Freigabe für Produktions-Channels | P2 | feature |
| IDP-042 | Soak-Zeit zwischen Freigabe und Auslieferung | P2 | feature |
| IDP-043 | Signing Service verlangt Freigabenachweis | P2 | security |
| EPIC F — Föderation | |||
| IDP-050 | GitHub als Upstream-IdP, mit Rollenschranke | P1 | config |
| IDP-051 | Bestandsnutzer vorverknüpfen | P1 | feature |
| IDP-052 | Kunden-IdP über OIDC/SAML | P3 | feature |
| IDP-053 | Workload-Identity-Federation für CI | P3 | feature |
| EPIC G — Insider und Support | |||
| IDP-060 | Impersonation zeitbegrenzt, begründet, sichtbar | P2 | security |
| IDP-061 | Toob-Mitarbeiter ohne stehende Kundenrechte | P2 | process |
| EPIC H — Erkennung | |||
| IDP-070 | Audit-Log nach Loki, unveränderlich, projektgetrennt | P1 | detect |
| IDP-071 | Alarme auf sicherheitsrelevante Ereignisse | P1 | detect |
| IDP-072 | Anomalie-Alarme: neue Geografie, neuer Authentikator | P2 | detect |
| IDP-073 | Rate-Limits ohne DoS-Nebenwirkung | P1 | security |
| EPIC I — Nachweis | |||
| IDP-080 | Angriffssimulation: AiTM-Phishing | P2 | process |
| IDP-081 | Externe Sicherheitsprüfung vor dem ersten Kunden | P2 | process |
| IDP-090 | Patch-Prozess mit Frist | P1 | process |
Prio: P0 · Typ: security
Problem Zitadel verschlüsselt Secrets in der Datenbank mit einem Masterkey. Wer Masterkey und Datenbank hat, hat die Identitätsinfrastruktur — inklusive aller Client-Secrets und IdP-Konfigurationen.
Der Standardweg legt ihn in eine Datei oder eine Umgebungsvariable. Beides landet in Backups, Prozesslisten und Log-Ausgaben.
Lösung
Masterkey aus secret/projects/identity/masterkey, per Vault-Agent in ein Template gerendert,
Dateimodus 0400, Eigentümer zitadel. Die Lease-Regel der Plattform gilt: mindestens 30
Tage, damit ein Vault-Ausfall den IdP nicht stoppt (OPS-060).
Der Schlüssel wird bei der Einrichtung genau einmal erzeugt und offline gesichert — er ist nicht rotierbar, ohne die Datenbank neu zu verschlüsseln.
Akzeptanzkriterien
- Der Masterkey steht in keiner Umgebungsvariablen und in keinem Ansible-Vault-freien Pfad.
-
systemctl show zitadelund/proc/<pid>/environenthalten ihn nicht. - Offline-Sicherung existiert und ihr Ort ist im Runbook vermerkt.
Prio: P0 · Typ: infra
Lösung
Eigene Ubicloud-Instanz toob-idp-db, kein geteiltes Schema. sslmode=verify-full wie im
Bestand. Firewall-Pinning über den zentralen Pruner.
Backups sind so sensibel wie der IdP selbst. Eigener Bucket
toob-idp-backups-<env> — nicht der geteilte Vault-Bucket, dessen Löschpfad in BEF-003
auffiel. Verschlüsselung at rest, WORM, eigene Zugriffsschlüssel.
Akzeptanzkriterien
- Kein anderer Dienst hat Zugriff auf
toob-idp-db. - Backup-Bucket ist umgebungspräfigiert und von keinem Teardown-Pfad erfasst.
- Ein Restore ist getestet (analog
OPS-020).
Prio: P0 · Typ: infra
Lösung
- Cloudflare vor
id.the-toob.com, Origin-Cert, Full Strict. Ursprungs-IPs nur von CF-Ranges erreichbar (Hetzner-Firewall). - Admin-Konsole nicht öffentlich: Zitadels Console-Pfad nur aus dem WireGuard-Netz erreichbar, per Caddy-Matcher auf Quell-IP. Der Login-Endpunkt bleibt öffentlich, die Verwaltungsoberfläche nicht.
- Security-Header wie im Registry-Caddyfile, CSP eng.
- Keine Introspection-Endpunkte öffentlich, wenn sie nicht gebraucht werden.
- WAF-Regel gegen bekannte Phishing-Kit-Signaturen und ungewöhnliche
redirect_uri-Muster.
Akzeptanzkriterien
- Portscan von außen: nur 443.
- Console-Pfad aus dem Internet:
403. - Ein Aufruf mit fremdem
Host-Header wird abgewiesen.
Prio: P0 · Typ: config
Problem Offene Selbstregistrierung erzeugt Konten, die später über Einladungsfehler oder Social Engineering in Organisationen wandern. Und unterschiedliche Fehlermeldungen für „Nutzer existiert nicht" gegenüber „falsches Passwort" verraten, wer Kunde ist — für einen gezielten Angriff auf einen bestimmten Hersteller ist das der erste Schritt.
Lösung
- Registrierung ausschließlich per Einladung (
IDP-031). - Login-Antworten und -Zeiten für existierende und nicht existierende Konten ununterscheidbar.
- Kein Hinweis darauf, welche Faktoren registriert sind, bevor die Identität feststeht.
Akzeptanzkriterien
-
POSTauf den Registrierungspfad ⇒ abgelehnt. - Antwortzeit für existierendes und nicht existierendes Konto unterscheidet sich nicht messbar (Messung über 1000 Versuche).
Prio: P0 · Typ: config
Problem Zitadel-Organisationen erben Policies von der Instanz, können sie aber überschreiben. Werden die Instanz-Defaults erst nach der ersten Org gesetzt, gilt für diese weiter der alte Stand — und niemand merkt es.
Lösung Alle Instanz-Policies festschreiben, bevor die erste Organisation existiert: Login-Policy, Passwort-Policy (ungenutzt, aber restriktiv als Sicherheitsnetz), MFA-Policy, Lockout-Policy, Domain-Policy. Als Terraform oder als versionierte API-Aufrufe, nicht per Klick.
Zusätzlich: Org-eigene Policy-Überschreibung deaktivieren, wo möglich. Ein Kunde soll die MFA-Anforderung nicht senken können.
Akzeptanzkriterien
- Die Policy-Konfiguration liegt als Code vor und ist reproduzierbar anwendbar.
- Eine neu angelegte Org erbt alle Einschränkungen (Negativtest: Versuch, MFA in einer Org abzuschalten, schlägt fehl).
Zu verifizieren: Welche Policies Zitadel org-seitig überschreibbar lässt und ob sich das instanzweit sperren lässt. Falls nicht, muss eine Action die Änderung zurücksetzen und alarmieren.
Prio: P0 · Typ: config · Ref: E1, E2
Lösung Drei Vertrauensstufen, die sich aus den registrierten Faktoren ergeben — nicht gesetzt werden:
| Stufe | Bedingung |
|---|---|
| L1 | E-Mail verifiziert, Passwort + TOTP |
| L2 | mindestens ein Passkey |
| L3 | mindestens zwei Passkeys |
Der Passkey-Weg ist der vorgegebene: Die Anmeldemaske bietet ihn zuerst an, der Passwort-Weg steht darunter als „andere Möglichkeit". Wer aus einem Unternehmensnetz kommt, das WebAuthn blockiert, oder ein altes Gerät nutzt, wird nicht ausgesperrt — er landet auf L1.
Die Stufe wird bei jeder Faktoränderung neu berechnet und als Claim ins Token geschrieben.
Akzeptanzkriterien
- Ein Nutzer, der einen Passkey registriert, ist unmittelbar danach L2 — ohne Ticket.
- Entfernt er ihn wieder, fällt er auf L1 zurück (Ausnahme: E4, siehe
IDP-012). - Die Stufe steht als Claim im Token und ist im Produkt auswertbar.
Prio: P0 · Typ: feature · Ref: E1
Problem
Ein viewer im Flottenprodukt ist nicht harmlos. Er sieht Geräte-IDs, ausgerollte
Firmware-Versionen, SBOM-Digests — also welche bekannten Schwachstellen im Feld leben —
und staging_slot_erase_count, also welche Geräte nahe am Lebensende sind.
Das ist exakt die Aufklärung, die ein Lieferkettenangriff braucht: Welche Geräte sind angreifbar, welche werden bald ersetzt, wann rollt der Hersteller normalerweise aus.
Ein Konto mit Passwort und TOTP darf diese Karte nicht liefern.
Lösung
| Datum | L1 | L2+ |
|---|---|---|
| Gerätezahl, Erfolgsquote, Versionsverteilung | ✓ aggregiert | ✓ |
| Geräte-IDs, Einzelstatus | — | ✓ |
| SBOM-Digests, CVE-Zuordnung | — | ✓ |
| Verschleißdaten je Gerät | — | ✓ |
| Audit-Log | — | ✓ |
Artefakt-Digests, blob_path |
— | ✓ |
Durchgesetzt im Produkt, nicht in der UI — ein L1-Token bekommt die Felder auch über die API nicht.
Akzeptanzkriterien
-
GET /v1/management/devicesliefert mit L1-Token nur Aggregate. - Kein Endpunkt gibt mit L1-Token einen SBOM-Digest oder eine Geräte-ID heraus.
- Die Prüfung sitzt in der Autorisierungsschicht, nicht im Handler.
Prio: P0 · Typ: config · Ref: E5
Problem TOTP und Push sind gegen AiTM-Proxys wirkungslos — der Proxy leitet den Code in Echtzeit weiter. WebAuthn bindet die Assertion an den Origin und ist deshalb nicht relaybar.
Eine Rückfallebene macht die Maßnahme wertlos, weil der Angreifer sie wählt.
Lösung
Rollen mit Geräteauswirkung (operator, release-manager, admin, owner) setzen L3
voraus, und L3 kennt ausschließlich WebAuthn. Es gibt keinen Pfad, auf dem ein solches Konto
sich mit TOTP anmeldet.
Bevorzugt Authentikatoren mit User-Verification (PIN oder Biometrie), damit ein gestohlener Schlüssel allein nicht genügt.
Akzeptanzkriterien
- Ein Konto mit
operatorkann sich nicht per TOTP anmelden — auch nicht, wenn TOTP früher registriert wurde. - Der Versuch, für ein L3-Konto TOTP als Faktor zu ergänzen, wird abgelehnt.
Prio: P0 · Typ: security · Ref: E3
Problem Das Anlegen eines Authentikators ist der Schritt, mit dem sich ein Angreifer nach einer Übernahme Persistenz verschafft. Erlaubt man es aus einer schwachen Sitzung, ist der neue Passkey nur so stark wie die Sitzung, aus der er entstand.
Lösung
| Vorgang | Voraussetzung |
|---|---|
| erster Passkey (L1 → L2) | L1-Sitzung genügt — mehr Schaden als L1 kann, entsteht nicht |
| jeder weitere Authentikator | Bestätigung mit einem bereits registrierten Passkey |
| Entfernen eines Authentikators | Bestätigung mit einem verbleibenden Passkey |
Jede Änderung an der Faktorliste benachrichtigt den Nutzer und alle Org-Owner
(IDP-071). Das ist der wichtigste Einzelalarm des ganzen Systems: Ein neuer Authentikator,
den der Inhaber nicht selbst angelegt hat, ist eine laufende Übernahme.
Akzeptanzkriterien
- Ein zweiter Passkey lässt sich aus einer Passwort-Sitzung nicht anlegen.
- Jede Faktoränderung erzeugt binnen 60 Sekunden eine Benachrichtigung.
Prio: P0 · Typ: feature · Ref: E4
Problem Ohne diese Regel lautet der Angriff: Operator verliert seine Schlüssel, das Konto fällt auf den Passwort-Pfad zurück, und das Passwort wird angegriffen. Die gesamte L3-Absicherung ist dann über einen Umweg umgangen.
Lösung Ein Konto, das jemals L3 erreicht hat, trägt eine dauerhafte Markierung:
- Der Passwort-Login ist für dieses Konto deaktiviert und nicht reaktivierbar.
- Fällt die Zahl der Authentikatoren unter zwei, wird die Rolle suspendiert (nicht entzogen), Nutzer und Org-Owner werden benachrichtigt, und das Konto verharrt auf L2.
- Bei null Authentikatoren greift ausschließlich
IDP-021— kein Selbstbedienungspfad.
Die Zwei-Schlüssel-Anforderung aus dem Stufenmodell hat genau hier ihren Zweck: Sie sorgt dafür, dass der Verlust eines Schlüssels ein Dienstagnachmittag ist und kein Notfall, in dem jemand unter Druck eine Ausnahme genehmigt.
Akzeptanzkriterien
- Rollenvergabe an ein L2-Konto ist nicht möglich; die Meldung nennt den fehlenden zweiten Faktor.
- Entfernen des zweiten Authentikators suspendiert die Rolle und benachrichtigt alle Owner.
- Ein Konto mit der L3-Markierung kann sich unter keinen Umständen per Passwort anmelden.
Prio: P1 · Typ: feature
Problem
Die Anforderung aus IDP-011 muss zum Zeitpunkt der Aktion gelten, nicht nur beim Login.
Ein Nutzer, der als viewer mit TOTP eingeloggt ist und dann operator erhält, hat eine
Sitzung mit zu schwachem Niveau.
Lösung
Das Produkt prüft die amr- und acr-Claims des Tokens gegen die für die Aktion nötige
Stufe. Reicht sie nicht, folgt eine Re-Authentifizierung (IDP-040) statt einer Ablehnung.
Akzeptanzkriterien
- Eine mit TOTP begonnene Sitzung kann keine Geräteoperation auslösen.
- Der Nutzer bekommt eine Aufforderung zur Re-Authentifizierung, keine Fehlermeldung.
Zu verifizieren: Wie Zitadel
amr/acrbefüllt und ob sich eigene ACR-Werte definieren lassen. Falls nicht, trägt eine Action einen eigenen Claim ein.
Prio: P1 · Typ: config
Lösung
| Wert | Einstellung | Begründung |
|---|---|---|
| Access-Token | 15 min | Offline-Verifikation, Diebstahlfenster klein |
| Refresh-Token | 8 h, rotierend | Wiederverwendung eines rotierten Tokens = Diebstahl ⇒ Familie invalidieren |
| Sitzung (Browser) | 12 h absolut, 30 min inaktiv | Ein vergessener Laptop ist kein Dauerzugang |
| Step-up-Gültigkeit | 5 min | IDP-040 |
Refresh-Token-Rotation mit Reuse-Detection ist der wichtigste Punkt: Wird ein bereits eingelöster Refresh-Token erneut vorgelegt, wurde er gestohlen — die gesamte Token-Familie wird invalidiert und der Nutzer alarmiert.
Akzeptanzkriterien
- Wiederverwendung eines rotierten Refresh-Tokens invalidiert die Familie und erzeugt einen Alarm.
- Cookies:
Secure,HttpOnly,SameSite=Lax,__Host--Präfix.
Prio: P2 · Typ: security
Problem Ein Bearer-Token ist so gut wie sein Besitz. Wer ihn stiehlt — Malware, XSS, Log-Leck — kann ihn überall verwenden.
Lösung DPoP (RFC 9449) bindet das Token an einen clientseitigen Schlüssel; ein gestohlenes Token ist ohne den privaten Schlüssel wertlos. Alternativ mTLS-gebundene Tokens für Maschinenpfade.
Zu verifizieren: DPoP-Unterstützung in Zitadel und in den Produkt-APIs. Falls nicht verfügbar, bleibt
IDP-040(Step-up) die wirksame Kompensation — ein gestohlenes Token erlaubt dann Lesen, aber keine Auslieferung.
Prio: P0 · Typ: config
Problem Der meistgenutzte Übernahmepfad in der Praxis. Wer MFA erzwingt und dann Reset per E-Mail erlaubt, hat die MFA an das E-Mail-Konto delegiert.
Lösung
Für Konten mit privilegierten Rollen: kein Selbstbedienungs-Reset, kein Magic Link, keine
SMS. Für viewer und contributor zulässig, aber ohne Rollenerhöhung nach der
Wiederherstellung.
Akzeptanzkriterien
- „Zugang verloren" für ein
operator-Konto führt zu einem Hinweis auf den Prozess ausIDP-021, nicht zu einem automatischen Fluss.
Prio: P1 · Typ: process
Lösung Vier Schritte, alle zwingend:
- Anfrage außerhalb des Kanals — nicht über das kompromittierbare E-Mail-Konto allein.
- Verifikation durch einen Menschen gegen eine bei Vertragsschluss hinterlegte Kontaktperson des Kunden.
- Wartezeit 24 Stunden, in der alle Org-Owner benachrichtigt werden und widersprechen können. Das ist der eigentliche Schutz: Ein Angreifer, der die Verifikation besteht, hat trotzdem einen Tag, in dem der echte Inhaber es merkt.
- Registrierung neuer Authentikatoren, mindestens zwei, ohne Absenkung des Niveaus.
Bei Widerspruch: sofortiger Abbruch, Sicherheitsvorfall, Sitzungen des betroffenen Kontos invalidiert.
Akzeptanzkriterien
- Der Prozess ist im Runbook, mit Namen der verantwortlichen Rolle.
- Ein Testdurchlauf ist protokolliert.
- Die Wartezeit ist technisch erzwungen, nicht organisatorisch zugesagt.
Prio: P0 · Typ: security
Problem
Der Instanz-Administrator kann in Zitadel alles: jede Org verwalten, Nutzer anlegen, Policies
ändern, Rollen vergeben. Ein übernommenes IAM_OWNER-Konto ist die Kompromittierung
sämtlicher Kunden gleichzeitig.
Lösung
- Genau ein
IAM_OWNER-Konto, nicht im Alltag verwendet. - Zwei Hardware-Schlüssel, physisch getrennt verwahrt.
- Keine E-Mail-Adresse, die auch für anderes benutzt wird.
- Jede Anmeldung erzeugt sofort einen Alarm — nicht „bei Auffälligkeit", sondern immer.
- Alltägliche Toob-Arbeit läuft über org-gebundene Rollen (
IDP-061).
Akzeptanzkriterien
- Es existiert genau ein Konto mit Instanz-Rechten.
- Eine Anmeldung damit erzeugt binnen 60 Sekunden einen Alarm im Betriebskanal.
- Kein Automatisierungspfad verwendet dieses Konto.
Prio: P2 · Typ: process
Lösung
Halbjährlich: Zugriff mit dem IAM_OWNER-Konto herstellen, gemessene Zeit protokollieren,
Alarm verifizieren, Schlüssel zurück in die Verwahrung. Zusammen mit der Übung aus OPS-023.
Ein ungeübter Notfallpfad ist keiner — das gilt hier wie beim WireGuard-Hub.
Prio: P1 · Typ: config
Lösung Zwei Zitadel-Projekte mit ihren Rollen:
| Projekt | Rollen |
|---|---|
registry |
contributor, core |
fleet |
viewer, operator, release-manager, admin, owner |
Die Trennung zwischen release-manager (darf signieren lassen) und operator (darf ausrollen)
ist Lieferkettenschutz: Ein übernommener Operator kann kein bösartiges Artefakt einschleusen,
nur ein vorhandenes falsch ausrollen — und das ist über den Assignment-Verlauf rekonstruierbar.
Als Code, nicht per Konsole.
Zu verifizieren: Welches Zitadel-Primitiv die org-gebundene Rolle trägt — Projektrolle mit Org-Grant, Org-Member-Rolle oder User-Grant. Bestimmt die Claim-Struktur.
Prio: P1 · Typ: feature
Lösung
- Einladung ist einmalig einlösbar, läuft nach 72 Stunden ab, ist an die eingeladene E-Mail gebunden.
- Der Einladende sieht, ob sie eingelöst wurde.
- Eine Einladung vergibt niemals direkt eine Rolle mit Geräteauswirkung — der Beitritt
erfolgt als
viewer, die Erhöhung brauchtIDP-033. - Widerruf jederzeit möglich.
Akzeptanzkriterien
- Ein zweiter Einlöseversuch derselben Einladung schlägt fehl.
- Eine Einladung, die auf eine andere E-Mail eingelöst wird, schlägt fehl.
Prio: P1 · Typ: feature
Problem
Der Org-Name ist zugleich Paket-Scope (@esp-alliance/foo). Lässt Zitadel Namen zu, die
validate.ValidateOrgName ablehnt, entstehen Organisationen, die keinen gültigen Scope ergeben
— und der Fehler fällt erst beim ersten Publish auf.
Lösung Action bei der Org-Erzeugung, die dieselbe Regel durchsetzt. Die Regel steht an einer Stelle und wird von der Action konsumiert, nicht nachgebaut.
Prio: P1 · Typ: feature
Lösung
Die Vergabe von operator, release-manager oder admin erfordert die Bestätigung eines
owner mit frischem Step-up. Alle Org-Owner werden benachrichtigt.
Damit reicht ein übernommener admin nicht, um sich still weitere Rechte zu verschaffen — der
Vorgang ist sichtbar.
Akzeptanzkriterien
- Rollenerhöhung ohne Owner-Bestätigung ist nicht möglich.
- Jede Erhöhung erzeugt eine Benachrichtigung an alle Owner.
Prio: P1 · Typ: feature
Lösung
Push aus Zitadel in toob-registry.organizations/organization_members und
toob-update.tenants/tenant_members. Read-only im Produkt, geschrieben nur vom Sync.
Damit liest PolicyEngine.AuthorizeOrgAction weiter lokal — kein Netzaufruf, kein
Laufzeitpfad zum IdP.
Akzeptanzkriterien
- Eine Mitgliedschaftsänderung ist binnen 60 Sekunden im Produkt sichtbar.
- Sync-Rückstand über 5 Minuten erzeugt einen Alarm.
- Der Produktcode schreibt nachweislich nicht in die Spiegeltabellen (Grant-Test).
Prio: P1 · Typ: feature
Lösung
Vor Artefakt-Publish, Channel-Wechsel, Rollout-Start und Killswitch: frische
Re-Authentifizierung mit phishing-resistentem Faktor, maximal fünf Minuten alt. Umgesetzt über
prompt=login mit max_age und Prüfung von auth_time.
Wirkung: Ein gestohlenes Session-Token erlaubt Lesen, aber keine Auslieferung. Das ist die
Kompensation, falls IDP-015 nicht verfügbar ist.
Akzeptanzkriterien
- Publish mit einem sechs Minuten alten
auth_timewird abgelehnt. - Die Ablehnung führt zur Re-Authentifizierung, nicht zu einem Fehler.
Prio: P2 · Typ: feature
Problem Ohne diese Maßnahme genügt ein kompromittiertes Konto für die gesamte Flotte. Alles davor macht das schwer — das hier macht es unzureichend.
Lösung
Ein Channel-Wechsel in Produktion erfordert die Freigabe von zwei verschiedenen
release-manager, beide mit frischem Step-up. Die zweite Freigabe kann nicht vom Ersteller
kommen.
Pro Mandant abschaltbar, aber Default an, sobald Geräte in Produktion registriert sind.
Akzeptanzkriterien
- Ein Nutzer kann nicht beide Freigaben erteilen.
- Die Abschaltung erfordert eine
owner-Entscheidung und erzeugt einen Audit-Eintrag.
Prio: P2 · Typ: feature
Lösung Zwischen der zweiten Freigabe und dem ersten ausgelieferten Byte liegen mindestens 30 Minuten, in denen jeder Org-Owner abbrechen kann. Alle Owner werden bei Freigabe benachrichtigt.
Warum das wichtig ist: Es verwandelt einen erfolgreichen Angriff von „sofort auf allen Geräten" in „ein halbstündiges Erkennungsfenster". Für einen Angreifer, der auf Unauffälligkeit angewiesen ist, ist das ein erheblicher Unterschied.
Akzeptanzkriterien
- Kein Gerät bekommt eine Zuweisung vor Ablauf der Soak-Zeit.
- Ein Abbruch innerhalb des Fensters verhindert jede Auslieferung.
Prio: P2 · Typ: security
Problem
Solange der Signing Service auf reine Rollenzugehörigkeit hin signiert, umgeht ein direkter
API-Aufruf die Freigabe aus IDP-041.
Lösung Der Signing Service akzeptiert nur Anfragen mit einem Nachweis über zwei Freigaben und frischen Step-up. Ohne diesen Nachweis wird nicht signiert — unabhängig davon, welche Rolle der Aufrufer hat.
Damit ist die Vier-Augen-Regel technisch durchgesetzt und nicht nur in der UI abgebildet.
Akzeptanzkriterien
- Ein direkter Aufruf des Signing Service ohne Freigabenachweis wird abgelehnt.
- Der Nachweis ist an Artefakt-Digest und Channel gebunden, nicht wiederverwendbar.
Prio: P1 · Typ: config
Problem GitHub-Login ist gute UX und ein Risiko: Eine GitHub-Übernahme wäre eine Toob-Übernahme, und GitHubs eigene MFA kann SMS sein.
Zusätzlich das klassische Account-Linking-Problem: Ein Upstream, der E-Mail-Adressen nicht verifiziert, erlaubt Verknüpfung mit einer fremden Identität.
Lösung
- GitHub bleibt Anmeldemethode für
contributorundviewer. - Für Geräterollen genügt GitHub nicht — dort ist zusätzlich ein lokaler Passkey erforderlich, unabhängig vom Anmeldeweg.
- Automatische Verknüpfung nur bei verifizierter E-Mail; sonst manuelle Bestätigung.
Akzeptanzkriterien
- Ein per GitHub angemeldeter Nutzer mit
operatormuss vor einer Geräteoperation den lokalen Faktor vorlegen. - Verknüpfung mit unverifizierter Upstream-E-Mail ist nicht automatisch möglich.
Prio: P1 · Typ: feature
Lösung
Bestehende Registry-Nutzer über die Management-API anlegen und per github_id mit ihrer
GitHub-Identität verknüpfen, damit der erste Login sie wiedererkennt statt ein Duplikat
anzulegen.
Wichtig: Verknüpfung über die numerische github_id, nicht über den Login-Namen — Namen
sind änderbar und wiederverwendbar.
Zu verifizieren: Ob die Management-API das Vorverknüpfen externer Identitäten erlaubt. Falls nicht, braucht der erste Login eine Action, die anhand der
github_idzuordnet.
Prio: P3 · Typ: feature
Industriekunden wollen ihren eigenen IdP. Wichtig dabei: Auch dann bleibt die Anforderung aus
IDP-011 bestehen — entweder der Kunden-IdP liefert nachweislich einen phishing-resistenten
Faktor (amr-Claim), oder es ist zusätzlich ein lokaler Passkey nötig.
Ein Kunde darf sein eigenes Sicherheitsniveau senken — aber nicht unbemerkt, und nicht für Geräteoperationen.
Prio: P3 · Typ: feature
GitHub-/GitLab-OIDC-Token gegen kurzlebiges Toob-Token. Kein langlebiges Kundensecret mehr bei uns.
Wichtig: Der Token-Tausch muss repository, ref und workflow prüfen — sonst kann jedes
Repository derselben Organisation Firmware publizieren. Und Maschinenidentitäten erhalten
nie release-manager für Produktions-Channels; sie können nach dev publizieren, die
Promotion bleibt menschlich.
Prio: P2 · Typ: security
Problem Die erste Frage eines Auditors: Wer bei euch sieht unsere Flottendaten, und wie erfahren wir davon? Ohne dieses Ticket lautet die Antwort „jeder mit DB-Zugriff, und ihr erfahrt es nicht".
Lösung Support-Zugriff läuft ausschließlich über eine explizite Impersonation:
- Begründung verpflichtend, freier Text
- Zeitlich begrenzt, maximal 4 Stunden
- Erscheint im Audit-Log des Kunden, nicht nur im unseren
- Benachrichtigung an alle Org-Owner beim Start
- Niemals mit
release-manager— Support liest, Support liefert nicht aus
Akzeptanzkriterien
- Impersonation ohne Begründung ist nicht möglich.
- Der Kunde sieht den Vorgang in seinem eigenen Audit-Log.
- Impersonierte Sitzungen können keine Geräteoperationen auslösen.
Prio: P2 · Typ: process
Lösung
Kein Toob-Konto hat dauerhaft Rollen in Kundenorganisationen. Zugriff entsteht nur über
IDP-060 und endet automatisch. Das Alltagskonto ist ein normales Konto mit Passkey.
Prio: P1 · Typ: detect
Lösung
Zitadels Ereignisstrom nach Loki, mit project=identity und Mandanten-Label
(X-Scope-OrgID aus BEF-009). Aufbewahrung mindestens so lang wie die CRA-Retention der
Flottendaten.
Das Log ist selbst schützenswert: Es enthält, wer wann welche Flotte verwaltet hat.
Akzeptanzkriterien
- Alle Anmelde-, Rollen- und Policy-Ereignisse landen in Loki.
- Ein Mandant sieht ausschließlich seine eigenen Ereignisse.
Prio: P1 · Typ: detect
| Ereignis | Schwere |
|---|---|
IAM_OWNER-Anmeldung |
kritisch, immer |
| Neuer Authentikator registriert | hoch — an Nutzer und Org-Owner |
| Privilegierte Rolle vergeben | hoch |
| MFA-Policy geändert | kritisch |
| Refresh-Token-Reuse erkannt | kritisch |
| Wiederherstellungsprozess gestartet | hoch |
| Impersonation gestartet | hoch, auch an den Kunden |
| Upstream-IdP-Konfiguration geändert | kritisch |
Der Alarm auf „neuer Authentikator" ist besonders wichtig: Das ist der Schritt, den ein Angreifer nach der Übernahme unternimmt, um sich Persistenz zu verschaffen.
Prio: P2 · Typ: detect
Neue Geografie oder neues ASN bei privilegierten Konten, ungewöhnliche Uhrzeit, fehlgeschlagene WebAuthn-Versuche in Serie (deutet auf AiTM-Versuch hin — der Proxy bekommt keine gültige Assertion und probiert weiter).
Kein automatisches Blockieren, sondern Benachrichtigung plus erzwungenes Step-up bei der nächsten Aktion.
Prio: P1 · Typ: security
Problem Harte Kontosperren nach N Fehlversuchen sind selbst ein Angriff: Ein Angreifer sperrt gezielt die Operatoren eines Kunden aus, kurz bevor ein Sicherheitsupdate ausgeliefert werden müsste.
Lösung Progressive Verzögerung statt Sperre, kombiniert mit Alarmierung. Rate-Limits pro IP und pro Konto, Cloudflare-Regel davor. Eine echte Sperre nur nach menschlicher Entscheidung.
Akzeptanzkriterien
- 1000 Fehlversuche gegen ein Konto sperren es nicht aus, erzeugen aber einen Alarm.
- Der legitime Inhaber kann sich während des Angriffs weiterhin anmelden.
Prio: P2 · Typ: process
Lösung Ein kontrollierter Versuch mit einem AiTM-Proxy gegen ein Testkonto mit Geräterolle. Erwartetes Ergebnis: Der Angriff scheitert, weil WebAuthn die Origin-Bindung durchsetzt.
Derselbe Versuch gegen ein viewer-Konto mit TOTP: Erwartetes Ergebnis: er gelingt — und
belegt damit, warum IDP-011 keine Rückfallebene erlaubt.
Akzeptanzkriterien
- Beide Ergebnisse sind protokolliert.
- Der Versuch gegen das Geräterollen-Konto erzeugt die Alarme aus
IDP-072.
Prio: P2 · Typ: process
Vor dem ersten Kunden mit Geräten im Feld. Schwerpunkt: Wiederherstellungsfluss, Einladungsfluss, Rollenerhöhung, Impersonation, Step-up-Umgehung.
Der Wiederherstellungsfluss zuerst — dort liegen erfahrungsgemäß die Findings.
Prio: P1 · Typ: process
Problem Gegen eine Schwachstelle in Zitadel selbst hilft keine Konfiguration. Nur Geschwindigkeit.
Lösung Abonnement der Zitadel-Sicherheitsmeldungen, feste Frist: kritische Lücken binnen 24 Stunden, hohe binnen 72 Stunden. Der Rolling-Deploy über zwei Knoten macht das unterbrechungsfrei.
Ein Zitadel, das drei Versionen zurückliegt, macht jedes andere Ticket dieses Backlogs wirkungslos.
Vor dem ersten echten Nutzer — nicht nachrüstbar ohne Zeitfenster:
IDP-001 → IDP-002 → IDP-003 → IDP-004 → IDP-005 → IDP-010 → IDP-011 →
IDP-011b → IDP-011c → IDP-012 → IDP-020 → IDP-022
Vor Produktivgang:
IDP-030 → IDP-031 → IDP-032 → IDP-033 → IDP-050 → IDP-051 → IDP-034 →
IDP-013 → IDP-014 → IDP-040 → IDP-021 → IDP-070 → IDP-071 → IDP-073 → IDP-090
Vor dem ersten Kunden mit Flotte:
IDP-041 → IDP-042 → IDP-043 → IDP-060 → IDP-061 → IDP-015 → IDP-072 →
IDP-023 → IDP-080 → IDP-081
Danach: IDP-052, IDP-053
Alles vor
IDP-041macht Kontoübernahme schwer.IDP-041bisIDP-043machen sie unzureichend. Nur zusammen ergeben sie eine Antwort auf die Frage, warum ein Hersteller uns die Kontrolle über hunderttausend Geräte anvertrauen sollte.