Table of Content
Table of Content
When your IoT fleet reaches ten thousand devices, manual certificate management does not slow down — it breaks entirely. The engineer who provisioned certificates for the first hundred devices by hand is now a bottleneck measured in weeks, not hours. Certificates expire silently. Devices drop off the network. The root CA key sits in a spreadsheet somewhere. Auditors ask questions nobody can answer.
This guide is a technical treatment of the full problem: how mTLS works at the protocol level in IoT contexts, why certificate lifecycle automation is the only path that scales, what the PKI architecture underneath it looks like, where SCEP and ACME fit, and how hardware-rooted attestation changes the security model entirely. It ends with a concrete architectural blueprint that covers a fleet of any size.
1. The IoT Authentication Problem at Scale
IoT deployments have a property that enterprise device management does not: density. A typical enterprise might manage one device per employee. An industrial IoT deployment manages dozens of sensors per square meter. A smart building deployment has thousands of endpoints across a single campus. An automotive fleet has hundreds of embedded controllers per vehicle.
The authentication problem this creates is not primarily a cryptographic problem. It is an operational problem. Every device needs:
- A unique cryptographic identity that cannot be cloned
- A certificate issued by a CA the service trusts
- A mechanism to rotate that certificate before it expires
- A revocation path if the device is compromised or decommissioned
At a hundred devices, these operations are manageable manually. At ten thousand, they require automation. At a million, they require automation plus distributed infrastructure.
The failure mode of getting this wrong is not theoretical. In 2016, the Mirai botnet compromised over 600,000 IoT devices, primarily because those devices used hardcoded credentials that were never rotated. The protocol-level fix — replacing shared passwords with per-device X.509 certificates enforced via mTLS — eliminates the entire class of credential-theft attack. The operational challenge is issuing and rotating those certificates at the scale the deployment requires.
2. Why mTLS Is the Right Protocol for IoT Authentication
How TLS Works (and Why One-Way Is Not Enough)
Standard TLS authenticates the server to the client. When your phone connects to a banking app, TLS ensures you are talking to the real bank and that your traffic is encrypted. The bank has no cryptographic proof of who you are — it relies on passwords, tokens, or sessions layered on top.
For IoT device-to-service communication, this asymmetry creates a structural vulnerability. If a service accepts connections from any device that presents a valid request, an attacker who compromises one device (or clones its configuration) can impersonate any device on the network.
Mutual TLS (mTLS) — also called two-way TLS — closes this gap. Mutual TLS authentication requires both parties to present X.509 certificates during the handshake. The service authenticates to the device and the device authenticates to the service, both using certificates issued by a trusted CA.
The mTLS Handshake for IoT
For an IoT device connecting to a backend service, the mTLS handshake proceeds as follows:
- ClientHello: The device initiates the TLS connection, advertising its supported cipher suites.
- ServerHello + Certificate: The server sends its TLS certificate. The device validates it against the CA certificate stored on the device at provisioning time.
- CertificateRequest: The server requests a client certificate from the device.
- Client Certificate: The device sends its X.509 certificate, containing its unique identity (typically the device serial number or hardware identifier in the Common Name or Subject Alternative Name fields).
- CertificateVerify: The device signs a hash of the handshake messages using its private key. The server uses the device’s public key (from the certificate) to verify this signature. This proves the device holds the private key corresponding to the certificate.
- Finished: Both sides derive session keys and confirm the handshake. All subsequent communication is encrypted.
The critical point is step 5. The server is not trusting the device because it knows a password. It is trusting the device because it can verify a signature made by a private key that was certified by the organization’s own CA. An attacker who does not have that private key cannot forge this signature — regardless of what other credentials they may have compromised.
IoT Transport Layer Considerations
Not every IoT device runs a full TLS stack. The transport choice determines how mTLS is applied:
MQTT over TLS (Port 8883): The dominant protocol for IoT telemetry. Standard TLS with mutual authentication — the MQTT broker is configured to require client certificates. Widely supported by AWS IoT Core, Azure IoT Hub, Google Cloud IoT Core, and open-source brokers like Mosquitto and EMQ X. The certificate-based authentication integrates directly into the broker’s access control policies, mapping certificate attributes to device permissions.
HTTPS/REST: Standard HTTP over TLS with tls.RequireAndVerifyClientCert (or equivalent in your server framework). The same certificate presented during the mTLS handshake can be extracted from the request context and used for authorization — mapping the device CN to allowed API endpoints, rate limits, or data scopes.
CoAP/DTLS: For constrained devices on lossy networks (IEEE 802.15.4, 6LoWPAN, NB-IoT), DTLS provides the datagram equivalent of TLS. The certificate structure is identical; the handshake runs over UDP and is tolerant of packet loss and reordering. The tinyDTLS library supports certificate-based authentication on microcontroller-class devices with as little as 10 KB RAM.
gRPC/HTTP2: For device-to-cloud streaming on capable hardware, gRPC over HTTP/2 with mTLS provides bidirectional streaming with certificate authentication. The server intercepts the certificate from the gRPC context per-call.
3. The PKI Architecture for IoT Certificate Management
Trust Hierarchy
A production IoT deployment requires a dedicated PKI hierarchy. Using your enterprise user PKI for device certificates conflates two distinct trust domains and creates policy management problems. The correct architecture is:
Root CA (offline, air-gapped)
│
├── Intermediate CA: IoT Devices
│ └── Device Certificates (serial-bound, short-lived)
│
└── Intermediate CA: Services
└── Service Certificates (mTLS server endpoints)
The Root CA is generated offline and never connects to any network. Its private key lives in a Hardware Security Module (HSM) or secure offline storage. The Root CA signs Intermediate CA certificates and nothing else.
Intermediate CAs are online — they receive certificate requests and issue signed certificates. Separating device and service intermediate CAs means that if the device CA is compromised, you can revoke it without affecting service certificates, and vice versa.
Certificate Profile for IoT Devices
IoT device certificates should encode specific attributes that support both authentication and authorization:
Subject:
CN = <device-serial-number> # Unique, hardware-bound identifier
O = <organization>
OU = <device-class> # e.g., "temperature-sensors", "actuators"
Subject Alternative Names:
URI: urn:device:<device-serial> # Machine-parseable device URI
DNS: <device-id>.devices.internal # Optional internal DNS resolution
Key Usage:
Digital Signature, Key Encipherment
Extended Key Usage:
TLS Web Client Authentication (1.3.6.1.5.5.7.3.2)
Validity:
24–72 hours for high-security deployments
90 days for operationally constrained environments
Basic Constraints:
CA: FALSE
The device serial number in the CN is the linkage between the cryptographic identity and the physical device inventory. Authorization logic on the service side extracts the CN from the validated certificate and looks it up in the device registry to determine what the device is allowed to do.
Key Storage on the Device
The security of the entire system depends on where the device’s private key is stored. Three tiers exist:
Software-only storage: The private key is a file on the device’s filesystem. Simplest to implement. Vulnerable to extraction if an attacker gains filesystem access. Acceptable for development environments; not acceptable for production deployments handling sensitive data.
TPM (Trusted Platform Module): The private key is generated inside the TPM and cannot be exported. The CPU can instruct the TPM to sign data, but the raw key bytes never leave the TPM boundary. TPM 2.0 is standard on modern industrial computers, gateways, and edge devices. Key generation and CSR signing go through the TPM PKCS#11 interface or the TSS stack.
Secure Element / Hardware Secure Module: Purpose-built cryptographic chips (Microchip ATECC608, NXP SE050, Infineon SLB97xx) with physically unclonable functions. Common in microcontroller-class IoT hardware. The private key is bound to the chip at manufacturing time or during provisioning and cannot be extracted through any software interface.
The choice of key storage determines what authentication claims you can make and what protocols are available. ACME Device Attestation with the device-attest-01 challenge, for example, requires a hardware security boundary — it only makes sense if the key is TPM-bound or Secure-Element-bound.
4. The IoT Certificate Lifecycle
Every certificate goes through six phases. Automating each phase is what separates a manageable PKI from a crisis waiting to happen.
Phase 1: Device Manufacturing / Provisioning
The device’s cryptographic identity should be established as early as possible in the supply chain — ideally at manufacturing time. For Secure Element-based devices, the manufacturer burns a unique key pair and an attestation certificate (attesting that this key was generated in this specific hardware) into the chip during production. This attestation certificate becomes the device’s birth certificate.
For devices without a pre-provisioned identity, the first secure interaction with your infrastructure is the provisioning step: the device generates a key pair (in hardware if possible), submits a CSR, and receives its first operational certificate after identity verification.
Phase 2: Certificate Enrollment
Enrollment is the process by which a device receives its first certificate from your CA. Two protocols dominate:
SCEP (Simple Certificate Enrollment Protocol, RFC 8894): The device presents a CSR and a shared challenge password. The CA validates the password and issues the certificate. SCEP is supported by virtually every IoT platform and MDM system. Its weakness is the shared password — it authenticates the enrollment request, but it does not prove which specific device is enrolling.
ACME (Automated Certificate Management Environment, RFC 8555): The device interacts with the CA using a standardized API. The CA issues a challenge; the device fulfills the challenge to prove its identity; the CA issues the certificate. For constrained IoT environments, ACME requires an HTTP stack, so it is primarily applicable to gateway-class devices and capable IoT hardware. For hardware-attestation use cases, the device-attest-01 extension allows the device to present manufacturer-signed attestation evidence rather than fulfilling a network challenge — binding the certificate to the specific physical hardware.
Phase 3: Certificate Distribution
For MDM-managed IoT gateways and edge devices, certificates are delivered via configuration profiles pushed from the MDM system. For embedded IoT devices without MDM integration, the device retrieves its certificate over a secure bootstrap channel — typically a factory-provisioned certificate that is valid only for the enrollment endpoint.
Phase 4: Operational Use
The device uses its certificate for mTLS authentication throughout its operational life. The service validates the certificate on every connection: checking the signature chain against the trusted CA, verifying the validity period, and optionally checking the revocation status via OCSP or CRL.
Phase 5: Renewal
Certificates should be renewed before they expire. For short-lived certificates (24-72 hours), renewal must be automated — no human can track and manually renew certificates at that cadence across a large fleet. The renewal process is identical to enrollment: the device generates a new CSR and requests a new certificate. If using ACME, the client handles this automatically according to its renewal policy (typically renewing at 2/3 of the certificate lifetime).
Phase 6: Revocation
When a device is decommissioned, lost, or compromised, its certificate must be revoked immediately. Revocation is communicated via two mechanisms:
CRL (Certificate Revocation List): The CA publishes a signed list of revoked certificate serial numbers. Clients download this list periodically and check it before trusting a certificate. CRLs work for environments where real-time revocation is not required. For more context, see our comparison of OCSP vs CRL for operational trade-offs.
OCSP (Online Certificate Status Protocol): The client queries the CA’s OCSP responder in real time before accepting a certificate. More timely than CRL but requires the OCSP responder to be reachable during every TLS handshake. For IoT devices on intermittent or air-gapped networks, OCSP stapling (where the server pre-fetches and caches its own OCSP response) is the practical solution.
The architectural pattern that eliminates most revocation complexity is short-lived certificates. If a certificate is valid for 24 hours, an attacker who steals it has a narrow window. Revocation becomes less critical because the certificate expires before most breach investigation cycles complete. This is the argument for short-lived certificates as a substitute for robust revocation infrastructure.
5. SCEP: The Legacy Standard and Its IoT Limits
SCEP has served the industry for over two decades, and its ubiquity makes it practically unavoidable in mixed IoT/enterprise deployments. Understanding its specific limitations in IoT contexts is essential for designing the right migration path.
What SCEP Does Well for IoT
- Universal device support: Every major MDM platform, network equipment vendor, and embedded OS includes SCEP support. Deploying SCEP requires no client-side changes.
- Low compute overhead: The protocol is lightweight. CSR submission and certificate retrieval are simple HTTP-based operations suitable for gateway-class IoT devices.
- MDM integration: MDMs like Intune, Jamf Pro, and VMware Workspace ONE deliver SCEP configuration profiles that automate enrollment without any device-side code changes.
A Cloud SCEP Gateway removes the operational burden of running Microsoft NDES on-premises while retaining SCEP compatibility with all existing MDM configurations. For a detailed walkthrough of how SCEP gateways distribute certificates to managed devices, see our SCEP gateway guide.
Where SCEP Fails at IoT Scale
Shared challenge password: The SCEP challenge password is the authorization mechanism. Any device that presents the correct password receives a certificate. This means:
- If the password leaks (via a compromised MDM configuration profile, a decompiled firmware image, or a network sniff), an attacker can enroll arbitrary devices.
- Static passwords must be rotated across all devices simultaneously — an operationally expensive operation.
- The password proves authorization, not identity. The CA does not know which specific device is enrolling.
No hardware binding: SCEP certificates are issued to whatever private key the device generates. If the key is stored in software, it can be exported. A cloned private key plus its certificate is a complete device impersonation that is invisible to the CA and the service.
No inventory verification: SCEP does not integrate natively with device inventories. A certificate can be issued for a device serial number that does not exist in your organization’s asset database. Your CA and your MDM operate in separate trust domains with no cryptographic linkage.
Certificate lifecycle opacity: SCEP has no built-in renewal signaling. Devices that miss their renewal window expire silently. At scale, tracking expiry across thousands of devices with varying renewal schedules requires external tooling.
6. ACME: The Automation Protocol for Modern IoT
The ACME protocol (RFC 8555) transformed public internet certificate management when Let’s Encrypt adopted it to issue billions of certificates automatically. The same protocol, running against a private CA, provides the same automation benefits for IoT fleet certificate management.
Why ACME Is Architecturally Superior for IoT
Standardized API: ACME defines a REST API that any ACME client can use to enroll, renew, and manage certificates. The ecosystem includes mature clients (Certbot, acme.sh, Lego, Caddy’s built-in ACME client) that run on Linux, Windows, macOS, and embedded platforms. An IoT gateway running Linux can use any of these clients unchanged.
Automated renewal: ACME clients monitor certificate expiry and initiate renewal automatically, typically at 2/3 of the certificate lifetime. For a 90-day certificate, renewal triggers at day 60. For a 24-hour certificate, renewal triggers at hour 16. This happens without operator intervention.
Per-device authorization: Instead of a shared password, ACME uses per-request challenges to prove that the entity requesting the certificate controls what it claims to control. For internal IoT deployments, the challenge type is selected by the CA based on the deployment’s trust model.
ACME External Account Binding (EAB): For enterprise IoT deployments, ACME EAB (RFC 8555, Section 7.3.4) provides a mechanism to bind device ACME accounts to pre-provisioned device inventory records. The CA issues an EAB credential (key ID + MAC key) per device during provisioning. When the device first contacts the ACME server, it presents this EAB credential, linking the ACME account to the specific device in your inventory system. BastionXP Private CA supports ACME EAB — see our ACME EAB guide for configuration details.
Setting Up BastionXP as a Private CA ACME Server for IoT
BastionXP Private CA supports the ACME protocol natively, which means any standard ACME client running on an IoT gateway or edge device can enroll against it without modification.
A BastionXP CA instance configured for ACME uses a trust authorities definition that specifies which challenge types are allowed and which domains or IP ranges are permitted to receive certificates. An example configuration for an IoT internal deployment:
{
"mode": "auth",
"email": "admin@example.com",
"gateway_domain": "ca.internal.example.com",
"trust_authorities": [
{
"type": "ACME",
"name": "iot-acme",
"tos": "https://www.example.com/tos",
"website": "https://www.example.com",
"dns_server": "dns.internal.example.com:1053",
"challenges": ["http-01", "dns-01"],
"policy": {
"x509": {
"dns": {
"allow": ["*.iot.internal.example.com"]
},
"ip": {
"allow": ["10.0.0.0/8", "172.16.0.0/12"]
}
}
}
}
]
}
The ACME directory for this provisioner is at:
https://ca.internal.example.com/acme/directory
An IoT gateway running certbot or acme.sh points to this directory URL and proceeds with standard ACME enrollment. The BastionXP CA issues certificates scoped to the permitted DNS names and IP ranges, with policy-enforced validity periods.
For the complete setup walkthrough, see Run Your Own Private CA and ACME Server for mTLS, IoT, and Internal Services.
ACME Challenge Types for IoT
http-01: The device proves it controls a DNS name by serving a specific token at http://<hostname>/.well-known/acme-challenge/<token>. Requires the device to be reachable on port 80 from the CA. Works for IoT gateways on private networks with internal DNS. Does not work for air-gapped devices or devices behind NAT without explicit port forwarding.
dns-01: The device proves it controls a DNS name by creating a TXT record at _acme-challenge.<hostname>. Requires DNS API access. Works for any device, regardless of network reachability. Ideal for air-gapped IoT deployments where the provisioning system (not the device itself) manages DNS.
device-attest-01: The hardware attestation challenge, defined in the IETF ACME Device Attestation draft. Instead of proving network control, the device presents manufacturer-signed attestation evidence: a cryptographic proof that the private key was generated inside a specific piece of hardware (Apple Secure Enclave, Android Keystore, or TPM). The CA validates this attestation against the manufacturer’s CA and optionally cross-references the attested hardware serial against the device inventory. BastionXP supports ACME device-attest-01 protocol. Learn more about ACME Device Attestation in our solutions page.
7. Hardware-Rooted Trust: TPM Attestation for IoT
The ACME device-attest-01 challenge and TPM-based key storage together form the strongest identity foundation available for IoT devices. This is where “certificate-based authentication” becomes “hardware-rooted identity.”
What TPM Attestation Proves
A TPM contains an Endorsement Key (EK) burned in at manufacturing time. The EK is certified by the TPM manufacturer (Infineon, STMicroelectronics, Nuvoton) with a chain leading to the manufacturer’s root CA. This EK is the TPM’s permanent identity — it cannot be extracted or cloned.
When a device generates an Attestation Key (AK) for use in ACME Device Attestation, the TPM creates a cryptographic binding: the AK is certified by the EK, and the EK certificate proves the AK is TPM-resident. The attestation statement sent to the CA contains:
- The AK public key (what the device wants in its certificate)
- The AK certificate signed by the EK
- The EK certificate signed by the TPM manufacturer
The CA validates this chain: TPM manufacturer root → EK certificate → AK certificate. This proves that:
- The AK was generated inside a genuine, unmodified TPM (not emulated software)
- The private key has never left and cannot leave the TPM
- The specific TPM can be identified by its EK
If the CA is integrated with the device inventory (as BastionXP Private CA integrates with MDMs such as Intune, Jamf, and FleetDM), it can perform a final check: the EK’s hardware serial number must match a device in the organization’s asset registry. This closes the loop entirely — the certificate is issued only to a physical device that the organization purchased and enrolled.
Practical TPM Integration Patterns
For Linux IoT gateways with TPM 2.0, the tpm2-tools package provides the primitives, and tpm2-pkcs11 exposes the TPM as a PKCS#11 token. OpenSSL can use this token for key generation and signing, which means standard certificate management tools work without modification:
# Generate a TPM-resident key and CSR using PKCS#11
openssl req -new \
-engine pkcs11 \
-keyform engine \
-key "pkcs11:object=iot-device-key;type=private" \
-out device.csr \
-subj "/CN=<device-serial>/O=Example Corp/OU=iot-sensors"
The resulting CSR contains the TPM-resident public key. The CA receives this CSR, validates the requesting device through the chosen enrollment protocol, and issues a certificate. The private key has never left the TPM.
For Microcontroller-class devices with Secure Elements (ATECC608, NXP SE050), the manufacturer provides a C SDK that exposes the same operations: key generation, CSR signing, and certificate storage. The device firmware calls these SDK functions rather than using a general-purpose crypto library.
8. Zero Trust Architecture for IoT Fleets
mTLS device certificates are the identity mechanism. Zero Trust is the policy layer built on top of that identity.
The Zero Trust IoT Model
In a traditional perimeter model, an IoT device that reaches the network is trusted. Everything inside the firewall can talk to everything else. This model fails for IoT because:
- IoT devices span multiple network segments, physical locations, and ownership domains
- IoT devices are often easier to compromise than user workstations
- An attacker who compromises one IoT device should not be able to pivot to core infrastructure
Zero Trust for IoT replaces implicit network trust with explicit, certificate-based, per-connection verification:
- Every device has a unique certificate. No device shares credentials with any other device.
- Every service validates the client certificate on every connection. Being on the “right network” grants nothing.
- Authorization is applied at the application layer using the certificate’s attributes (CN, OU, SANs) to determine what the device is permitted to do.
- Short certificate lifespans (hours to days) limit the blast radius of a compromised certificate.
Policy Enforcement with Certificate Attributes
The certificate’s Subject fields carry the device’s identity. The service extracts these on every authenticated connection and evaluates policy:
Device certificate CN: "sensor-12345"
Device certificate OU: "temperature-sensors"
Policy: devices with OU=temperature-sensors may POST to /api/v1/telemetry/temperature
and GET from /api/v1/config/temperature-sensors
and nothing else.
This policy is enforced at the API gateway or service mesh layer. The certificate is the authentication credential and the policy input simultaneously. No session tokens, no API keys, no password databases.
Continuous Posture Verification
Static policy (issued at enrollment time) enforces what a device was authorized to do. Continuous posture verification enforces what it is currently authorized to do.
The mechanism is certificate validity combined with revocation. If a device fails a health check (firmware integrity check, network behavior anomaly, physical tamper detection), its certificate is revoked, and it is immediately locked out of all services on the next connection attempt — no session timeout required.
Short-lived certificates provide a softer version of the same property: a device that fails a renewal check (because it cannot demonstrate continued integrity) simply does not receive a new certificate. Its current certificate expires within hours, and it loses access automatically.
BastionXP’s zero trust architecture extends this model with hardware-backed posture verification: TPM and Secure Enclave metadata are logged at enrollment, and the hardware serial number is cross-referenced against the device inventory on each certificate renewal.
9. Implementing mTLS in IoT Backend Services
Go (Golang)
Go’s crypto/tls package provides native mTLS support. For an IoT MQTT broker or REST API backend:
caCert, err := os.ReadFile("ca.crt")
caCertPool := x509.NewCertPool()
caCertPool.AppendCertsFromPEM(caCert)
tlsConfig := &tls.Config{
ClientCAs: caCertPool,
ClientAuth: tls.RequireAndVerifyClientCert,
MinVersion: tls.VersionTLS13,
}
server := &http.Server{
Addr: ":8443",
TLSConfig: tlsConfig,
Handler: mux,
}
The device’s certificate CN is extracted per-request:
func deviceIdentityMiddleware(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
if len(r.TLS.PeerCertificates) == 0 {
http.Error(w, "client certificate required", http.StatusUnauthorized)
return
}
deviceID := r.TLS.PeerCertificates[0].Subject.CommonName
ctx := context.WithValue(r.Context(), deviceIDKey, deviceID)
next.ServeHTTP(w, r.WithContext(ctx))
})
}
For a complete walkthrough of mTLS in Golang with BastionXP certificates, see the guides for Golang mTLS server and Golang mTLS client configurations.
Python
Python’s ssl module (backed by OpenSSL) and the Flask or FastAPI frameworks cover the two most common IoT backend patterns: lightweight REST APIs and async telemetry ingestion.
Flask (synchronous REST API)
import ssl
import flask
app = flask.Flask(__name__)
def get_device_id():
# Werkzeug exposes the underlying SSL socket via the WSGI environ
cert = flask.request.environ.get("SSL_CLIENT_CERT")
if not cert:
flask.abort(401, "Client certificate required")
# Extract CN from the subject dict provided by the ssl module
subject = dict(item for pair in cert["subject"] for item in pair)
return subject.get("commonName")
@app.route("/api/v1/telemetry", methods=["POST"])
def ingest_telemetry():
device_id = get_device_id()
payload = flask.request.get_json()
# ... process payload for device_id ...
return flask.jsonify({"device": device_id, "status": "accepted"}), 202
if __name__ == "__main__":
context = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER)
context.verify_mode = ssl.CERT_REQUIRED
context.load_verify_locations("ca.crt")
context.load_cert_chain("server.crt", "server.key")
context.minimum_version = ssl.TLSVersion.TLSv1_3
app.run(host="0.0.0.0", port=8443, ssl_context=context)
FastAPI (async, production-grade with Uvicorn)
For async IoT backends, Uvicorn handles TLS termination and exposes the client certificate through the ASGI connection scope:
import ssl
import uvicorn
from fastapi import FastAPI, Request, HTTPException
app = FastAPI()
def extract_device_id(request: Request) -> str:
# Uvicorn populates "ssl" in the ASGI scope with the client cert
ssl_object = request.scope.get("extensions", {}).get("tls", {})
cert = ssl_object.get("client_cert")
if not cert:
raise HTTPException(status_code=401, detail="Client certificate required")
subject = dict(item for pair in cert["subject"] for item in pair)
device_id = subject.get("commonName")
if not device_id:
raise HTTPException(status_code=403, detail="Certificate missing CN")
return device_id
@app.post("/api/v1/telemetry")
async def ingest_telemetry(request: Request):
device_id = extract_device_id(request)
payload = await request.json()
# ... async processing for device_id ...
return {"device": device_id, "status": "accepted"}
if __name__ == "__main__":
ssl_ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER)
ssl_ctx.verify_mode = ssl.CERT_REQUIRED
ssl_ctx.load_verify_locations("ca.crt")
ssl_ctx.load_cert_chain("server.crt", "server.key")
ssl_ctx.minimum_version = ssl.TLSVersion.TLSv1_3
uvicorn.run(app, host="0.0.0.0", port=8443, ssl=ssl_ctx)
Python mTLS client (IoT device side)
For gateway-class IoT devices written in Python, requests wraps the ssl module for outbound mTLS connections:
import requests
response = requests.post(
"https://iot-backend.internal.example.com:8443/api/v1/telemetry",
json={"temp": 22.4, "humidity": 61},
cert=("device.crt", "device.key"), # device's client certificate + private key
verify="ca.crt", # CA certificate to validate the server
)
response.raise_for_status()
The cert tuple is the device’s X.509 client certificate and its corresponding private key. The verify parameter pins the connection to the organization’s private CA — the device refuses to connect to any server whose certificate does not chain to this CA.
Nginx as a Reverse Proxy/API Gateway
For IoT backends behind Nginx, mTLS is enabled at the proxy layer, and the device identity is forwarded to upstream services via headers:
server {
listen 8443 ssl;
ssl_certificate /etc/ssl/server.crt;
ssl_certificate_key /etc/ssl/server.key;
ssl_client_certificate /etc/ssl/ca.crt;
ssl_verify_client on;
ssl_verify_depth 2;
ssl_protocols TLSv1.3;
# Forward device identity to upstream
proxy_set_header X-Device-ID $ssl_client_s_dn_cn;
proxy_set_header X-Device-Cert-Expiry $ssl_client_v_end;
location /api/v1/telemetry/ {
proxy_pass http://iot-backend:8080;
}
}
The $ssl_client_s_dn_cn variable contains the CN from the validated client certificate. For a detailed Nginx mTLS configuration walkthrough, see the Nginx mTLS server setup guide.
API Gateway mTLS for IoT
For organizations running a dedicated API gateway in front of IoT endpoints, mTLS can be terminated at the gateway layer while the device identity flows downstream as a verified header. This pattern is covered in detail in the API gateway mTLS security guide.
10. Certificate Rotation at Scale: The 10,000-Device Problem
A fleet of 10,000 IoT devices with 90-day certificates generates approximately 111 certificate renewals per day (10,000 / 90 ≈ 111). With 30-day certificates, this becomes 333 per day. With 24-hour certificates, it is 10,000 per day.
This is not a problem if renewal is automated. It is a catastrophic problem if renewal is manual.
The Automated Renewal Architecture
The renewal architecture has three components:
Client-side automation: Each IoT gateway or capable edge device runs an ACME client configured to renew at a fixed point in the certificate’s lifetime (typically 66%). The client wakes on a schedule, checks the current certificate’s expiry, and initiates ACME renewal if the threshold is crossed. For ACME clients like certbot, this is a standard --deploy-hook invocation:
certbot renew \
--server https://ca.internal.example.com/acme/directory \
--deploy-hook "/usr/local/bin/reload-iot-service.sh"
The deploy hook restarts the IoT service or signals it to reload its certificate, completing the rotation without downtime.
CA-side capacity: The private CA must handle the renewal load. BastionXP Private CA is designed for this — it processes ACME certificate requests at scale, with policy enforcement applied per-request. Rate limiting per device and per device class prevents a single misconfigured device from flooding the CA.
Monitoring and alerting: Even with automation, exceptions happen. A device that loses network connectivity during its renewal window will miss the renewal and eventually expire. Certificate lifecycle monitoring should track each device’s certificate expiry and alert when a device has not renewed within its expected window.
Zero-Downtime Certificate Rotation
Certificate rotation must not interrupt the device’s active connections. The pattern for zero-downtime rotation:
- The ACME client obtains the new certificate while the current certificate is still valid.
- The IoT service is signaled to reload (not restart). On reload, it reads the new certificate file.
- Existing TLS sessions continue using the old certificate until they terminate naturally.
- New sessions negotiate using the new certificate.
Most IoT backend frameworks support hot certificate reload via SIGHUP or a dedicated reload API. For services that do not, the deployment hook restarts the service with the new certificate after shifting traffic to another instance (for multi-instance deployments).
11. Operational Patterns: What Works at Different Fleet Sizes
Tier 1: Under 1,000 Devices
At this scale, the focus is on getting the architecture right rather than optimizing for throughput.
- A single BastionXP Private CA instance handles issuance and renewal for the fleet.
- ACME with
http-01ordns-01for gateway devices; SCEP via the BastionXP Cloud SCEP Gateway for legacy devices. - Certificate validity: 90 days with automated renewal at day 60.
- Monitoring: Simple expiry tracking query against the CA’s certificate database.
Tier 2: 1,000–100,000 Devices
- High-availability CA deployment (two CA instances with shared configuration, backed by a reliable database).
- Certificate validity reduced to 30 days to limit blast radius of compromise.
- ACME EAB enforced: each device has a pre-provisioned EAB credential that links its ACME account to the inventory record.
- MDM integration: BastionXP integrates with Intune, Jamf, and FleetDM for MDM-managed IoT gateways, delivering configuration profiles that configure the ACME client automatically.
- Monitoring: Per-device expiry tracking with automated alerting when a device has not renewed within 50% of its expected renewal window.
Tier 3: 100,000+ Devices
- CA infrastructure scaled horizontally, with regional ACME endpoints to minimize latency for geographically distributed fleets.
- Certificate validity: 24-48 hours, using short-lived certificates as the primary revocation mechanism.
- Hardware attestation (
device-attest-01or TPM-based enrollment) required for all new devices. SCEP retained only for legacy devices that cannot support ACME. - Device certificate issuance integrated into the manufacturing and provisioning pipeline: the device arrives from the factory with its first operational certificate already installed.
- Automated certificate inventory: the CA’s issued certificate list is the authoritative device registry, not a separate database.
12. The Architectural Blueprint
A production mTLS IoT deployment, at any scale, is built from seven definitive components. Each component has exactly one job.
1. Root CA (offline) Trust anchor. Generated offline. Private key in HSM. Signs Intermediate CA certificates. Never connected to a network. Validity: 20+ years.
2. Intermediate CA: IoT Devices (BastionXP Private CA) Issues device certificates. Online, reachable from ACME clients and SCEP clients. Configured with certificate policies: allowed DNS names, IP ranges, maximum validity periods, required EKUs. Validity: 5–10 years. BastionXP Private CA with ACME support serves this role — it handles the full certificate lifecycle from issuance through renewal.
3. Intermediate CA: Services Issues server certificates for IoT backend endpoints. Separate from the device CA to contain the blast radius of CA compromise. Certificates issued for internal DNS names that IoT devices trust.
4. ACME Gateway (BastionXP ACME Server)
The ACME directory endpoint that device ACME clients call for enrollment and renewal. BastionXP Private CA exposes the ACME directory at https://ca.internal.example.com/acme/directory. Policy enforcement (EAB required, allowed domains, rate limits) is applied at this layer.
5. SCEP Gateway (BastionXP Cloud SCEP Gateway) Handles enrollment for legacy IoT devices and MDM-managed devices that use SCEP profiles. Bridges SCEP requests to the BastionXP Private CA without exposing the CA directly. Dynamic SCEP eliminates static shared passwords. Replaces Microsoft NDES without requiring Windows Server infrastructure.
6. Device Inventory Integration The CA’s certificate issuance is gated on inventory membership. An ACME request from a device whose hardware serial does not appear in the inventory is rejected. BastionXP integrates with Intune, Jamf, and FleetDM for MDM-managed inventories. For custom IoT inventories, the CA policy enforces enrollment eligibility.
7. mTLS Enforcement at Service Endpoints Every IoT backend service — MQTT broker, REST API, gRPC service, internal service — requires client certificates issued by the IoT Device Intermediate CA. The service validates certificate chains, checks validity periods, optionally queries OCSP, and extracts the device CN for policy decisions. No service accepts unauthenticated connections from the device network segment.
The result is an IoT identity architecture where every connection is authenticated with a hardware-bound certificate issued by a CA you control, renewed automatically before expiry, revocable in under an hour, and enforced at every service boundary — without a shared password, hardcoded credential, or API key anywhere in the system. The operational burden is front-loaded: instrument the provisioning pipeline, deploy the CA, configure the ACME clients. After that, the system runs itself.
About BastionXP
BastionXP is a cloud-native private PKI CA and device identity management platform that eliminates passwords and shared secrets by issuing hardware-attested certificates to mobile devices and laptops. Secure access to your Wi-Fi, VPN, and SaaS applications in your enterprise network. Replace legacy SCEP with automated ACME Device Attestation. No shared secrets. Zero credential theft. Learn more about BastionXP →
