Repository navigation
Architecture and Security
Tyler Hatfield edited this page Nov 12, 2026
·
4 revisions
Vitrine RMM is architected around zero-trust authentication, Enterprise OIDC PKCE SSO, cryptographic secret vaulting at rest, strict multi-tenant RBAC, strict Content-Security-Policy (CSP), and defense-in-depth SSRF/WebSocket validation.
-
Zero-Default Bootstrap: Fresh installations contain no pre-seeded user accounts. The initial
super_adminis created interactively on first boot (POST /api/auth/setup-initial-admin), after which bootstrap is permanently locked (HTTP 409). -
Memory-Hard Password Hashing (
scrypt) & Mutation Guards: User and guest portal passwords are salted with 16 CSPRNG bytes, hashed viacrypto.scryptSync(N=16384, r=8, p=1), and verified viacrypto.timingSafeEqual. User updates (PUT /api/users/:id) enforce a minimum 10-character password policy, block demoting the last activesuper_admin(HTTP 400), and immediately revoke active sessions upon password, role, or tenant reassignment. -
OpenID Connect (
OIDC) Authorization Code +S256 PKCESSO:- Supports Authentik, Keycloak, Pocket ID, Authelia, Okta, and Microsoft Entra ID via standard
.well-known/openid-configurationdiscovery (POST /api/auth/oidc/test). -
GET /api/auth/oidc/logingenerates a cryptographic 32-bytecode_verifier,S256code_challenge,state, andnoncebound to a short-livedHttpOnlycookie (vitrine_oidc_tx). -
GET /api/auth/oidc/callbackvalidatesstate, exchanges the authorization code withcode_verifier, verifies ID tokennonce/issuer/expiry and/userinfoclaims, enforces verified email status, and optionally provisions Just-In-Time (JIT) technician accounts whenoidc_auto_provisionis enabled.
- Supports Authentik, Keycloak, Pocket ID, Authelia, Okta, and Microsoft Entra ID via standard
-
Revocable Sessions & Live WebSocket Enforcement:
- Sign-in issues a 256-bit random session token stored only as a SHA-256 digest in
auth_sessions(HttpOnly; SameSite=Lax, plusSecureover HTTPS). -
/ws/terminaland/ws/telemetryenforce strictOriginheader validation (isAllowedCorsOrigin) on HTTP upgrade and re-verifyisSessionTokenActive(tokenHash)on every inbound frame and outbound broadcast tick — terminating WebSocket streams immediately if a session is logged out or revoked.
- Sign-in issues a 256-bit random session token stored only as a SHA-256 digest in
Every /api/* request and /ws/* WebSocket upgrade passes through a global authentication and authorization hook:
| Role | Tenant Scope | Capabilities |
|---|---|---|
MSP Super Admin (super_admin) |
Global (All Clients) | Full fleet control, user/RBAC management, system settings, OIDC SSO, code signing, MeshCentral federation, client permanent deletion/purge, Backup Recovery Key reveal, encrypted backups & restores, and system updates. |
Technician (technician) |
Global or Assigned Clients | Remote KVM/Ghost/AMT sessions, background tools, patch & script execution, LAPS, BitLocker & secret Custom Field reveal (all gated by per-user Step-Up MFA), hypervisor sync, policy edits, and standard endpoint offboarding. |
Client Admin (client_admin) |
Strictly Bound tenant_id
|
Read-only visibility strictly isolated to their assigned tenant_id (including tenant-scoped notifications). Sub-routes for /files, /files/download, /registry, /processes, /services, /tasks, /eventlogs, /laps, /bitlocker, /notes, and /chat return HTTP 403 Forbidden, and secret custom fields are completely stripped. |
Sensitive secrets are never stored in plaintext in SQLite or leaked in API list responses:
-
Master Key Management: Uses
VITRINE_MASTER_KEY(orLAPS_MASTER_SECRETalias) when provided via secret manager, or auto-generates<DATA_DIR>/.vault-key.jsonwith0600file permissions. Cross-machine backup restores automatically reload the active vault key in memory (reloadVaultMasterKey()). -
Authenticated Encryption (
enc:v1:<iv>:<tag>:<ciphertext>): Encrypts LAPS passwords (current & historical), BitLocker/LUKS/FileVault recovery keys,secret-type Custom Field values, per-user TOTP secrets, OIDC client secrets, MeshCentral API tokens, hypervisor & specialty device credentials, SMTP passwords, ITFlow API keys, PSA webhook secrets, S3 offsite secret keys, backup passphrases, and per-device agent heartbeat tokens. -
Vaulted
secretCustom Attributes: Custom fields defined withfield_type = 'secret'are encrypted at rest incustom_field_values, masked (••••••••••••) for technicians by default, preserved without corruption when masked placeholders are saved back, stripped completely fromclient_adminand Guest Portal responses, and revealed only viaGET /api/devices/:id/custom-fields?reveal=truewith an active Step-Up MFA session.
Accessing high-impact vault secrets (GET /api/devices/:id/bitlocker, GET /api/devices/:id/laps?reveal=true, GET /api/devices/:id/custom-fields?reveal=true, POST /api/backups/recovery-key, and POST /api/laps/break-glass-export) requires Step-Up MFA (POST /api/auth/verify-mfa):
-
Strict Per-User TOTP Secrets: Every administrator and technician maintains an isolated per-user
users.totp_secret(no shared global fallback). -
Time-Step Anti-Replay: Records
last_totp_stepper user so a 6-digit TOTP code cannot be replayed within the same 30-second window (HTTP 401). -
Single-Use Recovery Codes: Users receive 8 high-entropy emergency recovery codes stored as SHA-256 digests (
recovery_codes_json), atomically consumed on use.
-
Strict
Content-Security-Policy(CSP): Responses enforcedefault-src 'self'; script-src 'self'; object-src 'none'; base-uri 'self'; frame-ancestors 'self'with zero inline<script>execution required by the SPA. -
DNS-Rebinding Outbound SSRF Guard (
validateOutboundHostSafety): All outbound connections — specialty appliance probes, hypervisor APIs, OIDC discovery/token endpoints, S3 offsite backup uploads, ITFlow PSA sync, Cloud HSM signing webhooks, and MeshCentral federation — resolve target hostnames viadns.promises.lookup(..., { all: true })and block loopback (127.0.0.0/8,::1), link-local metadata (169.254.0.0/16,fe80::/10), CGNAT, multicast, and IPv4-mapped IPv6 bypasses (preserving explicit private LAN opt-in only where intended for local infrastructure).