Capabilities
Operations
Signed and retried webhooks, a dual audit ledger with a tamper-evident hash chain, time-boxed impersonation with consent, break-glass with mandatory rotation and drill health checks, and the admin console.
Identity systems earn their keep on the bad days: the incident, the audit, the locked-out CEO. Sentinel’s operational surface is built for those days — with the paper trail attached.
Webhooks
Admin-managed outbound webhooks (MapSentinelWebhookAdmin, default
/sentinel-admin/webhooks) subscribe endpoints to event kinds with wildcard patterns
(login.*, breakglass.*) — realm-wide, or scoped to a single organization so a tenant
can receive only their own events.
Deliveries are signed and survivable:
- Signature:
X-Sentinel-Signature: t=<unix>,v1=<hex hmac-sha256(secret, "t.body")>with a constant-time verify helper and a 5-minute default tolerance, plusX-Sentinel-Eventand anX-Sentinel-Deliveryidempotency key. Secrets arewhsec_…, rotatable per endpoint. - Retries: a lightweight outbox inside Sentinel.Core (no Relay dependency) with
exponential backoff — 1m, 5m, 30m, 2h, 12h — then dead-letter with admin visibility.
Ten consecutive failures disable the endpoint and emit
webhook.endpoint_disabledrather than hammering a dead listener forever. - Testing:
POST /{endpointId}/testfires a signed test event;GET /{endpointId}/deliveriesshows the delivery log.
The in-process ISentinelEventSink port remains for hosts that bridge events into their
own alerting or brokers. The event vocabulary is wide — login.*, mfa.*, passkey.*,
token.refresh_reuse_detected, risk.*, abuse.*, oidc.*, saml.*, federation.*,
workload.*, breakglass.*, impersonation.*, user.*, webhook.* — and every kind
is a stable string your SIEM can key on.
Audit: two ledgers, one of them chained
Sentinel keeps two deliberately different records:
security_events— user-visible events (logins, new devices, MFA failures, erasures) that power profile “activity” pages and webhooks.admin_audit— every admin mutation with before/after JSON snapshots, actor and actor kind (User,ServiceAccount,ApiKey,System,BreakGlass), target, org, and a tamper-evident hash chain: each entry’s hash covers its content plus the previous entry’s hash, per-realm, from a genesis of zeros.VerifyChainAsync(and the admin audit browser) detects any retroactive edit.
The chain coexists with retention: payload digests are stored separately from payloads, so retention redaction can null a payload while the chain still verifies. Tampering and forgetting are different operations, and the ledger can tell them apart.
Impersonation
Support needs to see what the user sees; auditors need to see that support did it.
Impersonation (MapSentinelImpersonation, under /sentinel-admin/impersonation) is:
- Time-boxed — 30 minutes by default, the token’s
expcapped to the window. - One active per actor — no parallel disguises.
- Reasoned — the reason field is mandatory and lands in both ledgers.
- Optionally consented — consent mode (global or per-realm) sends the target a
single-purpose consent token (
impconsent+sentinel); the session starts only onPOST /consent/approve. - Visible in the token — the access token carries an
actclaim with the actor’s id and the impersonation id;SentinelPrincipal.ImpersonatorId/.ImpersonationIdexpose it server-side, andGET /profile/mesurfaces the banner contract so SDKs can render “you are being impersonated / you are impersonating”.
Sessions are fenced by sentinel:org:impersonate / sentinel:global:impersonate —
evaluated per-target-resource like every other admin operation.
Break-glass
The 2 a.m. account everyone has and nobody tests. Sentinel’s version is complete — including the part where you rehearse it:
- Capped grants: break-glass users are marked by attribute, and a decorating
ISubjectDataSourceintersects their snapshot with a fixed pattern cap at build time — the emergency account cannot quietly accumulate power. - Alarm on use: every login emits
breakglass.loginthrough the event sink and webhooks. Break-glass that doesn’t page is just a backdoor. - Mandatory rotation after use — surfaced as
breakglass.rotation_requireduntil done. - Drill health check:
SentinelBreakGlassHealthCheckdegrades the host’s health when break-glass hasn’t been exercised within the configured window (90 days by default). An untested escape hatch fails your readiness probe, on purpose.GET /sentinel-admin/break-glass/statusand the drill marker endpoint drive the routine.
The admin console
Sentinel.Admin ships the React console as embedded static assets —
app.MapSentinelAdminUi() serves it (default /sentinel-admin/ui) with no Node
tooling at consume time. Dashboard, orgs, users, roles and grants, the authz inspector,
the audit browser with chain verification, webhooks, break-glass status, impersonation
and privacy actions — all against the same fenced admin API, authenticated through
Sentinel itself. The static routes are unauthenticated by design; every byte of data
comes from the authorized API.
Observability
Per-package health checks (database, signing-key ring, break-glass drill) tag into
liveness (/healthz) and readiness (/readyz) in the Sentinel Server, and are
registerable in any embedding host. The Server wires standard OpenTelemetry ASP.NET
Core + HttpClient instrumentation with an OTLP exporter (SENTINEL_OTLP); a packaged
AddSentinelInstrumentation() with Sentinel-specific meters is on the roadmap this
wave. SENTINEL_DEBUG=1 boot diagnostics follow the Relay convention.
Learn by building
The tutorials for this area, in order — each with a runnable sample.