Straza / kill switch

Kill-switch propagation race Disabling a user in the identity system sends a SCIM deactivate to strazad, which writes a revocation, updates the denylist, revokes sessions, and fans the event out: a push relayed over each daemon's SSE stream reaches connected daemons in under two seconds, JetStream replay converges every gateway pod, and without a daemon the 300-second token TTL bounds the session's death. The kill itself is hash-chained. midPoint / IdM user disabled SCIM strazad SCIM active:false · DELETE revokeUserCtx revocation row · denylist session rows revoked straza.audit.identity user.killed → hash chain push relay: NATS → SSE straza.push.user.<id> p99 < 2 s straza daemon SSE /v1/push · state dropped JetStream replay straza.revocation.user every pod gateway denylists next /mcp or /v1 call denied no daemon · poll-refresh next checkin → 401 ≤ 300 s (token TTL) session token dies 300 s TTL · refresh refused reactivation is explicit: straza.revocation.lift deletes the row, lifts denylists, converges pods and replays daemon crash changes nothing: hooks re-verify token + snapshot on every call and fail closed
Press “disable user” to race the revocation across all three propagation lanes. Hover any element for its facts.
What this shows

The kill switch, end to end. Deactivating an identity in the IdM (or via admin API) reaches strazad as a SCIM active:false or DELETE. revokeUserCtx writes the revocation row, updates the in-memory denylist, revokes the user's session rows, and emits the events. Propagation races on three lanes: (1) a target-scoped push: strazad publishes straza.push.user.<id> on core NATS (pod-internal), the pod holding that daemon's SSE stream relays a revocation event over GET /v1/push, and the daemon drops session state with a p99 under 2 seconds (the CI-gated budget at 100k simulated clients); this works in every profile, standalone included, because no broker is client-reachable; (2) JetStream replay of straza.revocation.user that converges every gateway pod's denylist (boot also seeds from the revocations table, fail-closed on read error); (3) without a running daemon (or with its stream down), the next checkin 401s and the 300-second token TTL is the hard bound on the session's life. The kill itself is tamper-evident: straza.audit.identity (user.killed) enters the hash chain. Reactivation is an explicit lift event, never implicit.