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 becomes available. You won't be able to upgrade a preview installation.
For legal terms that apply to Azure features that are in beta, in preview, or otherwise not yet released into general availability, see the Supplemental Terms of Use for Microsoft Azure Previews.
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 18883 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 to the default listener inside the cluster
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 certificate.
First, create a file named client.yaml
with the following configuration:
apiVersion: v1
kind: ServiceAccount
metadata:
name: mqtt-client
namespace: azure-iot-operations
---
apiVersion: v1
kind: Pod
metadata:
name: mqtt-client
# Namespace must match MQTT broker BrokerListener's namespace
# Otherwise use the long hostname: aio-broker.azure-iot-operations.svc.cluster.local
namespace: azure-iot-operations
spec:
# Use the "mqtt-client" service account created from above
# 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: broker-sat
mountPath: /var/run/secrets/tokens
- name: trust-bundle
mountPath: /var/run/certs
volumes:
- name: broker-sat
projected:
sources:
- serviceAccountToken:
path: broker-sat
audience: aio-internal # Must match audience in BrokerAuthentication
expirationSeconds: 86400
- name: trust-bundle
configMap:
name: azure-iot-operations-aio-ca-trust-bundle # Default root CA cert
Then, use kubectl
to deploy the configuration. It should only take a few seconds to start.
kubectl apply -f client.yaml
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-broker --port 18883 --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/broker-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/broker-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.
Tip
You can use kubectl
to download the default root CA certificate to use with other clients. For example, to download the default root CA certificate to a file named ca.crt
:
kubectl get configmap azure-iot-operations-aio-ca-trust-bundle -n azure-iot-operations -o jsonpath='{.data.ca\.crt}' > ca.crt
To subscribe to the topic, run the following command:
mosquitto_sub --host aio-broker --port 18883 --topic "world" --debug --cafile /var/run/certs/ca.crt -D CONNECT authentication-method 'K8S-SAT' -D CONNECT authentication-data $(cat /var/run/secrets/tokens/broker-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
Since the default broker listener is set to ClusterIp service type, you can't connect to the broker from outside the cluster directly. To prevent unintentional disruption to communication between internal Azure IoT Operations components, we recommend keeping the default listener unmodified and dedicated for AIO internal communication. While it's possible to create a separate Kubernetes LoadBalancer service to expose the cluster IP service, it's better to create a separate listener with different settings, like more common MQTT port 1883 and 8883, to avoid confusion and potential security risks.
Node port
The easiest way to test connectivity is to use the NodePort service type in the listener. With that, you can use <nodeExternalIP>:<NodePort>
to connect like in Kubernetes documentation.
For example, create a new broker listener with node port service type listening on port 1883:
In the Azure portal, go to your IoT Operations instance.
Under Azure IoT Operations resources, select MQTT Broker.
Select MQTT broker listener for NodePort > Create. You can only create one listener per service type. If you already have a listener of the same service type, you can add more ports to the existing listener.
Caution
Setting authentication to None and not configuring TLS turns off authentication and TLS for testing purposes only.
Enter the following settings:
Setting Value Name nodeport Service name aio-broker-nodeport Port 1883 Authentication Choose default or None Authorization Choose default Protocol Choose MQTT Node port 31883 Add TLS settings to the listener by selecting TLS on the port.
Setting Description TLS Select the Add button. TLS mode Choose Manual or Automatic. Issuer name Name of the cert-manager issuer. Required. Issuer kind Kind of the cert-manager issuer. Required. Issuer group Group of the cert-manager issuer. Required. Private key algorithm Algorithm for the private key. Private key rotation policy Policy for rotating the private key. DNS names DNS subject alternate names for the certificate. IP addresses IP addresses of the subject alternate names for the certificate. Secret name Kubernetes secret containing an X.509 client certificate. Duration Total lifetime of the TLS server certificate Defaults to 90 days. Renew before When to begin renewing the certificate. Select Apply to save the TLS settings.
Select Create to create the listener.
Get the node's external IP address:
kubectl get nodes -o yaml | grep ExternalIP -C 1
The output should look similar to the following:
- address: 104.197.41.11
type: ExternalIP
allocatable:
--
- address: 23.251.152.56
type: ExternalIP
allocatable:
...
Use the external IP address and the node port to connect to the broker. For example, to publish a message to the broker:
mosquitto_pub --host <EXTERNAL_IP> --port 31883 --message "hello" --topic "world" --debug # Add authentication and TLS options matching listener settings
If there's no external IP in the output, you might be using a Kubernetes setup that doesn't expose the node's external IP address by default, like many setups of k3s, k3d, or minikube. In that case, you can access the broker with the internal IP along with the node port from machines on the same network. For example, to get the internal IP address of the node:
kubectl get nodes -o yaml | grep InternalIP -C 1
The output should look similar to the following:
- address: 172.19.0.2
type: InternalIP
allocatable:
Then, use the internal IP address and the node port to connect to the broker from a machine within the same cluster. If Kubernetes is running on a local machine, like with single-node k3s, you can often use localhost
instead of the internal IP address. If Kubernetes is running in a Docker container, like with k3d, the internal IP address corresponds to the container's IP address, and should be reachable from the host machine.
Load balancer
Another way to expose the broker to the internet is to use the LoadBalancer service type. This method is more complex and might require additional configuration, like setting up port forwarding.
For example, to create a new broker listener with load balancer service type listening on port 1883:
In the Azure portal, go to your IoT Operations instance.
Under Azure IoT Operations resources, select MQTT Broker.
Select MQTT broker listener for NodePort > Create. You can only create one listener per service type. If you already have a listener of the same service type, you can add more ports to the existing listener.
Caution
Setting authentication to None and not configuring TLS turns off authentication and TLS for testing purposes only.
Enter the following settings:
Setting Value Name loadbalancer Service name aio-broker-loadbalancer Port 1883 Authentication Choose default Authorization Choose default or None Protocol Choose MQTT You can add TLS settings to the listener by selecting TLS on the port.
Setting Description TLS Select the Add button. TLS mode Choose Manual or Automatic. Issuer name Name of the cert-manager issuer. Required. Issuer kind Kind of the cert-manager issuer. Required. Issuer group Group of the cert-manager issuer. Required. Private key algorithm Algorithm for the private key. Private key rotation policy Policy for rotating the private key. DNS names DNS subject alternate names for the certificate. IP addresses IP addresses of the subject alternate names for the certificate. Secret name Kubernetes secret containing an X.509 client certificate. Duration Total lifetime of the TLS server certificate Defaults to 90 days. Renew before When to begin renewing the certificate. Select Apply to save the TLS settings.
Select Create to create the listener.
Get the external IP address for the broker's service:
kubectl get service aio-broker-loadbalancer --namespace azure-iot-operations
If the output looks similar to the following:
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
aio-broker-loadbalancer LoadBalancer 10.x.x.x x.x.x.x 1883:30382/TCP 83s
This means that an external IP has been assigned to the load balancer service, and you can use the external IP address and the port to connect to the broker. For example, to publish a message to the broker:
mosquitto_pub --host <EXTERNAL_IP> --port 1883 --message "hello" --topic "world" --debug # Add authentication and TLS options matching listener settings
If the external IP is not assigned, you might need to use port forwarding or a virtual switch to access the broker.
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 18883 to the host.
kubectl port-forward --namespace azure-iot-operations service/aio-broker 18883:mqtts-18883
Use 127.0.0.1 to connect to the broker at port 18883 with the same authentication and TLS configuration as the example without port forwarding.
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. With AKS Edge Essentials, getting the external IP address might not be enough to connect to the broker. You might need to set up port forwarding and open the port on the firewall to allow traffic to the broker's service.
First, get the external IP address of the broker's load balancer listener:
kubectl get service broker-loadbalancer --namespace azure-iot-operations
Output should look similar to the following:
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE broker-loadbalancer LoadBalancer 10.x.x.x 192.168.0.4 1883:30366/TCP 14h
Set up port forwarding to the
broker-loadbalancer
service on the external IP address192.168.0.4
and port1883
:netsh interface portproxy add v4tov4 listenport=1883 connectport=1883 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 1883 -Action Allow
Use the host's public IP address to connect to the MQTT broker.
For more information about port forwarding, see Expose Kubernetes services to external devices.
Access through localhost
Some Kubernetes distributions can expose MQTT broker to a port on the host system (localhost) as part of cluster configuration. Use this approach to make 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 1883 to localhost:1883
:
k3d cluster create --port '1883:1883@loadbalancer'
Or to update an existing cluster:
k3d cluster edit <CLUSTER_NAME> --port-add '1883:1883@loadbalancer'
Then, use localhost
and the port to connect to the broker. For example, to publish a message to the broker:
mosquitto_pub --host localhost --port 1883 --message "hello" --topic "world" --debug # Add authentication and TLS options matching listener settings
Only turn off TLS and authentication for testing
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. Exposing MQTT broker to the internet without authentication and TLS can lead to unauthorized access and even DDOS attacks.
Warning
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 by removing the tls
and authenticationRef
settings from the listener configuration.
In the Azure portal, go to your IoT Operations instance.
Under Azure IoT Operations resources, select MQTT Broker.
Select MQTT broker listener for NodePort > Create. You can only create one listener per service type. If you already have a listener of the same service type, you can add more ports to the existing listener.
Caution
Setting authentication to None and not configuring TLS turns off authentication and TLS for testing purposes only.
Enter the following settings:
Setting Value Name Enter a name for the listener Service name Enter a service name Port 1883 Authentication Choose None Authorization Choose None Protocol Choose MQTT Node port 31883 if using node port Select Create to create the listener.