|
| 1 | +# Migrating from Azure IoT Hub to EMQX |
| 2 | + |
| 3 | +This guide provides a practical walkthrough for migrating IoT devices from Azure IoT Hub to EMQX. It covers two migration paths: |
| 4 | + |
| 5 | +1. **X.509 certificate authentication** - Devices using client certificates |
| 6 | +2. **SAS token authentication** - Devices using Shared Access Signature tokens with HTTP-based authentication |
| 7 | + |
| 8 | +## Migration at a Glance |
| 9 | + |
| 10 | +For devices using X.509 certificates, the migration is primarily a configuration change. Device certificates and private keys remain unchanged; only the broker endpoint and server CA certificate need updates. EMQX must be configured to trust the same CA that Azure trusts and to replicate Azure's identity mapping model where the certificate Common Name (CN) equals the deviceId. |
| 11 | + |
| 12 | + |
| 13 | +The migration process consists of three main phases: |
| 14 | + |
| 15 | +1. **Locate Your CA Certificate**. Find the CA certificate that signed your device certificates. |
| 16 | + |
| 17 | +2. **Configure EMQX for mTLS**. Set up an SSL/TLS listener on the EMQX broker, enable mandatory peer verification, and configure the listener to trust your CA and map certificate CN to deviceId. |
| 18 | + |
| 19 | +3. **Update Device Clients**. Update device code to connect to the EMQX endpoint and trust the EMQX server CA certificate. Devices can continue using Azure IoT SDK or use standard MQTT clients. |
| 20 | + |
| 21 | +The following table summarizes the parameter changes: |
| 22 | + |
| 23 | +| **Parameter** | **Azure IoT Hub (Example)** | **EMQX (Example)** | **Notes** | |
| 24 | +| ------------- | -------------------------- | ------------------ | --------- | |
| 25 | +| **Endpoint Hostname** | `my-hub.azure-devices.net` | `mqtt.example.com` | Update device client code | |
| 26 | +| **Device Certificate** | `device-001.cert.pem` | `device-001.cert.pem` | No change. Device continues using existing certificate | |
| 27 | +| **Device Private Key** | `device-001.key.pem` | `device-001.key.pem` | No change. Device continues using existing private key | |
| 28 | +| **Server Verification** (Device trusts Server) | Device trusts Azure's public CA | Device must trust `emqx-server-ca.pem` | Deploy EMQX server CA to devices | |
| 29 | +| **Client Verification** (Server trusts Device) | Azure trusts your CA (registered via CA upload or thumbprint) | EMQX `cacertfile` must be set to your CA | Same CA used in Azure | |
| 30 | +| **Identity Mapping** | Azure extracts `CN=deviceId` | Enable `mqtt.peer_cert_as_clientid = cn` | Preserves deviceId-based authorization | |
| 31 | + |
| 32 | +## Phase 1: Locate Your CA Certificate |
| 33 | + |
| 34 | +**What you need**: The CA certificate that signed your device certificates (in PEM format, e.g., `device-ca.pem`). |
| 35 | + |
| 36 | +Azure IoT Hub has two X.509 registration methods: |
| 37 | +- **CA registration**: You uploaded the CA to Azure IoT Hub |
| 38 | +- **Thumbprint registration**: You registered devices individually by certificate thumbprint |
| 39 | + |
| 40 | +**Both methods use the same certificate structure** - your device certificates were signed by a CA. For EMQX migration, you need that CA certificate. |
| 41 | + |
| 42 | +### Verify Certificate Requirements |
| 43 | + |
| 44 | +Azure requires that the certificate Subject Common Name (CN) matches the deviceId (or `deviceId/moduleId` for modules). Verify with: |
| 45 | + |
| 46 | +```bash |
| 47 | +openssl x509 -in device-001.cert.pem -noout -subject |
| 48 | +``` |
| 49 | + |
| 50 | +The output should show: |
| 51 | +``` |
| 52 | +subject=CN = device-001 |
| 53 | +``` |
| 54 | + |
| 55 | +This CN value will be used by EMQX to identify the device. |
| 56 | + |
| 57 | +### Confirm Device Credential Access |
| 58 | + |
| 59 | +Ensure each device retains secure access to: |
| 60 | +- Its leaf certificate (`device-001.cert.pem`) |
| 61 | +- Its private key (`device-001.key.pem`) |
| 62 | + |
| 63 | +No certificate re-provisioning is needed for this migration path. |
| 64 | + |
| 65 | +## Phase 2: Configure EMQX for Azure-Style mTLS |
| 66 | + |
| 67 | +Configure the EMQX broker to authenticate devices using the same certificates trusted by Azure IoT Hub. |
| 68 | + |
| 69 | +### Enable and Configure the mTLS Listener |
| 70 | + |
| 71 | +Configure EMQX to enable two-way SSL/TLS authentication (mTLS) on the SSL listener. For detailed information on SSL/TLS configuration, see [Enable SSL/TLS Connection](../network/emqx-mqtt-tls.md). |
| 72 | + |
| 73 | +Open the EMQX configuration file (`emqx.conf`) and configure the SSL/TLS listener, or use the Dashboard (**Management** -> **Listeners**): |
| 74 | + |
| 75 | +```hocon |
| 76 | +listeners.ssl.default { |
| 77 | + bind = "0.0.0.0:8883" |
| 78 | +
|
| 79 | + ssl_options { |
| 80 | + # Your EMQX server's certificate |
| 81 | + certfile = "etc/certs/server-cert.pem" |
| 82 | +
|
| 83 | + # Your EMQX server's private key |
| 84 | + keyfile = "etc/certs/server-key.pem" |
| 85 | +
|
| 86 | + # --- mTLS Configuration for Device Authentication --- |
| 87 | +
|
| 88 | + # The CA certificate that signed your device certificates |
| 89 | + cacertfile = "etc/certs/azure-device-ca.pem" |
| 90 | +
|
| 91 | + # Enable client certificate verification |
| 92 | + verify = verify_peer |
| 93 | +
|
| 94 | + # Reject clients that do not present a certificate |
| 95 | + fail_if_no_peer_cert = true |
| 96 | + } |
| 97 | +} |
| 98 | +``` |
| 99 | + |
| 100 | +::: tip |
| 101 | +Both Azure IoT Hub and EMQX use port 8883 as the default for MQTT over TLS/SSL, so no port changes are needed in device clients. |
| 102 | +::: |
| 103 | + |
| 104 | +**Key Configuration Parameters**: |
| 105 | +* `cacertfile`: Path to your CA certificate (or bundle of self-signed device certificates). EMQX will use this to verify device certificates. |
| 106 | +* `verify`: Must be set to `verify_peer` to enable mTLS. |
| 107 | +* `fail_if_no_peer_cert`: Must be set to `true` to enforce certificate requirement. |
| 108 | + |
| 109 | +### Replicate Azure's CN=deviceId Identity Mapping |
| 110 | + |
| 111 | +Azure IoT Hub extracts the certificate's Common Name and uses it as the deviceId for authorization. Replicate this in EMQX: |
| 112 | + |
| 113 | +```hocon |
| 114 | +mqtt.peer_cert_as_clientid = cn |
| 115 | +mqtt.peer_cert_as_username = cn |
| 116 | +``` |
| 117 | + |
| 118 | +This configuration ensures that: |
| 119 | +- The MQTT ClientID is automatically set to the certificate CN (deviceId) |
| 120 | +- The username is also set to the certificate CN |
| 121 | +- You can configure EMQX ACL rules using `${clientid}` or `${username}` to match the deviceId, replicating Azure's authorization model |
| 122 | + |
| 123 | +For devices using modules (`deviceId/moduleId` format), the CN contains both identifiers and can be used directly in EMQX ACLs. |
| 124 | + |
| 125 | +### Apply Configuration Changes |
| 126 | + |
| 127 | +After updating the configuration file, reload the configuration: |
| 128 | + |
| 129 | +```bash |
| 130 | +emqx ctl conf reload |
| 131 | +``` |
| 132 | + |
| 133 | +If you made changes via the Dashboard, click **Update** to apply them. The listener will restart automatically to apply the new settings. |
| 134 | + |
| 135 | +Verify the listener is enforcing mTLS: |
| 136 | + |
| 137 | +```bash |
| 138 | +openssl s_client -connect mqtt.example.com:8883 -showcerts |
| 139 | +``` |
| 140 | + |
| 141 | +The connection should fail without a client certificate. |
| 142 | + |
| 143 | +## Phase 3: Update Device Clients and Verify Migration |
| 144 | + |
| 145 | +The final phase is to update device client code to connect to EMQX instead of Azure IoT Hub. |
| 146 | + |
| 147 | +### Update Device Client Code |
| 148 | + |
| 149 | +The Azure IoT SDK for Python (and other languages) supports connecting to custom MQTT brokers through the `server_verification_cert` and custom `hostname` parameters. This allows for minimal code changes. |
| 150 | + |
| 151 | +**Python Example**: |
| 152 | + |
| 153 | +```python |
| 154 | +from azure.iot.device import IoTHubDeviceClient, X509 |
| 155 | + |
| 156 | +# Load device credentials |
| 157 | +x509 = X509( |
| 158 | + cert_file="certs/device-001.cert.pem", |
| 159 | + key_file="certs/device-001.key.pem" |
| 160 | +) |
| 161 | + |
| 162 | +# Create client pointing to EMQX |
| 163 | +client = IoTHubDeviceClient.create_from_x509_certificate( |
| 164 | + x509=x509, |
| 165 | + hostname="mqtt.example.com", # EMQX hostname instead of Azure |
| 166 | + device_id="device-001", |
| 167 | + server_verification_cert="certs/emqx-server-ca.pem" # EMQX server CA |
| 168 | +) |
| 169 | + |
| 170 | +# Connect and use as before |
| 171 | +client.connect() |
| 172 | +client.send_message("Hello from migrated device") |
| 173 | +``` |
| 174 | + |
| 175 | +**C# Example**: |
| 176 | + |
| 177 | +```csharp |
| 178 | +var auth = new DeviceAuthenticationWithX509Certificate( |
| 179 | + deviceId: "device-001", |
| 180 | + certificate: new X509Certificate2("device-001.pfx", "password") |
| 181 | +); |
| 182 | + |
| 183 | +var options = new ClientOptions |
| 184 | +{ |
| 185 | + // Point to EMQX instead of Azure IoT Hub |
| 186 | + ModelId = "", |
| 187 | + CertificateValidationCallback = (sender, certificate, chain, errors) => |
| 188 | + { |
| 189 | + // Validate against EMQX CA |
| 190 | + return ValidateServerCertificate(certificate, "emqx-server-ca.pem"); |
| 191 | + } |
| 192 | +}; |
| 193 | + |
| 194 | +var client = new DeviceClient( |
| 195 | + hostname: "mqtt.example.com", // EMQX hostname |
| 196 | + authenticationMethod: auth, |
| 197 | + transportType: TransportType.Mqtt_Tcp_Only, |
| 198 | + options: options |
| 199 | +); |
| 200 | + |
| 201 | +await client.OpenAsync(); |
| 202 | +``` |
| 203 | + |
| 204 | +::: tip |
| 205 | +Using the Azure IoT SDK preserves your existing application code structure, requiring only configuration changes. This is the simplest migration path for devices already using X.509 authentication. |
| 206 | +::: |
| 207 | + |
| 208 | +### Device-Side Parameter Summary |
| 209 | + |
| 210 | +These are the parameter changes needed: |
| 211 | + |
| 212 | +1. **Endpoint/Hostname**: |
| 213 | + - Azure: `my-hub.azure-devices.net` |
| 214 | + - EMQX: `mqtt.example.com` |
| 215 | + |
| 216 | +2. **Server CA Certificate**: |
| 217 | + - Azure: Uses system trust store or Azure CA |
| 218 | + - EMQX: Must explicitly provide `emqx-server-ca.pem` |
| 219 | + |
| 220 | +3. **Device Credentials** (no changes): |
| 221 | + - Certificate: Keep existing device certificate |
| 222 | + - Private key: Keep existing private key |
| 223 | + |
| 224 | +4. **ClientId**: Set to deviceId (matching certificate CN) |
| 225 | + |
| 226 | +### Validation Checklist |
| 227 | + |
| 228 | +1. Device appears in EMQX Dashboard with `clientid = deviceId` |
| 229 | +2. TLS handshake succeeds and device certificate is verified |
| 230 | +3. Device can publish to authorized topics |
| 231 | +4. Device can subscribe to authorized topics |
| 232 | +5. No authentication errors in EMQX logs |
| 233 | + |
| 234 | +## Happy Path Variations |
| 235 | + |
| 236 | +### CA-Signed Fleet |
| 237 | + |
| 238 | +- Upload the CA certificate to EMQX |
| 239 | +- All devices signed by this CA are automatically trusted |
| 240 | +- Simplified certificate lifecycle management |
| 241 | +- Easy to add new devices without EMQX reconfiguration |
| 242 | + |
| 243 | +### Modules (deviceId/moduleId) |
| 244 | + |
| 245 | +- Certificates with CN in format `deviceId/moduleId` |
| 246 | +- EMQX can use the full CN for authorization |
| 247 | +- Reflect the same structure in ACL rules |
| 248 | + |
| 249 | +## Alternative: SAS Token Authentication with HTTP Authenticator |
| 250 | + |
| 251 | +Devices using Azure Shared Access Signature (SAS) tokens can continue using them with EMQX by implementing an **HTTP Authentication** service. For detailed information on HTTP authentication, see [Use HTTP Service](../access-control/authn/http.md). |
| 252 | + |
| 253 | +### How SAS Token Authentication Works |
| 254 | + |
| 255 | +Azure SAS tokens are passed in the MQTT password field with a specific format: |
| 256 | +- **Username**: `{iothubhostname}/{deviceId}/?api-version=2021-04-12` |
| 257 | +- **Password**: `SharedAccessSignature sr={resource}&sig={signature}&se={expiry}` |
| 258 | + |
| 259 | +### Implement HTTP Authentication for SAS Tokens |
| 260 | + |
| 261 | +1. **Create an HTTP authentication service** that: |
| 262 | + - Receives the username and password from EMQX |
| 263 | + - Extracts the deviceId from the username |
| 264 | + - Parses the SAS token from the password field |
| 265 | + - Validates the token signature using the device's symmetric key |
| 266 | + - Checks the token expiry (`se` field) |
| 267 | + - Returns `{"result": "allow"}` or `{"result": "deny"}` |
| 268 | + |
| 269 | +2. **Configure EMQX HTTP Authenticator** via Dashboard or configuration file: |
| 270 | + |
| 271 | +```hocon |
| 272 | +authentication = [ |
| 273 | + { |
| 274 | + mechanism = password_based |
| 275 | + backend = http |
| 276 | + method = post |
| 277 | + url = "http://your-auth-service:8080/auth" |
| 278 | + body { |
| 279 | + username = "${username}" |
| 280 | + password = "${password}" |
| 281 | + clientid = "${clientid}" |
| 282 | + } |
| 283 | + headers { |
| 284 | + "Content-Type" = "application/json" |
| 285 | + } |
| 286 | + } |
| 287 | +] |
| 288 | +``` |
| 289 | + |
| 290 | +3. **Provision Device Credentials**: Export device identities and symmetric keys from Azure IoT Hub identity registry and provision them in your authentication service's database. |
| 291 | + |
| 292 | +### Example HTTP Authentication Service Response |
| 293 | + |
| 294 | +```json |
| 295 | +{ |
| 296 | + "result": "allow", |
| 297 | + "is_superuser": false, |
| 298 | + "client_attrs": { |
| 299 | + "device_id": "device-001" |
| 300 | + } |
| 301 | +} |
| 302 | +``` |
| 303 | + |
| 304 | +::: tip |
| 305 | +This approach allows SAS token-based devices to migrate without firmware changes. However, for long-term portability and security, migrating to X.509 certificate authentication is recommended. |
| 306 | +::: |
| 307 | + |
| 308 | +## Conclusion |
| 309 | + |
| 310 | +Migrating devices from Azure IoT Hub to EMQX offers flexible paths depending on your authentication method: |
| 311 | + |
| 312 | +**For X.509 certificate-based devices**: The migration is straightforward when using your own Certificate Authority. Device certificates and private keys remain unchanged, requiring only endpoint updates and server CA deployment. Follow the three phases: locating your CA certificate, configuring EMQX for mTLS with CN-based identity mapping, and updating device clients to successfully migrate while maintaining the same security model. |
| 313 | + |
| 314 | +**For SAS token-based devices**: Devices can continue using SAS tokens by implementing an HTTP authentication service that validates token signatures and expiry. This allows migration without firmware changes, though transitioning to X.509 certificates is recommended for long-term portability. |
| 315 | + |
| 316 | +::: tip |
| 317 | +Focus your initial migration on X.509 CA-signed devices to achieve quick wins. For SAS token devices, evaluate whether to implement HTTP authentication for immediate migration or refactor to X.509 certificates for better long-term maintainability. |
| 318 | +::: |
0 commit comments