Identity, Access & Fleet Operations
Operator identity (OIDC / Keycloak-compatible)
Control-plane operator authentication uses a standard OIDC authorization-code flow against a provider's discovery document (Keycloak-compatible; any spec-compliant OIDC provider fits the same integration). The returned ID token is verified RS256 against the provider's JWKS, with issuer, audience, expiry, and nonce all checked, and login state is single-use.
- JWKS is cached for 10 minutes by default. A refresh replaces the cached key set wholesale. If a refresh fails while the cache is already stale, that is treated as a hard authentication failure — the system does not fall back to potentially-revoked stale keys just to keep logins working.
- JWT group/role claims map to internal roles via configuration; an identity whose claims don't match a configured mapping receives no privileges — there is no default role granted to an authenticated-but-unmapped identity.
- Route authorization is deny-by-default. The Admin UI is served with a restrictive
Content-Security-Policy (
script-src 'self', no inline scripts, noeval) and standard hardening headers (X-Frame-Options,X-Content-Type-Options,Referrer-Policy) on every served path, including the entry HTML and its scripts. - Sessions carry explicit expiry and are purged once expired.
Roles
| Role | Intended scope |
|---|---|
| Administrator | Full control-plane administration |
| Security Officer | Policy authoring, publication, rollback |
| CISO / Viewer | Read-only audit and compliance visibility |
| Developer | Local statistics access |
Credential storage
Operator passwords are stored with Argon2id (memory-hard, per-credential salt). Agent enrollment/authentication tokens use a keyed hash with a server-side pepper (HMAC). Legacy credentials are transparently rehashed and upgraded on next successful login.
Fleet enrollment and lifecycle
%%{init: {"theme": "base", "themeVariables": {"fontFamily": "-apple-system, Segoe UI, Helvetica, Arial, sans-serif", "primaryColor": "#eef2f7", "primaryTextColor": "#0b0b0b", "primaryBorderColor": "#5b6b7c", "lineColor": "#5b6b7c", "secondaryColor": "#eef4ff", "tertiaryColor": "#f4f3f0", "clusterBkg": "#f9f9f7", "clusterBorder": "#c3c2b7", "edgeLabelBackground": "#fcfcfb", "actorBkg": "#eef2f7", "actorBorder": "#5b6b7c", "actorTextColor": "#0b0b0b", "actorLineColor": "#5b6b7c", "signalColor": "#52514e", "signalTextColor": "#0b0b0b", "labelBoxBkgColor": "#eef4ff", "labelBoxBorderColor": "#5b6b7c", "labelTextColor": "#0b0b0b", "loopTextColor": "#0b0b0b", "noteBkgColor": "#fdf3d9", "noteBorderColor": "#c98500", "noteTextColor": "#3d2f00", "activationBorderColor": "#5b6b7c", "activationBkgColor": "#eef4ff", "sequenceNumberColor": "#ffffff"}}}%%
sequenceDiagram
participant Op as Operator
participant CP as Control Plane
participant WS as Workstation Agent
Op->>CP: issue org-scoped, single-use enrollment token (with expiry)
WS->>CP: register(enrollment token)
CP-->>WS: agent credential token
loop periodic
WS->>CP: heartbeat (authenticated, real runtime mode)
WS->>CP: fetch policy (authenticated)
CP-->>WS: signed policy snapshot
WS->>WS: verify via policy-integrity chain, persist atomically
end
loop version check
WS->>CP: check version catalog
CP-->>WS: signed update artifact metadata\n(URL, checksum, signature, signing key)
WS->>WS: verify signature, install atomically
alt post-update health check fails
WS->>WS: automatic rollback
end
end
- Enrollment is closed by default. An unconfigured enrollment token disables enrollment entirely. Re-registering a workstation does not silently rotate its credentials without presenting the current one — resetting enrollment is an explicit, audit-recorded action.
- Heartbeat requires authentication unconditionally, and always reports the agent's
actual runtime mode (including a degraded/
strict_fallbackstate). - Every outbound HTTP call from the agent shares one dispatch function that refuses
plaintext
http://to any non-loopback host unless an explicit environment override is set (and logs a warning when it is); loopback addresses are always permitted, since that's the local development/test path. - Updates are signed artifacts. Verification precedes installation; a failed post-update health check triggers automatic rollback. Auto-update can be disabled independently while heartbeat, policy sync, and event sync continue operating normally.
- Every installer provisions a trust store: root-owned, not group- or world-writable, with at least one non-development signing key. Installation without valid trust material fails outright — it does not complete in a state that trusts nothing, and it does not fall back to a built-in key.
Operator visibility
The Admin UI's events table is the operator's incident feed: status (blocked / passed / no-decision), detector, a human-readable description built only from already-sanitized fields (never raw command lines or arguments), and a drill-down detail view. A no-decision event (e.g. an MCP session status change, a policy integrity failure, a queue overflow) is visually distinct from an actual allow/block outcome.
Scale targets
| Dimension | Pilot | Production target |
|---|---|---|
| Workstations per control plane | 50 | 5,000 |
| Events per workstation per day | ~200 | ~2,000 |
| Local repositories per scan | 10 | 500+ |
| Policy snapshot size | <100 rules | <2,000 rules |
Continue to Deployment & Infrastructure.