trstctl /docs GitHub ↗

Enroll devices and IoT fleets

Goal

When you finish this journey, the routers, switches, printers, phones, and IoT devices you already run will enroll for trstctl-issued certificates over the enrollment protocols baked into their firmware — and renew before expiry — without re-flashing a single device. It is for teams with an existing fleet of network or embedded gear that speaks EST, SCEP, or CMP. In plain terms: a device asks trstctl for a certificate using the protocol it already knows, trstctl checks the request against its rules, and hands back a signed certificate.

Before you start

  • A running trstctl control plane with a provisioned issuing CA. Bring one up via Issue your first certificate or Getting started.
  • A device (or a standard client such as a stock EST client) that speaks EST, SCEP, or CMP.
  • For depth on the protocols, certificate-profile control, and failure behavior, see the Device enrollment with EST guide, whose concrete flow this journey lifts.

Steps

  1. Enable the enrollment protocol your fleet speaks. Each protocol server is off by default and binds to a tenant. For EST, turn it on:

    protocols:
      est:
        enabled: true
        tenant_id: "11111111-1111-1111-1111-111111111111"
    

    You should see the control plane mount EST under /.well-known/est/... (and, similarly, SCEP at /scep and CMP at /cmp when enabled) on startup. The three protocols and what each industry uses are covered in Enrollment protocols.

  2. Fetch the CA chain to establish trust. A device fetches the CA chain first (no auth) so it can bootstrap explicit trust before sending anything:

    curl -s https://trstctl.example.com/.well-known/est/cacerts -o cacerts.p7
    

    You should receive a certs-only PKCS#7 chain. The device installs it as its explicit TLS trust anchor.

  3. Enroll: POST a CSR, get back a certificate. The device generates its key locally (the private half never crosses the wire), builds a PKCS#10 CSR, and enrolls. With a stock client this is a base64 CSR POSTed to /simpleenroll:

    curl -s -H "Content-Type: application/pkcs10" \
         -H "Idempotency-Key: $(uuidgen)" \
         --data-binary @request.b64 \
         https://trstctl.example.com/.well-known/est/simpleenroll
    

    You should get back the issued certificate wrapped in a PKCS#7. Every enrollment is validated against the endpoint's bound certificate profile before anything is signed — a disallowed key type, EKU, over-long validity, or out-of-profile name is rejected. The profile model is described in Issuance & certificate authorities.

  4. Renew before expiry. Before the certificate expires, the device re-enrolls over the same protocol — for EST that is a POST to /simplereenroll, the same request and response shapes as the first enroll. You should see a fresh certificate issued the same way. Because issuance is idempotent, a retried enrollment never mints two certificates.

  5. For the smallest devices, bootstrap with a one-time token. Constrained IoT hardware that cannot run a full agent bootstraps with a single-use token over the served endpoint; the device generates and keeps its own key and sends only a CSR:

    curl -s -X POST https://trstctl.example.com/enroll/bootstrap \
         -d '{"token":"<one-time-token>","csr":"<base64-DER-CSR>"}'
    # -> {"certificate":"<PEM chain>"}
    

    You should receive a PEM certificate chain. The token is checked-and-deleted atomically, so it works exactly once.

  6. For MDM-managed phones and laptops, gate enrollment with a challenge. When a mobile-device-management platform (Intune, JAMF) pushes a SCEP profile, you want only MDM-provisioned devices to enroll. trstctl issues an HMAC-signed challenge token the MDM embeds in the device's SCEP profile challengePassword, and the SCEP server validates it (constant-time check, expiry) before issuing — fail-closed on any defect. You should see enrollment succeed only for devices carrying a valid challenge. This is covered in Enrollment protocols.

    Honest status: the EST, SCEP, and CMP servers are served end-to-end and cross-checked against stock reference clients in CI. The embedded renewal endpoint and the MDM challenge gate's served activation are tracked in Current limitations.

Where next

Journey: J4 Steps through: F22, F23, F55, F54, F56

Rendered live from github.com/ctlplne/trstctl — found a mistake? edit this page.