|
| 1 | +# Migrating from AWS IoT Core to EMQX |
| 2 | + |
| 3 | +This guide provides a comprehensive walkthrough for migrating IoT devices from AWS IoT Core to EMQX. It outlines the process for reconfiguring devices and the EMQX broker to ensure a seamless transition for an entire device fleet. |
| 4 | + |
| 5 | +The guide focuses on the most common and robust authentication method supported by both platforms: X.509 Client Certificate (mTLS) Authentication. This guide assumes you are using your own custom Certificate Authority (CA) registered with AWS IoT Core to sign device certificates. If you are using AWS-issued certificates ("one-click" method), you will need to transition to using your own CA, as AWS's proprietary intermediate CAs are not accessible for third-party broker configuration. |
| 6 | + |
| 7 | +## Migration at a Glance: The "Happy Path" |
| 8 | + |
| 9 | +For devices using X.509 client certificates (mTLS) signed by your own CA with AWS IoT Core, the migration to EMQX is straightforward. Standard-compliant clients, including the official AWS IoT Device SDKs, can connect to EMQX with minimal changes to the client-side code—only the endpoint and server CA certificate need to be updated. Your existing device certificates and private keys remain valid. |
| 10 | + |
| 11 | +The migration process consists of three main phases: |
| 12 | + |
| 13 | +1. **Prepare Your CA Certificate**. Locate your custom CA certificate that was registered with AWS IoT Core and is currently used to sign your device certificates. |
| 14 | + |
| 15 | +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. |
| 16 | + |
| 17 | +3. **Update Device Clients**. Update device client code with the new EMQX endpoint address and the EMQX server's CA certificate for server verification. |
| 18 | + |
| 19 | +The following table summarizes the parameter changes required at a high level. |
| 20 | + |
| 21 | +| **Parameter** | **AWS IoT Core (Example)** | **EMQX (Example)** | **Notes** | |
| 22 | +| ------------- | -------------------------- | ------------------ | --------- | |
| 23 | +| **Endpoint Hostname** | `agwba84cbf2pn-ats.iot.eu-west-1.amazonaws.com` | `mqtt.example.com` | Update device client code/firmware | |
| 24 | +| **Device Certificate** | `device-001.cert.pem` | `device-001.cert.pem` | No change. Device continues using its existing certificate signed by your CA. | |
| 25 | +| **Device Private Key** | `device-001.key.pem` | `device-001.key.pem` | No change. Device continues using its existing private key. | |
| 26 | +| **Server Verification** (Device trusts Server) | Device client uses `AmazonRootCA1.pem` | Device client must be updated to use `emqx-server-ca.pem` | The client must trust the CA that issued the EMQX server's certificate. | |
| 27 | +| **Client Verification** (Server trusts Device) | AWS IoT Core trusts your registered CA | EMQX listener's `cacertfile` must be set to `your-ca.pem` | EMQX must be configured to trust the same CA you registered with AWS IoT Core. |
| 28 | + |
| 29 | +## Phase 1: Prepare Your CA Certificate |
| 30 | + |
| 31 | +This guide assumes you are using your own custom Certificate Authority (CA) that was registered with AWS IoT Core using the "Bring Your Own CA" (BYOCA) feature. Your device certificates are signed by this CA, not by AWS's proprietary intermediate CAs. |
| 32 | + |
| 33 | +**Action**: Locate your CA certificate file (e.g., `my-company-ca.pem`). This is the same CA certificate that you registered with AWS IoT Core and used to sign your device certificates. |
| 34 | + |
| 35 | +You can verify which CA signed your device certificate by inspecting it: |
| 36 | + |
| 37 | +```bash |
| 38 | +openssl x509 -in device-001.cert.pem -text -noout | grep "Issuer" |
| 39 | +``` |
| 40 | + |
| 41 | +The issuer should match your organization's CA, not AWS intermediate CAs. |
| 42 | + |
| 43 | +::: tip |
| 44 | +**If you are using AWS-issued certificates**: AWS IoT Core's "one-click" certificate generation uses proprietary intermediate CAs that are not accessible to customers. If your devices use AWS-issued certificates, you will need to create your own CA and re-issue certificates to your devices before migrating to EMQX. This is beyond the scope of this guide, but you can use standard tools like OpenSSL or a PKI solution to create a CA and issue device certificates. |
| 45 | +::: |
| 46 | + |
| 47 | +## Phase 2: Configure EMQX for mTLS Authentication |
| 48 | + |
| 49 | +With your CA certificate located, the next step is to configure the EMQX broker to accept and authenticate devices using certificates signed by your CA. |
| 50 | + |
| 51 | +### Enable and Configure the mTLS Listener |
| 52 | + |
| 53 | +The core of the migration is enabling two-way SSL/TLS authentication (mTLS) on an EMQX listener. This configuration instructs EMQX to demand a certificate from the connecting client and verify its authenticity against your CA. |
| 54 | + |
| 55 | +**Action**: Open the EMQX configuration file (e.g., `emqx.conf`) and configure the SSL/TLS listener: |
| 56 | + |
| 57 | +```hocon |
| 58 | +listeners.ssl.default { |
| 59 | + bind = "0.0.0.0:8883" |
| 60 | +
|
| 61 | + ssl_options { |
| 62 | + # Your EMQX server's certificate |
| 63 | + certfile = "etc/certs/server-cert.pem" |
| 64 | +
|
| 65 | + # Your EMQX server's private key |
| 66 | + keyfile = "etc/certs/server-key.pem" |
| 67 | +
|
| 68 | + # --- mTLS Configuration for Device Authentication --- |
| 69 | +
|
| 70 | + # This is YOUR CA certificate (from Phase 1) |
| 71 | + # The same CA that was registered with AWS IoT Core |
| 72 | + cacertfile = "etc/certs/my-company-ca.pem" |
| 73 | +
|
| 74 | + # Enable client certificate verification |
| 75 | + verify = verify_peer |
| 76 | +
|
| 77 | + # Reject clients that do not present a certificate |
| 78 | + fail_if_no_peer_cert = true |
| 79 | + } |
| 80 | +} |
| 81 | +``` |
| 82 | + |
| 83 | +::: tip |
| 84 | +Both AWS IoT Core and EMQX use port 8883 as the default for MQTT over TLS/SSL, so no port changes are needed in your device clients. |
| 85 | +::: |
| 86 | + |
| 87 | +**Key Configuration Parameters**: |
| 88 | +* `cacertfile`: Path to your CA certificate file that you registered with AWS IoT Core. This allows EMQX to verify that connecting device certificates are authentic. |
| 89 | +* `verify`: Must be set to `verify_peer` to enable mTLS. |
| 90 | +* `fail_if_no_peer_cert`: Must be set to `true` to reject connections without a client certificate, enforcing mTLS. |
| 91 | +* `certfile` and `keyfile`: Your EMQX server's own certificate and private key. Clients will verify this certificate to ensure they're connecting to the correct broker. |
| 92 | + |
| 93 | +### (Optional) Map Certificate CN to ClientID or Username |
| 94 | + |
| 95 | +In many AWS IoT Core implementations, authorization policies rely on variables populated from the certificate, such as using the certificate's Common Name (CN) as the `iot:ClientId`. EMQX can replicate this behavior seamlessly, allowing for easier migration of authorization rules. |
| 96 | + |
| 97 | +**Action**: To automatically populate the MQTT ClientID or Username from the device certificate, add the following to your `emqx.conf`: |
| 98 | + |
| 99 | +```hocon |
| 100 | +# To use the certificate Common Name (CN) as the ClientID |
| 101 | +mqtt.peer_cert_as_clientid = cn |
| 102 | +
|
| 103 | +# To use the certificate Common Name (CN) as the Username |
| 104 | +mqtt.peer_cert_as_username = cn |
| 105 | +``` |
| 106 | + |
| 107 | +This configuration instructs EMQX to extract the Common Name (or other fields like `dn` for Distinguished Name) from the peer certificate during the TLS handshake and use it as the ClientID or Username for the MQTT session. This ensures that existing authorization logic (e.g., ACLs based on `${clientid}` or `${username}`) will continue to function after migration. |
| 108 | + |
| 109 | +For example, if your device certificates have CN=device-001, enabling `mqtt.peer_cert_as_clientid = cn` will automatically set the MQTT client ID to "device-001" during connection. |
| 110 | + |
| 111 | +## Phase 3: Update Device Clients and Verify Migration |
| 112 | + |
| 113 | +The final phase is to update device client code to point to the new EMQX broker endpoint. This process is demonstrated using the official [AWS IoT Device SDK for Python v2](https://github.com/aws/aws-iot-device-sdk-python-v2). |
| 114 | + |
| 115 | +AWS IoT SDKs are not locked into the AWS platform; they function as standard-compliant MQTT-over-TLS clients. This means existing application code built on these SDKs can be preserved, requiring changes only to the connection endpoint and server CA certificate parameters. |
| 116 | + |
| 117 | +### Client-Side Code Modifications (Python Example) |
| 118 | + |
| 119 | +Based on the `mqtt5_client_builder` module from the `aws-iot-device-sdk-python-v2`, you need to update the connection parameters to migrate from AWS IoT Core to EMQX: |
| 120 | + |
| 121 | +1. **Update the Endpoint**: |
| 122 | + * AWS: `endpoint="agwba84cbf2pn-ats.iot.eu-west-1.amazonaws.com"` |
| 123 | + * EMQX: `endpoint="mqtt.example.com"` (Your EMQX broker's hostname/FQDN) |
| 124 | + |
| 125 | +2. **Update the Server CA Certificate** (`ca_filepath`): |
| 126 | + * This is how the device verifies the EMQX server's identity. |
| 127 | + * AWS: Often omitted (defaults to system trust store) or `ca_filepath="root-CA.crt"` (Amazon Root CA 1) |
| 128 | + * EMQX: `ca_filepath="emqx-server-ca.pem"` (The CA that issued your EMQX server certificate) |
| 129 | + |
| 130 | +3. **Device Certificates Remain the Same**: |
| 131 | + * **Device certificate** (`cert_filepath`): No change needed. Devices continue using their existing certificates signed by your CA. |
| 132 | + * **Device private key** (`pri_key_filepath`): No change needed. Devices continue using their existing private keys. |
| 133 | + |
| 134 | +### Full Example: Connecting the AWS SDK to EMQX |
| 135 | + |
| 136 | +The following example demonstrates how to connect to EMQX using the AWS IoT Device SDK for Python v2. The `samples/mqtt/mqtt5_x509.py` sample script can be used with minimal modifications. |
| 137 | + |
| 138 | +**AWS IoT Core version** (before migration): |
| 139 | +```bash |
| 140 | +python3 mqtt5_x509.py \ |
| 141 | + --endpoint agwba84cbf2pn-ats.iot.eu-west-1.amazonaws.com \ |
| 142 | + --cert device-001.cert.pem \ |
| 143 | + --key device-001.key.pem \ |
| 144 | + --client_id basicPubSub \ |
| 145 | + --topic sdk/test/python \ |
| 146 | + --count 10 |
| 147 | +``` |
| 148 | + |
| 149 | +**EMQX version** (after migration): |
| 150 | +```bash |
| 151 | +python3 mqtt5_x509.py \ |
| 152 | + --endpoint mqtt.example.com \ |
| 153 | + --cert device-001.cert.pem \ |
| 154 | + --key device-001.key.pem \ |
| 155 | + --client_id basicPubSub \ |
| 156 | + --topic sdk/test/python \ |
| 157 | + --count 10 |
| 158 | +``` |
| 159 | + |
| 160 | +Note that the certificate and key parameters remain unchanged - only the endpoint changes. |
| 161 | + |
| 162 | +If you need to explicitly specify the server CA certificate (when not using system trust store), you can modify the SDK sample to add the `ca_filepath` parameter: |
| 163 | + |
| 164 | +```python |
| 165 | +# In mqtt5_x509.py, locate the mqtt5_client_builder.mtls_from_path() call |
| 166 | +# and add the ca_filepath parameter: |
| 167 | + |
| 168 | +client = mqtt5_client_builder.mtls_from_path( |
| 169 | + endpoint=args.input_endpoint, |
| 170 | + cert_filepath=args.input_cert, |
| 171 | + pri_key_filepath=args.input_key, |
| 172 | + ca_filepath="emqx-server-ca.pem", # Add this line |
| 173 | + on_publish_received=on_publish_received, |
| 174 | + on_lifecycle_stopped=on_lifecycle_stopped, |
| 175 | + on_lifecycle_attempting_connect=on_lifecycle_attempting_connect, |
| 176 | + on_lifecycle_connection_success=on_lifecycle_connection_success, |
| 177 | + on_lifecycle_connection_failure=on_lifecycle_connection_failure, |
| 178 | + on_lifecycle_disconnection=on_lifecycle_disconnection, |
| 179 | + client_id=args.input_clientId |
| 180 | +) |
| 181 | +``` |
| 182 | + |
| 183 | +**Key Changes Summary**: |
| 184 | +- **Endpoint**: Changed from AWS IoT Core endpoint to your EMQX broker hostname |
| 185 | +- **Server CA**: Optionally specify the CA that signed your EMQX server certificate |
| 186 | +- **Device Certificates**: No changes - devices continue using existing certificates and private keys |
| 187 | +- **Application logic**: No changes required - publish, subscribe, and message handling code remains identical |
| 188 | + |
| 189 | +Running this updated command will verify a successful connection, subscribe, and publish, confirming that the device migration is complete. |
| 190 | + |
| 191 | +## Advanced Migration Scenarios |
| 192 | + |
| 193 | +The same migration approach applies to more advanced connection scenarios. |
| 194 | + |
| 195 | +### Migrating Devices Using PKCS11 (HSMs) |
| 196 | + |
| 197 | +For devices that store private keys in a Hardware Security Module (HSM) for enhanced security, the migration process is straightforward. The private keys remain in the HSM, and the device certificates remain valid as long as they were signed by your custom CA. |
| 198 | + |
| 199 | +**Client-Side Code Modification**: |
| 200 | + |
| 201 | +The EMQX server-side configuration (Phase 2) remains the same. On the client side, use the `mtls_with_pkcs11` builder with updated endpoint: |
| 202 | + |
| 203 | +```python |
| 204 | +client = mqtt5_client_builder.mtls_with_pkcs11( |
| 205 | + # CHANGED: Your EMQX broker's hostname |
| 206 | + endpoint="mqtt.example.com", |
| 207 | + |
| 208 | + # CHANGED: Point to your EMQX server's CA |
| 209 | + ca_filepath="emqx-server-ca.pem", |
| 210 | + |
| 211 | + # Device certificate (no change - same cert signed by your CA) |
| 212 | + cert_filepath="device-001.cert.pem", |
| 213 | + |
| 214 | + # HSM Configuration (no changes) |
| 215 | + pkcs11_lib="/path/to/pkcs11.so", |
| 216 | + user_pin="YOUR-HSM-PIN", |
| 217 | + slot_id=pkcs11_slot_id, |
| 218 | + token_label="YOUR-TOKEN-LABEL", |
| 219 | + private_key_label="device-001-key", |
| 220 | + |
| 221 | + on_publish_received=on_publish_received, |
| 222 | + # ... other callbacks ... |
| 223 | + client_id="device-001" |
| 224 | +) |
| 225 | +``` |
| 226 | + |
| 227 | +### Migrating Devices Connecting via an HTTP Proxy |
| 228 | + |
| 229 | +For devices in restricted networks that must connect via an HTTP Proxy, the migration process remains the same as the standard path. The mTLS connection is tunneled through an HTTP CONNECT request. |
| 230 | + |
| 231 | +The EMQX server-side configuration (Phase 2) is **exactly the same**. The proxy is transparent to the EMQX listener, which only sees the incoming mTLS connection. |
| 232 | + |
| 233 | +The client SDK configuration must include the proxy settings in addition to the updated endpoint. |
| 234 | + |
| 235 | +**Client-Side Code Modification (Python Example)**: |
| 236 | + |
| 237 | +```python |
| 238 | +from awscrt import http |
| 239 | + |
| 240 | +# 1. Configure the HTTP Proxy |
| 241 | +http_proxy_options = http.HttpProxyOptions( |
| 242 | + host_name="my-proxy.my-network.com", |
| 243 | + port=8888 |
| 244 | +) |
| 245 | + |
| 246 | +# 2. Create client with proxy options |
| 247 | +client = mqtt5_client_builder.mtls_from_path( |
| 248 | + # CHANGED: Your EMQX broker's hostname |
| 249 | + endpoint="mqtt.example.com", |
| 250 | + |
| 251 | + # CHANGED: Point to your EMQX server's CA |
| 252 | + ca_filepath="emqx-server-ca.pem", |
| 253 | + |
| 254 | + # Device credentials (no changes - same certs signed by your CA) |
| 255 | + cert_filepath="device-001.cert.pem", |
| 256 | + pri_key_filepath="device-001.key.pem", |
| 257 | + |
| 258 | + # Add the proxy configuration |
| 259 | + http_proxy_options=http_proxy_options, |
| 260 | + |
| 261 | + on_publish_received=on_publish_received, |
| 262 | + # ... other callbacks ... |
| 263 | + client_id="device-001" |
| 264 | +) |
| 265 | +``` |
| 266 | + |
| 267 | +## Conclusion |
| 268 | + |
| 269 | +Migrating mTLS-based devices from AWS IoT Core to EMQX is straightforward when using your own custom Certificate Authority. The process is primarily a configuration change rather than a re-provisioning effort. |
| 270 | + |
| 271 | +By following the three phases outlined in this guide: |
| 272 | +1. Locating your custom CA certificate |
| 273 | +2. Configuring the EMQX broker for mTLS authentication with your CA |
| 274 | +3. Updating device client endpoints |
| 275 | + |
| 276 | +Your device fleet can be successfully migrated to EMQX while maintaining the same robust mTLS authentication. The migration preserves existing device certificates, private keys, and application logic in AWS IoT Device SDKs, requiring only minimal connection parameter updates. Organizations can efficiently transition their IoT infrastructure to EMQX with minimal disruption while maintaining security best practices. |
| 277 | + |
| 278 | +::: tip |
| 279 | +If your devices are currently using AWS-issued certificates (one-click method), you will need to establish your own CA infrastructure and re-provision device certificates before migration. This is a prerequisite for moving away from AWS's proprietary certificate chain. |
| 280 | +::: |
0 commit comments