Test connectivity to MQTT broker 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.
You'll need to deploy a new Azure IoT Operations installation when a generally available release is made available. You won't be able to upgrade a preview installation.
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 MQTT broker with MQTT clients in a nonproduction environment.
By default, MQTT broker:
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 MQTT broker
- Configure authentication in MQTT broker
- Expose Kubernetes services to external devices using port forwarding or a virtual switch with Azure Kubernetes Services Edge Essentials.
Before you begin, install or configure IoT Operations. Use the following options to test connectivity to MQTT broker 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 MQTT broker 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" --debug --cafile /var/run/certs/ca.crt -D CONNECT authentication-method 'K8S-SAT' -D CONNECT authentication-data $(cat /var/run/secrets/tokens/mq-sat)
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" --debug --cafile /var/run/certs/ca.crt -D CONNECT authentication-method 'K8S-SAT' -D CONNECT authentication-data $(cat /var/run/secrets/tokens/mq-sat)
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.
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.
If you are connecting to the broker from a different namespace, you must use the full service hostname aio-mq-dmqtt-frontend.azure-iot-operations.svc.cluster.local
. You must also add the DNS name to the server certificate by including a subject alternative name (SAN) DNS field to the BrokerListener resource. For more information, see Configure server certificate parameters.
Authenticate with the broker
By default, MQTT broker 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. 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 MQTT broker 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 MQTT broker.
For example, to create a K3d cluster with mapping the MQTT broker's default MQTT port 8883 to localhost:8883:
k3d cluster create --port '8883:8883@loadbalancer'
But for this method to work with MQTT broker, 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 MQTT broker 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 MQTT broker from outside the cluster. If you used the K3d command with port forwarding option, you can use localhost
to connect to MQTT broker. 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 MQTT broker 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 MQTT broker locally on your development machine without having to modify the broker's configuration. For more information about minikube, see Use Port Forwarding to Access Applications in a Cluster
Port forwarding on AKS Edge Essentials
For Azure Kubernetes Services Edge Essentials, you need to perform a few additional steps. For more information about port forwarding, see Expose Kubernetes services to external devices.
Assume that the broker's service is exposed to an external IP using a load balancer. For example if you patched the default load balancer
aio-mq-dmqtt-frontend
, get the external IP address for the service.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 192.168.0.4 8883:30366/TCP 14h
Set up port forwarding to the
aio-mq-dmqtt-frontend
service on the external IP address192.168.0.4
and port8883
:netsh interface portproxy add v4tov4 listenport=8883 connectport=8883 connectaddress=192.168.0.4
Open the port on the firewall to allow traffic to the broker's service:
New-NetFirewallRule -DisplayName "AIO MQTT Broker" -Direction Inbound -Protocol TCP -LocalPort 8883 -Action Allow
Use the host's public IP address to connect to the MQTT broker.
No TLS and no authentication
The reason that MQTT broker 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 MQTT broker 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: mqttbroker.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