Security Trust Model
Telovix separates four independent trust domains: control-plane trust between sensors and the Console, policy trust for runtime behavior, operator access trust for the Console UI and API, and commercial trust for entitlements. Each domain has distinct mechanisms and failure modes. Understanding the boundaries prevents misdiagnosis when something goes wrong and prevents incorrect assumptions about what a compromised component can affect.
The four trust domains
| Domain | What it governs | Mechanism |
|---|---|---|
| Control-plane trust | Sensor identity and communication with Console | Mutual TLS with per-sensor client certificates |
| Policy trust | Whether a delivered runtime policy is trusted | Ed25519 signature verification per policy file |
| Operator access trust | Who can read and write Console state | Session authentication, RBAC, optional SSO and MFA |
| Commercial trust | Whether a deployment is entitled to run | Offline Ed25519-signed license bundles |
These four domains are intentionally independent. A compromised enrollment token does not affect policy trust. A license expiry does not revoke sensor certificates. A rogue operator session cannot bypass policy signature verification on the sensor.
Control-plane trust: sensor to Console
Enrollment
During enrollment, the sensor generates a local RSA key pair using rcgen and creates a Certificate Signing Request with CN=<node_name>, O=Telovix Sensor. It presents an enrollment token alongside this CSR to the Console enrollment endpoint. The Console verifies the token and signs the CSR, issuing a client certificate with a 720-hour (30-day) TTL by default.
The enrollment token is a bootstrap secret only. It is consumed at enrollment time. After enrollment, the durable sensor identity is the client certificate, not the token.
The Telovix Console returns:
control_plane_certificate_pem: the signed client certificatecontrol_plane_ca_certificate_pem: the Console's CA certificatepolicy_signing_public_key_pem: the Ed25519 public key for policy verificationcertificate_expires_at: expiry timestamp in RFC3339 formatcertificate_reference: internal reference ID
The sensor atomically writes all of these to the state directory (/var/lib/telovix-sensor by default). The sensor-state.json file records trust_state="trusted" and renewal_status="ok".
All subsequent communication
Every heartbeat, WebSocket connection, and policy download uses outbound mTLS. The sensor presents its client certificate on every request. The Console validates the certificate against its CA on every request. There is no API key or session token fallback for sensor communication.
Renew certificates
Renewal is triggered automatically:
| Trigger | Condition |
|---|---|
| Proactive renewal | Certificate expiry is less than 72 hours away |
The renewal process generates a new CSR and submits it to the Console renewal endpoint. The Console issues a new certificate. The sensor writes the new key first, then the certificate, so that a crash mid-write triggers re-enrollment rather than leaving a corrupt state.
The default certificate TTL is 720 hours (30 days). The renewal-due threshold defaults to 86400 seconds (1 day).
Read trust states
| State | Meaning |
|---|---|
trusted | Certificate is valid; mTLS is working |
renewal_recommended | Cert is approaching expiry but still within tolerance |
renewal_due | Cert expiry is within the renewal threshold; renewal should happen immediately |
trust_revoked | Console revoked this sensor; mTLS will stop working |
When trust state is trust_revoked, the Sensor stops forwarding events and the Console rejects requests from that identity. Review trust alerts and status from Sensors > Fleet and Sensors > Health Center.
Understand trust state and enforcement
Resolve sensor trust problems before changing enforcement. Confirm the intended rule and its sensor-reported delivery result in Runtime Blocks; a requested state alone does not establish active protection.
Policy trust: runtime behavior
Verify policy delivery
Runtime policies are delivered from the Console to the sensor as YAML files. Each policy file may be accompanied by a .sig sidecar file containing an Ed25519 signature, base64-encoded.
The Console holds an Ed25519 signing key at the path configured during setup (default: policy-signing.ed25519). The sensor receives the corresponding public key during enrollment and stores it at policy-signing.pub.
When loading a policy file, the sensor follows this logic:
- If a
.sigsidecar exists: load the public key frompolicy-signing.pub, verify the signature againsttelovix-policy-v1:{policy_name}\n{yaml_content}, and reject the policy if verification fails. - If no
.sigsidecar exists but a signing key is present: log a warning and proceed (backward compatibility with pre-signing deployments). - If no
.sigsidecar and no signing key: skip verification.
The signature format telovix-policy-v1:{name}\n{content} binds the policy name to its content. A policy file cannot be renamed and applied under a different name without invalidating the signature.
This means a policy injected by an attacker who can write to the sensor's state directory but does not have the Console's Ed25519 private key will be rejected at load time.
Operator access trust
Authentication
Console users authenticate with email and password. Sessions are issued as secure, HTTP-only cookies. TOTP-based MFA is available for local accounts. The Console supports OpenID Connect (OIDC) for SSO through Okta, Microsoft Entra ID, Google Workspace, and generic OIDC providers. Administrators manage SSO from Settings > SSO.
API keys are scoped alternatives to session authentication for programmatic access. API keys are created by authenticated users and can be revoked individually.
Role-based access control
| Role | Level | What it can do |
|---|---|---|
viewer | 1 | Read-only access to sensors, events, and reports |
analyst | 2 | All viewer permissions plus investigation and alert management |
sensor_owner | 3 | All analyst permissions plus sensor management for owned sensors |
operator | 3 | All analyst permissions plus policy management, enforcement changes, and exercise creation |
admin | 4 | Full access including user management, settings, and license import |
Role levels are enforced server-side on every request. The require_operator and require_admin middleware functions gate the relevant API routes. Role elevation requires an admin user.
Commercial trust: license validation
License structure
The Portal issues signed license bundles. Each bundle is a JSON envelope with the structure:
{
"schema_version": 1,
"signature_algorithm": "ED25519",
"payload": {
"customer_id": "...",
"workspace_id": "...",
"license_id": "lic-...",
"plan": "growth",
"max_protected_nodes": 250,
"valid_from": "...",
"valid_until": "...",
"grace_until": "...",
"issued_at": "..."
},
"signature": "<base64-encoded-ed25519-signature>"
}The grace_until field extends the license beyond valid_until for a configurable grace period (default: 30 days). During the grace period, the deployment remains operational but the Console displays an expiry warning.
Signing
The Portal's license signing service exposes a single internal endpoint at POST /internal/v1/sign-license. This service is not reachable from the public internet. It loads the Ed25519 signing key from the path configured at deployment time, serializes the payload to canonical JSON, signs it, and returns the envelope. Communication between the Portal and the signing service is authenticated with a shared secret compared using constant-time comparison.
Console validation
The Console validates license bundles offline. It does not contact the Portal or any external service at validation time. The operator imports the signed bundle via the setup wizard or from Settings > License in the Console. The Console verifies the Ed25519 signature against its embedded public key and checks valid_until and grace_until against the current time.
This offline model means the Console continues operating in air-gapped or network-isolated environments as long as the imported license has not expired. The Console does not depend on Stripe connectivity, Portal availability, or any cloud service for runtime entitlement decisions.
Understand why commercial trust is separate
The Stripe payment flow, Portal workspace state, and billing webhook processing all feed the Portal. The Portal issues a signed license. The Console trusts only the signature on that license bundle, not any runtime state from Stripe or the Portal. This means:
- Stripe refunds, disputes, or service outages do not affect the Console's license state
- A compromised Portal cannot issue a license with capabilities beyond what the Ed25519 signing key authorizes
- A stolen or replayed license bundle is only as dangerous as the private key that signed it
Trust boundary violations and what they mean
| Violation | What is affected | What is not affected |
|---|---|---|
| Stolen enrollment token | Can enroll a rogue sensor during the token's valid window | Does not compromise existing sensors; revoke the token immediately |
| Stolen sensor client certificate | Can send forged heartbeats from that sensor identity | Does not affect other sensors; revoke via Console trust management |
| Compromised policy signing key | Can inject arbitrary policy into sensors that trust this key | Does not affect sensors with no signing key (they skip verification with a warning); rotate the key and re-enroll |
| Expired license | Console blocks new sensor enrollments above the node limit; grace period provides 30-day buffer | Does not revoke sensor certificates or stop active monitoring on enrolled sensors |
| Stolen operator session | Attacker has operator-level Console access | Cannot bypass mTLS on existing sensors; cannot forge signed policy without the Ed25519 key |
Monitor trust from the Console
| Console page | What it shows |
|---|---|
| Sensors > Fleet | Fleet-wide trust summary, filters, and active trust-alert status |
| Sensors > Health Center | Trust, connectivity, and reporting diagnostics across the fleet |
| Sensor detail > Overview | Trust state and current Sensor identity summary |
| Settings > License | Import a signed license bundle; view current license status |
Operational guidance
Do not share enrollment tokens across hosts. Each token should enroll one Sensor. Generate one token per node or cluster from Sensors > Deploy, then verify that the Sensor appears in Sensors > Fleet after enrollment.
Protect the policy signing key. Restrict access to the Console's signing key and include it in your protected backup procedure. If it is compromised, follow Policy Signing to rotate trust and replace signed policies.
Separate the license signing key from the Portal. The signing service runs as a separate process (backend-license). The key path should point to a key stored on a separate host or HSM. A compromised Portal cannot issue fraudulent licenses unless it can also reach the signing service and knows the shared secret.
Monitor trust alerts. Use the trust filters in Sensors > Fleet and the diagnostics in Sensors > Health Center to identify certificate expiry or revocation. Configure notifications so trust failures reach the responsible operators.