Device CA — mTLS Device Identity
Clavex Device CA covers device/machine mTLS identity under
/api/v1/organizations/{org}/devices: a Vault PKI-backed certificate authority,
separate from the PAM SSH CA, that issues short-lived client certificates for IoT and
machine fleets. Admin endpoints require the security resource permission;
enrollment and renewal are device-facing and use a bootstrap secret / mTLS respectively,
not an admin session.
The Device Lifecycle
0. Configure the Device CA
Point Clavex at a Vault PKI secrets engine. On first save Clavex provisions the mount, generates the root CA, and configures the device-signing role.
1. Enrollment
Pre-register the device and issue a one-time bootstrap secret for it — scoped to that single device, never a fleet-wide shared credential. Inject the secret into the device during your physical provisioning process; the device generates its own key pair locally and sends only the CSR.
# Device: generate its own key pair + CSR (private key never leaves the device) $ openssl req -new -newkey ec -pkeyopt ec_paramgen_curve:P-256 -nodes \ -keyout device.key -out device.csr -subj "/CN=sensor-042@$ORG_ID"
# Device: enroll once, with the CSR + the bootstrap secret it was provisioned with $ curl -s -X POST https://id.clavex.eu/api/v1/organizations/$ORG_ID/devices/enroll \ -H "Content-Type: application/json" \ -d "{\"device_id\":\"sensor-042\",\"bootstrap_secret\":\"9f8e...\",\"csr_pem\":\"$(cat device.csr)\"}" \ | jq -r .certificate_pem > device.crt
<deviceID>@<orgID> — this is the identity format the MQTT broker's
client-auth hook expects, and the CSR's own CN must already match it exactly or enrollment
is rejected.
2. Self-Service Renewal
Renewal never touches the bootstrap secret or an operator. The device authenticates with its current, still-valid certificate over a dedicated mTLS listener and gets a fresh one for the same identity — safe to run unattended indefinitely.
$ curl -s -X POST https://id.clavex.eu:8443/renew \ --cert device.crt --key device.key \ -H "Content-Type: application/json" \ -d "{\"csr_pem\":\"$(cat device-new.csr)\"}" \ | jq -r .certificate_pem > device-new.crt
renewal_window_seconds
remains before not_after — the server accepts any renewal against a
still-valid, still-active certificate, so the exact cadence is up to your device-side
tooling.
3. Revocation
The real defence for a compromised device — not "stop renewing and wait", since a certificate stays cryptographically valid until its expiry regardless of whether Clavex keeps renewing it.
| Endpoint | Purpose |
|---|---|
| POST /devices/:device_id/certificates/:serial/revoke | Revoke one issued certificate by serial number |
| POST /devices/:device_id/revoke | Revoke every active certificate for the device and flag the device itself revoked (whole-device-stolen path) |
| POST /devices/enrollment-secrets/:secret_id/revoke | Revoke an unused (still-pending) bootstrap secret — e.g. an operator fat-fingered provisioning |
Revoking a certificate dispatches a device.cert.revoked connector event
carrying device_id/tenant_id/serial, so the MQTT
broker (or any other external consumer) can maintain its own local deny-list without
polling Clavex.
4. CA Rotation
Rare, operator/agent-driven, and staged the same way as the SSH CA's rotation:
POST /devices/ca/rotation/start → status polling → mark-ready →
complete) so both the old and new CA certificates are trusted during cutover and no
device drops its connection. This is an advanced operation — see the Admin API reference
for the full state machine.