Skip to main content

Enroll devices with EST

EST (RFC 7030) lets devices request and renew certificates over HTTPS. Compared to SCEP it adds two things that matter for a fleet: devices can renew using the certificate they already hold, and each device can bootstrap with an identity of its own instead of a secret shared across the fleet.

For the background on device enrollment, see Device certificate enrollment.

Enable EST on a CA

Create or update a TLS CA with an est section. Unlike SCEP, EST does not require an RSA-keyed CA, so the platform default (ECDSA) is fine:

supctl create strongbox tls ca <<EOF
name: devices
est:
enabled: true
initial-enroll-secret: <a strong shared secret>
allowed-domains:
- example.com
allow-subdomains: true
ttl: 30d
EOF

EST shares its identity policy (allowed-domains, allow-subdomains, allow-bare-domains, allow-ip-sans, ttl) with SCEP, so a certificate carries the same guarantees whichever protocol a device used. See Enroll devices with SCEP for what each setting does.

EST is served on its own port, 4665. The CA publishes the URLs:

supctl show strongbox tls ca devices --fields est
est:
enabled: true
allowed-domains:
- example.com
ttl: 30d
https-url:
- https://control-tower.example.com:4665/.well-known/est/<tenant-uuid>/devices/simpleenroll
- https://192.168.1.10:4665/.well-known/est/<tenant-uuid>/devices/simpleenroll

Three endpoints live under the same base path:

EndpointPurpose
/cacertsFetch the CA certificate chain. Unauthenticated.
/simpleenrollFirst enrollment.
/simplereenrollRenewal, authenticated by the certificate the device already holds.

Choose how devices authenticate their first enrollment

A device has no certificate from this CA yet when it first enrolls, so something else has to vouch for it. EST supports two methods, and you can configure either or both.

A shared secret

initial-enroll-secret is presented with HTTP Basic authentication over TLS. It is simple, and it is the direct equivalent of the SCEP challenge password, with the same caveat: every device shares it, so the identity policy is what limits what a holder can obtain.

curl --cert-type PEM \
-u device:<the shared secret> \
-H "Content-Type: application/pkcs10" \
-H "Content-Transfer-Encoding: base64" \
--data-binary @request.b64 \
https://<host>:4665/.well-known/est/<tenant-uuid>/devices/simpleenroll

A per-device birth certificate

initial-enroll-trust-ca names another CA whose certificates are accepted as TLS client authentication for first enrollment. A device presenting a client certificate issued by that CA -- typically a factory installed birth certificate -- may enroll with no shared secret at all. Each device then authenticates as itself:

supctl merge strongbox tls ca devices <<EOF
est:
initial-enroll-trust-ca: device-birth
EOF

The device enrolls by presenting its birth credential:

curl --cert birth.pem --key birth.key \
-H "Content-Type: application/pkcs10" \
-H "Content-Transfer-Encoding: base64" \
--data-binary @request.b64 \
https://<host>:4665/.well-known/est/<tenant-uuid>/devices/simpleenroll

Prefer this for a fleet. A shared secret compromised on one device compromises enrollment for all of them; a birth certificate does not.

note

The EST port accepts client certificates from any CA, because a birth certificate is by definition not issued by this system. Acceptance at the TLS layer is not a trust decision: the certificate is then verified against initial-enroll-trust-ca, and enrollment is refused with 401 if it does not chain to it. Only the EST endpoints are served on this port.

Renewal

With allow-reenroll-with-issued-cert (on by default), a device renews by calling simplereenroll with its current certificate as the TLS client certificate:

curl --cert device.pem --key device.key \
-H "Content-Type: application/pkcs10" \
-H "Content-Transfer-Encoding: base64" \
--data-binary @request.b64 \
https://<host>:4665/.well-known/est/<tenant-uuid>/devices/simplereenroll

No shared secret is involved, which is what makes short certificate lifetimes practical: renewal needs no operator and no distributed secret. Have devices renew well before expiry, so a device that has been unreachable for a while still has a valid certificate to renew with.

Enroll a post-quantum credential

EST accepts ML-DSA (NIST FIPS 204) certificate requests, so a device can hold a fully post-quantum credential. Create a CA with an ML-DSA key and enable EST on it:

supctl create strongbox tls ca <<EOF
name: devices-pq
cert-key-type: ml-dsa-65
est:
enabled: true
initial-enroll-secret: <a strong shared secret>
allowed-domains:
- example.com
allow-subdomains: true
ttl: 30d
EOF

A device with OpenSSL 3.5 or later enrolls exactly as before, using an ML-DSA key:

openssl genpkey -algorithm ML-DSA-65 -out device.key
openssl req -new -key device.key -subj "/CN=sensor-7.example.com" \
-outform DER | openssl base64 -A > request.b64

Both the device's key and the CA's signature on the issued certificate are then ML-DSA:

openssl x509 -in device.crt -noout -text | grep -i ML-DSA

SCEP cannot do this: its enrollment envelope depends on RSA key transport, so an ML-DSA-keyed CA cannot serve it. EST is the path forward for post-quantum device credentials.

Troubleshooting

401 Unauthorized. The credential was not accepted:

  • With a shared secret, check it matches initial-enroll-secret.
  • With a birth certificate, check that it chains to the CA named in initial-enroll-trust-ca, and that the CA still exists.
  • On renewal, check the client certificate was issued by this CA, is still valid, and has not been revoked.
  • If neither method is configured on the CA, enrollment is refused with 403 instead: there is nothing a device could present.

403 Forbidden. The request was authenticated but the requested identity is not permitted. Check the CN and DNS SANs against allowed-domains, allow-subdomains and allow-bare-domains, and whether the request carries an IP SAN while allow-ip-sans is off.

400 Bad Request. The body was not a well-formed PKCS#10 request, or its self-signature did not verify. Confirm the request is DER, base64-encoded, and signed by the key being certified.

404 Not Found. EST is not enabled on that CA, or the tenant or CA name in the URL is wrong. Use the URLs published under the CA's est section.