Test connectivity to Azure IoT MQ Preview with MQTT clients
Important
Azure IoT Operations Preview – enabled by Azure Arc is currently in PREVIEW. You shouldn't use this preview software in production environments.
See the Supplemental Terms of Use for Microsoft Azure Previews for legal terms that apply to Azure features that are in beta, preview, or otherwise not yet released into general availability.
This article shows different ways to test connectivity to Azure IoT MQ Preview with MQTT clients in a nonproduction environment.
By default, Azure IoT MQ Preview:
Deploys a TLS-enabled listener on port 8883 with ClusterIp as the service type. ClusterIp means that the broker is accessible only from within the Kubernetes cluster. To access the broker from outside the cluster, you must configure a service of type LoadBalancer or NodePort.
Accepts Kubernetes service accounts for authentication for connections from within the cluster. To connect from outside the cluster, you must configure a different authentication method.
Caution
For production scenarios, you should use TLS and service accounts authentication to secure your IoT solution. For more information, see:
- Configure TLS with automatic certificate management to secure MQTT communication in Azure IoT MQ Preview
- Configure authentication in Azure IoT MQ Preview
- Expose Kubernetes services to external devices using port forwarding or a virtual switch with Azure Kubernetes Services Edge Essentials.
Before you begin, install or deploy IoT Operations. Use the following options to test connectivity to IoT MQ with MQTT clients in a nonproduction environment.
Connect from a pod within the cluster with default configuration
The first option is to connect from within the cluster. This option uses the default configuration and requires no extra updates. The following examples show how to connect from within the cluster using plain Alpine Linux and a commonly used MQTT client, using the service account and default root CA cert.
Create a file named
client.yaml
with the following configuration:apiVersion: v1 kind: Pod metadata: name: mqtt-client # Namespace must match IoT MQ BrokerListener's namespace # Otherwise use the long hostname: aio-mq-dmqtt-frontend.azure-iot-operations.svc.cluster.local namespace: azure-iot-operations spec: # Use the "mqtt-client" service account which comes with default deployment # Otherwise create it with `kubectl create serviceaccount mqtt-client -n azure-iot-operations` serviceAccountName: mqtt-client containers: # Mosquitto and mqttui on Alpine - image: alpine name: mqtt-client command: ["sh", "-c"] args: ["apk add mosquitto-clients mqttui && sleep infinity"] volumeMounts: - name: mq-sat mountPath: /var/run/secrets/tokens - name: trust-bundle mountPath: /var/run/certs volumes: - name: mq-sat projected: sources: - serviceAccountToken: path: mq-sat audience: aio-mq # Must match audience in BrokerAuthentication expirationSeconds: 86400 - name: trust-bundle configMap: name: aio-ca-trust-bundle-test-only # Default root CA cert
Use
kubectl apply -f client.yaml
to deploy the configuration. It should only take a few seconds to start.Once the pod is running, use
kubectl exec
to run commands inside the pod.For example, to publish a message to the broker, open a shell inside the pod:
kubectl exec --stdin --tty mqtt-client --namespace azure-iot-operations -- sh
Inside the pod's shell, run the following command to publish a message to the broker:
mosquitto_pub --host aio-mq-dmqtt-frontend --port 8883 --message "hello" --topic "world" --username '$sat' --pw $(cat /var/run/secrets/tokens/mq-sat) --debug --cafile /var/run/certs/ca.crt
The output should look similar to the following:
Client (null) sending CONNECT Client (null) received CONNACK (0) Client (null) sending PUBLISH (d0, q0, r0, m1, 'world', ... (5 bytes)) Client (null) sending DISCONNECT
The mosquitto client uses the service account token mounted at
/var/run/secrets/tokens/mq-sat
to authenticate with the broker. The token is valid for 24 hours. The client also uses the default root CA cert mounted at/var/run/certs/ca.crt
to verify the broker's TLS certificate chain.To subscribe to the topic, run the following command:
mosquitto_sub --host aio-mq-dmqtt-frontend --port 8883 --topic "world" --username '$sat' --pw $(cat /var/run/secrets/tokens/mq-sat) --debug --cafile /var/run/certs/ca.crt
The output should look similar to the following:
Client (null) sending CONNECT Client (null) received CONNACK (0) Client (null) sending SUBSCRIBE (Mid: 1, Topic: world, QoS: 0, Options: 0x00) Client (null) received SUBACK Subscribed (mid: 1): 0
The mosquitto client uses the same service account token and root CA cert to authenticate with the broker and subscribe to the topic.
You can also use mqttui to connect to the broker using the service account token. The
--insecure
flag is required because mqttui doesn't support TLS certificate chain verification with a custom root CA cert.Caution
Using
--insecure
is not recommended for production scenarios. Only use it for testing or development purposes.mqttui --broker mqtts://aio-mq-dmqtt-frontend:8883 --username '$sat' --password $(cat /var/run/secrets/tokens/mq-sat) --insecure
To remove the pod, run
kubectl delete pod mqtt-client -n azure-iot-operations
.
Connect clients from outside the cluster to default the TLS port
TLS trust chain
Since the broker uses TLS, the client must trust the broker's TLS certificate chain. You need to configure the client to trust the root CA certificate used by the broker.
To use the default root CA certificate, download it from the aio-ca-trust-bundle-test-only
ConfigMap:
kubectl get configmap aio-ca-trust-bundle-test-only -n azure-iot-operations -o jsonpath='{.data.ca\.crt}' > ca.crt
Use the downloaded ca.crt
file to configure your client to trust the broker's TLS certificate chain.
Authenticate with the broker
By default, IoT MQ only accepts Kubernetes service accounts for authentication for connections from within the cluster. To connect from outside the cluster, you must configure a different authentication method like X.509 or username and password. For more information, see Configure authentication.
Turn off authentication is for testing purposes only
To turn off authentication for testing purposes, edit the BrokerListener
resource and set the authenticationEnabled
field to false
:
Caution
Turning off authentication should only be used for testing purposes with a test cluster that's not accessible from the internet.
kubectl patch brokerlistener listener -n azure-iot-operations --type='json' -p='[{"op": "replace", "path": "/spec/authenticationEnabled", "value": false}]'
Port connectivity
Some Kubernetes distributions can expose IoT MQ to a port on the host system (localhost). You should use this approach because it makes it easier for clients on the same host to access IoT MQ.
For example, to create a K3d cluster with mapping the IoT MQ's default MQTT port 8883 to localhost:8883:
k3d cluster create --port '8883:8883@loadbalancer'
But for this method to work with IoT MQ, you must configure it to use a load balancer instead of cluster IP. There are two ways to do this: create a load balancer or patch the existing default BrokerListener resource service type to load balancer.
Option 1: Create a load balancer
Create a file named
loadbalancer.yaml
with the following configuration:apiVersion: v1 kind: Service metadata: name: iotmq-public-svc spec: type: LoadBalancer ports: - name: mqtt1 port: 8883 targetPort: 8883 selector: app: broker app.kubernetes.io/instance: broker app.kubernetes.io/managed-by: dmqtt-operator app.kubernetes.io/name: dmqtt tier: frontend
Apply the configuration to create a load balancer service:
kubectl apply -f loadbalancer.yaml
Option 2: Patch the default load balancer
Edit the
BrokerListener
resource and change theserviceType
field toloadBalancer
.kubectl patch brokerlistener listener --namespace azure-iot-operations --type='json' --patch='[{"op": "replace", "path": "/spec/serviceType", "value": "loadBalancer"}]'
Wait for the service to be updated.
kubectl get service aio-mq-dmqtt-frontend --namespace azure-iot-operations
Output should look similar to the following:
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE aio-mq-dmqtt-frontend LoadBalancer 10.43.107.11 XXX.XX.X.X 8883:30366/TCP 14h
You can use the external IP address to connect to IoT MQ over the internet. Make sure to use the external IP address instead of
localhost
.mosquitto_pub --qos 1 --debug -h XXX.XX.X.X --message hello --topic world --username client1 --pw password --cafile ca.crt
Tip
You can use the external IP address to connect to IoT MQ from outside the cluster. If you used the K3d command with port forwarding option, you can use localhost
to connect to IoT MQ. For example, to connect with mosquitto client:
mosquitto_pub --qos 1 --debug -h localhost --message hello --topic world --username client1 --pw password --cafile ca.crt --insecure
In this example, the mosquitto client uses username and password to authenticate with the broker along with the root CA cert to verify the broker's TLS certificate chain. Here, the --insecure
flag is required because the default TLS certificate issued to the load balancer is only valid for the load balancer's default service name (aio-mq-dmqtt-frontend) and assigned IPs, not localhost.
Never expose IoT MQ port to the internet without authentication and TLS. Doing so is dangerous and can lead to unauthorized access to your IoT devices and bring unsolicited traffic to your cluster.
For information on how to add localhost to the certificate's subject alternative name (SAN) to avoid using the insecure flag, see Configure server certificate parameters.
Use port forwarding
With minikube, kind, and other cluster emulation systems, an external IP might not be automatically assigned. For example, it might show as Pending state.
To access the broker, forward the broker listening port 8883 to the host.
kubectl port-forward --namespace azure-iot-operations service/aio-mq-dmqtt-frontend 8883:mqtts-8883
Use 127.0.0.1 to connect to the broker at port 8883 with the same authentication and TLS configuration as the example without port forwarding.
Port forwarding is also useful for testing IoT MQ locally on your development machine without having to modify the broker's configuration.
To learn more, see Use Port Forwarding to Access Applications in a Cluster for minikube and Expose Kubernetes services to external devices for Azure Kubernetes Services Edge Essentials.
No TLS and no authentication
The reason that IoT MQ uses TLS and service accounts authentication by default is to provide a secure-by-default experience that minimizes inadvertent exposure of your IoT solution to attackers. You shouldn't turn off TLS and authentication in production.
Caution
Don't use in production. Exposing IoT MQ to the internet without authentication and TLS can lead to unauthorized access and even DDOS attacks.
If you understand the risks and need to use an insecure port in a well-controlled environment, you can turn off TLS and authentication for testing purposes following these steps:
Create a new
BrokerListener
resource without TLS settings:apiVersion: mq.iotoperations.azure.com/v1beta1 kind: BrokerListener metadata: name: non-tls-listener namespace: azure-iot-operations spec: brokerRef: broker serviceType: loadBalancer serviceName: my-unique-service-name authenticationEnabled: false authorizationEnabled: false port: 1883
The
authenticationEnabled
andauthorizationEnabled
fields are set tofalse
to turn off authentication and authorization. Theport
field is set to1883
to use common MQTT port.Wait for the service to be updated.
kubectl get service my-unique-service-name --namespace azure-iot-operations
Output should look similar to the following:
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE my-unique-service-name LoadBalancer 10.43.144.182 XXX.XX.X.X 1883:31001/TCP 5m11s
The new port 1883 is available.
Use mosquitto client to connect to the broker:
mosquitto_pub --qos 1 --debug -h localhost --message hello --topic world
The output should look similar to the following:
Client mosq-7JGM4INbc5N1RaRxbW sending CONNECT Client mosq-7JGM4INbc5N1RaRxbW received CONNACK (0) Client mosq-7JGM4INbc5N1RaRxbW sending PUBLISH (d0, q1, r0, m1, 'world', ... (5 bytes)) Client mosq-7JGM4INbc5N1RaRxbW received PUBACK (Mid: 1, RC:0) Client mosq-7JGM4INbc5N1RaRxbW sending DISCONNECT
Related content
Feedback
https://aka.ms/ContentUserFeedback.
Coming soon: Throughout 2024 we will be phasing out GitHub Issues as the feedback mechanism for content and replacing it with a new feedback system. For more information see:Submit and view feedback for