Zero-Trust Device Authentication Without the Enterprise Price Tag
Bearer tokens are the workhorse of agent authentication. Every RMM platform uses some variant of the pattern: the agent enrolls, gets a secret, and presents it on every API call. It works. It scales. And when someone steals that secret, they own the device.
Think about what a stolen agent token actually gives an attacker. They can heartbeat as the device, receive any pending commands (including scripts with embedded credentials), report fake telemetry, and quietly exfiltrate data from the command queue. Token rotation shrinks the exposure window, but it does not eliminate it — between rotation intervals, that token is a skeleton key. The industry knows this. That is why the enterprise zero-trust vendors — Zscaler, CrowdStrike, the usual suspects — have built proprietary solutions that layer device identity below the application. But those solutions come with $20k+/year price tags, proprietary agents you cannot inspect, and vendor lock-in that makes migration a multi-quarter project.
What If the Network Did the Checking?
Mutual TLS flips the authentication model. Instead of the server deciding whether to trust the client based on a shared secret, the TLS layer itself enforces identity. Every Breeze agent gets a unique X.509 client certificate at enrollment time. When the agent connects, it presents that certificate during the TLS handshake — before a single byte of HTTP reaches the API server. Cloudflare’s edge verifies the cert, checks its validity, and either allows the connection through or drops it at the network layer.
This is not a novel concept. Banks and payment processors have used mTLS for API security for decades. What is new is applying it to RMM at the scale of thousands of managed endpoints, using Cloudflare’s API Shield to handle the certificate verification so you do not need to run your own PKI infrastructure. The result: a stolen bearer token is useless. The attacker does not have the private key stored on the device, so Cloudflare blocks the connection before it ever reaches your Breeze API. The bearer token remains as the application-layer identity check — mTLS is layered on top, giving you defense in depth.
How Breeze Does It
The certificate lifecycle is designed so that certificates never expire during normal operation. Here is the full flow:
Enrollment
|
v
+---------------------+
| Certificate Issued | (valid for certLifetimeDays, default 90)
| Status: online |
+---------------------+
|
| At 2/3 of lifetime...
v
+---------------------+
| Heartbeat returns | renewCert: true
| renewCert: true |
+---------------------+
|
| Agent calls POST /renew-cert
v
+---------------------+
| New cert issued | Old cert revoked via Cloudflare API
| Status: online |
+---------------------+
If cert expires before renewal (agent was offline)...
|
v
+------------------------------------------+
| Agent startup detects expired cert |
| Creates bearer-only HTTP client |
| Calls POST /renew-cert |
+------------------------------------------+
| |
| auto_reissue policy | quarantine policy
v v
+--------------+ +------------------------+
| New cert | | Status: quarantined |
| issued | | Awaiting admin approval |
| Status: online| +------------------------+
+--------------+ | |
| approve | deny
v v
+----------+ +-----------------+
| New cert | | decommissioned |
| online | +-----------------+
+----------+
When an agent enrolls, the Breeze API calls Cloudflare’s Client Certificates API to issue a cert, then returns the certificate and private key in the enrollment response alongside the standard bearer token. The agent stores both the cert PEM and key PEM in its config file with strict permissions (0600 for the file, 0700 for the directory).
The key insight is proactive renewal. On every heartbeat, the API checks whether the current time has passed two-thirds of the certificate’s lifetime. For a 90-day cert, that means renewal kicks in at day 60 — giving you a full 30-day buffer. The agent spawns a background goroutine to call the /renew-cert endpoint, the old cert gets revoked via the Cloudflare API, and the new cert is saved to the config file. Active WebSocket connections are not interrupted; the new cert is picked up on the next reconnect.
The Go agent’s expiry logic fails closed. If IsExpired() cannot parse the expiry timestamp, it treats the cert as expired and forces a renewal attempt. This is a deliberate design choice — an unparseable date should never result in the agent silently running without a valid certificate.
Why It Is Effectively Free
Cloudflare API Shield Client Certificates are included in Cloudflare Business and Enterprise plans. There is no per-device fee. No per-certificate fee. You are not standing up a certificate authority, managing a CRL distribution point, or buying an HSM. The Breeze API makes a single API call to Cloudflare to issue a cert at enrollment and another to revoke it at renewal. That is the entire infrastructure cost.
Compare that to the enterprise alternative. A dedicated zero-trust device identity platform will run you five to six figures annually, scale pricing by device count, and require you to deploy yet another agent on every endpoint. With Breeze, you are using the Cloudflare plan you likely already have for DNS and CDN, the open-source agent you already deployed, and a few hundred lines of TypeScript and Go. The mTLS service implementation (cloudflareMtls.ts) is about 100 lines. The agent-side cert handling (mtls.go) is under 90. There is no magic here — just a clean integration with infrastructure you are already paying for.
Fully Optional, Progressive Rollout
This is not a flag-day migration. The mTLS feature is deployed in five phases, and you can stop at any point with zero impact on running agents.
Phase 1: Deploy code. Update your API and agent binaries. Nothing changes. The mTLS code path checks for CLOUDFLARE_API_TOKEN and CLOUDFLARE_ZONE_ID environment variables; when they are absent, every mTLS function returns null. Enrollment responses include mtls: null. Agents behave exactly as before. Phase 2: Set credentials. Add the two env vars and restart the API. Now new enrollments receive an mTLS certificate, but Cloudflare is not enforcing it yet — agents present the cert if they have one, but requests without certs still pass through. Existing agents keep working with bearer-token-only auth. Phase 3: Run database migration. Add the mTLS columns to the devices table (mtls_cert_serial_number, mtls_cert_expires_at, mtls_cert_issued_at, mtls_cert_cf_id, quarantined_at, quarantined_reason). Phase 4: Verify agents. Enroll test agents, confirm certs appear in the Cloudflare dashboard, check that the agent config file has the cert PEM populated. Phase 5: Enable WAF enforcement. Create a Cloudflare WAF custom rule that blocks requests to agent routes without a valid client certificate, excluding the enrollment and renewal endpoints.
At each phase, the system is in a consistent, working state. Phase 2 without Phase 5 means you are issuing certs but not requiring them — useful for a gradual rollout across your fleet. An MSP managing 500 endpoints can migrate a handful of test devices first, verify everything works, and then flip the WAF switch when they are confident.
The Quarantine Flow
When an organization’s expiredCertPolicy is set to quarantine, expired certificates become a deliberate checkpoint rather than an automatic renewal. If an agent’s cert expires — maybe the device was powered off for three months, maybe it was stolen and kept offline — the agent calls /renew-cert and instead of receiving a new certificate, it gets a quarantined status. The device shows up in the quarantine queue, timestamped, with the reason mtls_cert_expired.
This is your kill switch. An admin reviews the quarantined device list, sees the hostname, OS, and last-known state, and makes a decision: approve or deny. Approving issues a fresh certificate and sets the device back to online. Denying moves it to decommissioned — the device is cut off permanently. For MSPs managing client environments with compliance requirements, this is the difference between “we rotate certs” and “we have a documented chain of custody for every device identity on the network.” The alternative policy, auto_reissue, skips the human review and hands out a new cert automatically — appropriate for environments where availability matters more than manual oversight.
It Is Open Source
Every line of this is in the Breeze repository. The implementation lives in three places:
- API service:
apps/api/src/services/cloudflareMtls.ts— the Cloudflare API wrapper that issues and revokes certificates - Go agent:
agent/internal/mtls/mtls.go— cert loading, expiry checks, and the fail-closedIsExpired()logic - Setup guide:
docs/cloudflare-mtls-setup.md— the full five-phase deployment walkthrough with SQL migrations, verification steps, and troubleshooting
If you are running Breeze today, you can enable mTLS this afternoon. If you are evaluating RMM platforms, read the source — the security model is not behind a sales call.
Next in the Breeze Security series: agent token hashing, rate limiting, and the audit trail.