Command Palette
Search for a command to run...

Threat model

Eight trust boundaries. The list below is what each one is, then what it actually buys you when something on the other side gets compromised.

Boundaries

  1. Web or CLI to control RPC. HTTPS plus JWT bearer. The auth interceptor and per-procedure rate limits run first; the authz interceptor enforces permission gates.
  2. SCIM IdP to SCIM endpoint. Bcrypt-hashed bearer token per provider slug. Rate limits bucket on the slug (100/min) and on slug + client IP (20/min), applied before the bcrypt compare so token guessing can't be turned into a CPU DoS.
  3. SSO IdP to OIDC callback. PKCE (S256) plus state and nonce validation. Any client-supplied redirect_url is checked server-side: it must be same-origin with the configured callback base URL (loopback URLs are allowed for CLI flows), everything else is refused.
  4. Agent to gateway. mTLS with RequireAndVerifyClientCert (TLS 1.3 minimum), a SPIFFE peer-class SAN check, and a fail-closed revocation check against the CRL.
  5. Agent enrolment. Local Unix socket /run/pm-agent/enroll.sock. Registration-token gated and rate limited to 5 attempts per minute.
  6. Gateway to control InternalService. Internal mTLS proxy for credential-bearing operations (LUKS keys, LPS passwords). The listener requires the gateway peer class and rejects revoked certs — an agent cert, even a valid one, cannot reach it.
  7. Control to and from Asynq / Valkey. Every task payload is HMAC-signed with PM_TASK_SIGNING_KEY. The consumer verifies (constant-time) before handing off to its handler.
  8. Control to Postgres. sqlc-generated queries. Secrets at rest go through AES-256-GCM with CONTROL_ENCRYPTION_KEY (new writes bind an AAD context, enc:v2).

What stays safe when something gets compromised

The layers are stacked so no single compromise gives an attacker arbitrary action execution.

A compromised Valkey/Redis can't forge a dispatch. The HMAC envelope catches it before the gateway forwards.

A compromised gateway can't forge a dispatch the agent will run — and can't alter one either. The CA signature covers the full action envelope (id, type, params, desired state, timeout, schedule, target device), signed at the control server and verified fail-closed by the agent over the exact bytes it executes. Terminal session start is the documented exception — see Remote terminal access.

A compromised OIDC provider can't pin a session to an attacker-controlled redirect URL. The server-side same-origin check refuses, independent of whatever the IdP validates.

A leaked registration token is bounded: self-service tokens are forced single-use with a 7-day expiry; operator-created tokens carry whatever one-time/max-uses/expiry limits the operator set. The certificate it provisions is identity-bound (fingerprint pinned in the DB, key-continuity enforced on renewal) and rotated at 80% of its lifetime, with the superseded cert revoked.

A stolen device cert stops working when its device is deleted or its cert is superseded: the gateway consults a Valkey-backed CRL on every connection, fails closed while the list is unloaded, and refuses to boot without an initial CRL load.

See mTLS and signed actions and Asynq task signing for the cryptographic details.