Skip to content

Commit 02b34ac

Browse files
authored
Merge pull request #269097 from PatAltimore/patricka-mqtt-connect
Improve MQTT connect article
2 parents 4936127 + 5a5e1f3 commit 02b34ac

File tree

1 file changed

+143
-76
lines changed

1 file changed

+143
-76
lines changed

articles/iot-operations/manage-mqtt-connectivity/howto-test-connection.md

Lines changed: 143 additions & 76 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,13 @@
11
---
22
title: Test connectivity to IoT MQ with MQTT clients
3-
description: Learn how to use common and standard MQTT tools to test connectivity to Azure IoT MQ.
3+
description: Learn how to use common and standard MQTT tools to test connectivity to Azure IoT MQ in a nonproduction environment.
44
author: PatAltimore
55
ms.author: patricka
66
ms.subservice: mq
77
ms.topic: how-to
88
ms.custom:
99
- ignite-2023
10-
ms.date: 11/15/2023
10+
ms.date: 03/18/2024
1111

1212
#CustomerIntent: As an operator or developer, I want to test MQTT connectivity with tools that I'm already familiar with to know that I set up my Azure IoT MQ broker correctly.
1313
---
@@ -16,55 +16,63 @@ ms.date: 11/15/2023
1616

1717
[!INCLUDE [public-preview-note](../includes/public-preview-note.md)]
1818

19-
This article shows different ways to test connectivity to Azure IoT MQ Preview with MQTT clients.
19+
This article shows different ways to test connectivity to Azure IoT MQ Preview with MQTT clients in a nonproduction environment.
2020

21-
By default:
21+
By default, Azure IoT MQ Preview:
2222

23-
- IoT MQ deploys a [TLS-enabled listener](howto-configure-brokerlistener.md) 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*.
23+
- Deploys a [TLS-enabled listener](howto-configure-brokerlistener.md) 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*.
2424

25-
- IoT MQ only accepts [Kubernetes service accounts for authentication](howto-configure-authentication.md) for connections from within the cluster. To connect from outside the cluster, you must configure a different authentication method.
25+
- Accepts [Kubernetes service accounts for authentication](howto-configure-authentication.md) for connections from within the cluster. To connect from outside the cluster, you must configure a different authentication method.
2626

27-
Before you begin, [install or deploy IoT Operations](../get-started/quickstart-deploy.md). Use the following options to test connectivity to IoT MQ with MQTT clients.
27+
> [!CAUTION]
28+
> For production scenarios, you should use TLS and service accounts authentication to secure your IoT solution. For more information, see:
29+
> - [Configure TLS with automatic certificate management to secure MQTT communication in Azure IoT MQ Preview](./howto-configure-tls-auto.md)
30+
> - [Configure authentication in Azure IoT MQ Preview](./howto-configure-authentication.md)
31+
> - [Expose Kubernetes services to external devices](/azure/aks/hybrid/aks-edge-howto-expose-service) using port forwarding or a virtual switch with Azure Kubernetes Services Edge Essentials.
32+
33+
Before you begin, [install or deploy IoT Operations](../get-started/quickstart-deploy.md). Use the following options to test connectivity to IoT MQ with MQTT clients in a nonproduction environment.
2834

2935
## Connect from a pod within the cluster with default configuration
3036

3137
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.
3238

33-
```yaml
34-
apiVersion: v1
35-
kind: Pod
36-
metadata:
37-
name: mqtt-client
38-
# Namespace must match IoT MQ BrokerListener's namespace
39-
# Otherwise use the long hostname: aio-mq-dmqtt-frontend.azure-iot-operations.svc.cluster.local
40-
namespace: azure-iot-operations
41-
spec:
42-
# Use the "mqtt-client" service account which comes with default deployment
43-
# Otherwise create it with `kubectl create serviceaccount mqtt-client -n azure-iot-operations`
44-
serviceAccountName: mqtt-client
45-
containers:
46-
# Mosquitto and mqttui on Alpine
47-
- image: alpine
48-
name: mqtt-client
49-
command: ["sh", "-c"]
50-
args: ["apk add mosquitto-clients mqttui && sleep infinity"]
51-
volumeMounts:
52-
- name: mq-sat
53-
mountPath: /var/run/secrets/tokens
54-
- name: trust-bundle
55-
mountPath: /var/run/certs
56-
volumes:
57-
- name: mq-sat
58-
projected:
59-
sources:
60-
- serviceAccountToken:
61-
path: mq-sat
62-
audience: aio-mq # Must match audience in BrokerAuthentication
63-
expirationSeconds: 86400
64-
- name: trust-bundle
65-
configMap:
66-
name: aio-ca-trust-bundle-test-only # Default root CA cert
67-
```
39+
1. Create a file named `client.yaml` with the following configuration:
40+
41+
```yaml
42+
apiVersion: v1
43+
kind: Pod
44+
metadata:
45+
name: mqtt-client
46+
# Namespace must match IoT MQ BrokerListener's namespace
47+
# Otherwise use the long hostname: aio-mq-dmqtt-frontend.azure-iot-operations.svc.cluster.local
48+
namespace: azure-iot-operations
49+
spec:
50+
# Use the "mqtt-client" service account which comes with default deployment
51+
# Otherwise create it with `kubectl create serviceaccount mqtt-client -n azure-iot-operations`
52+
serviceAccountName: mqtt-client
53+
containers:
54+
# Mosquitto and mqttui on Alpine
55+
- image: alpine
56+
name: mqtt-client
57+
command: ["sh", "-c"]
58+
args: ["apk add mosquitto-clients mqttui && sleep infinity"]
59+
volumeMounts:
60+
- name: mq-sat
61+
mountPath: /var/run/secrets/tokens
62+
- name: trust-bundle
63+
mountPath: /var/run/certs
64+
volumes:
65+
- name: mq-sat
66+
projected:
67+
sources:
68+
- serviceAccountToken:
69+
path: mq-sat
70+
audience: aio-mq # Must match audience in BrokerAuthentication
71+
expirationSeconds: 86400
72+
- name: trust-bundle
73+
configMap:
74+
name: aio-ca-trust-bundle-test-only # Default root CA cert
75+
```
6876
6977
1. Use `kubectl apply -f client.yaml` to deploy the configuration. It should only take a few seconds to start.
7078

@@ -73,13 +81,18 @@ spec:
7381
For example, to publish a message to the broker, open a shell inside the pod:
7482

7583
```bash
76-
kubectl exec --stdin --tty mqtt-client -n azure-iot-operations -- sh
84+
kubectl exec --stdin --tty mqtt-client --namespace azure-iot-operations -- sh
7785
```
7886

7987
1. Inside the pod's shell, run the following command to publish a message to the broker:
8088

8189
```console
82-
$ mosquitto_pub -h aio-mq-dmqtt-frontend -p 8883 -m "hello" -t "world" -u '$sat' -P $(cat /var/run/secrets/tokens/mq-sat) -d --cafile /var/run/certs/ca.crt
90+
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
91+
```
92+
93+
The output should look similar to the following:
94+
95+
```Output
8396
Client (null) sending CONNECT
8497
Client (null) received CONNACK (0)
8598
Client (null) sending PUBLISH (d0, q0, r0, m1, 'world', ... (5 bytes))
@@ -91,7 +104,12 @@ spec:
91104
1. To subscribe to the topic, run the following command:
92105

93106
```console
94-
$ mosquitto_sub -h aio-mq-dmqtt-frontend -p 8883 -t "world" -u '$sat' -P $(cat /var/run/secrets/tokens/mq-sat) -d --cafile /var/run/certs/ca.crt
107+
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
108+
```
109+
110+
The output should look similar to the following:
111+
112+
```Output
95113
Client (null) sending CONNECT
96114
Client (null) received CONNACK (0)
97115
Client (null) sending SUBSCRIBE (Mid: 1, Topic: world, QoS: 0, Options: 0x00)
@@ -101,27 +119,30 @@ spec:
101119

102120
The mosquitto client uses the same service account token and root CA cert to authenticate with the broker and subscribe to the topic.
103121

104-
1. To use *mqttui*, the command is similar:
122+
1. 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.
123+
124+
> [!CAUTION]
125+
> Using `--insecure` is not recommended for production scenarios. Only use it for testing or development purposes.
105126

106127
```console
107-
$ mqttui -b mqtts://aio-mq-dmqtt-frontend:8883 -u '$sat' --password $(cat /var/run/secrets/tokens/mq-sat) --insecure
128+
mqttui --broker mqtts://aio-mq-dmqtt-frontend:8883 --username '$sat' --password $(cat /var/run/secrets/tokens/mq-sat) --insecure
108129
```
109130

110-
With the above command, mqttui connects 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.
111-
112131
1. To remove the pod, run `kubectl delete pod mqtt-client -n azure-iot-operations`.
113132

114133
## Connect clients from outside the cluster to default the TLS port
115134

116135
### TLS trust chain
117136

118-
Since the broker uses TLS, the client must trust the broker's TLS certificate chain. To do so, you must configure the client to trust the root CA cert used by the broker. To use the default root CA cert, download it from the `aio-ca-trust-bundle-test-only` ConfigMap:
137+
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.
138+
139+
To use the default root CA certificate, download it from the `aio-ca-trust-bundle-test-only` ConfigMap:
119140

120141
```bash
121142
kubectl get configmap aio-ca-trust-bundle-test-only -n azure-iot-operations -o jsonpath='{.data.ca\.crt}' > ca.crt
122143
```
123144

124-
Then, use the `ca.crt` file to configure your client to trust the broker's TLS certificate chain.
145+
Use the downloaded `ca.crt` file to configure your client to trust the broker's TLS certificate chain.
125146

126147
### Authenticate with the broker
127148

@@ -131,57 +152,93 @@ By default, IoT MQ only accepts Kubernetes service accounts for authentication f
131152

132153
To turn off authentication for testing purposes, edit the `BrokerListener` resource and set the `authenticationEnabled` field to `false`:
133154

155+
> [!CAUTION]
156+
> Turning off authentication should only be used for testing purposes with a test cluster that's not accessible from the internet.
157+
134158
```bash
135159
kubectl patch brokerlistener listener -n azure-iot-operations --type='json' -p='[{"op": "replace", "path": "/spec/authenticationEnabled", "value": false}]'
136160
```
137161

138-
> [!WARNING]
139-
> Turning off authentication should only be used for testing purposes with a test cluster that's not accessible from the internet.
140-
141162
### Port connectivity
142163

143164
Some Kubernetes distributions can [expose](https://k3d.io/v5.1.0/usage/exposing_services/) 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.
144165

145166
For example, to create a K3d cluster with mapping the IoT MQ's default MQTT port 8883 to localhost:8883:
146167

147168
```bash
148-
k3d cluster create -p '8883:8883@loadbalancer'
169+
k3d cluster create --port '8883:8883@loadbalancer'
149170
```
150171

151-
But for this method to work with IoT MQ, you must configure it to use a load balancer instead of cluster IP.
172+
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.
152173

153-
To configure a load balancer:
174+
#### Option 1: Create a load balancer
175+
176+
1. Create a file named `loadbalancer.yaml` with the following configuration:
177+
178+
```yaml
179+
apiVersion: v1
180+
kind: Service
181+
metadata:
182+
name: iotmq-public-svc
183+
spec:
184+
type: LoadBalancer
185+
ports:
186+
- name: mqtt1
187+
port: 8883
188+
targetPort: 8883
189+
selector:
190+
app: broker
191+
app.kubernetes.io/instance: broker
192+
app.kubernetes.io/managed-by: dmqtt-operator
193+
app.kubernetes.io/name: dmqtt
194+
tier: frontend
195+
```
196+
197+
1. Apply the configuration to create a load balancer service:
198+
199+
```bash
200+
kubectl apply -f loadbalancer.yaml
201+
```
202+
203+
#### Option 2: Patch the default load balancer
154204

155205
1. Edit the `BrokerListener` resource and change the `serviceType` field to `loadBalancer`.
156206

157207
```bash
158-
kubectl patch brokerlistener listener -n azure-iot-operations --type='json' -p='[{"op": "replace", "path": "/spec/serviceType", "value": "loadBalancer"}]'
208+
kubectl patch brokerlistener listener --namespace azure-iot-operations --type='json' --patch='[{"op": "replace", "path": "/spec/serviceType", "value": "loadBalancer"}]'
159209
```
160210

161-
1. Wait for the service to be updated, You should see output similar to the following:
211+
1. Wait for the service to be updated.
162212

163213
```console
164-
$ kubectl get service aio-mq-dmqtt-frontend -n azure-iot-operations
165-
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
166-
aio-mq-dmqtt-frontend LoadBalancer 10.43.107.11 XXX.XX.X.X 8883:30366/TCP 14h
214+
kubectl get service aio-mq-dmqtt-frontend --namespace azure-iot-operations
167215
```
168216

169-
1. Use the external IP address to connect to IoT MQ from outside the cluster. If you used the K3d command with port forwarding, you can use `localhost` to connect to IoT MQ. For example, to connect with mosquitto client:
217+
Output should look similar to the following:
170218

171-
```bash
172-
mosquitto_pub -q 1 -d -h localhost -m hello -t world -u client1 -P password --cafile ca.crt --insecure
219+
```Output
220+
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
221+
aio-mq-dmqtt-frontend LoadBalancer 10.43.107.11 XXX.XX.X.X 8883:30366/TCP 14h
173222
```
174223

175-
In this example, the mosquitto client uses username/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.
176-
177-
1. If your cluster like Azure Kubernetes Service automatically assigns an external IP address to the load balancer, 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` in the prior command, and remove the `--insecure` flag.
224+
1. 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`.
178225

179226
```bash
180-
mosquitto_pub -q 1 -d -h XXX.XX.X.X -m hello -t world -u client1 -P password --cafile ca.crt
227+
mosquitto_pub --qos 1 --debug -h XXX.XX.X.X --message hello --topic world --username client1 --pw password --cafile ca.crt
181228
```
182229

183-
> [!WARNING]
184-
> 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.
230+
> [!TIP]
231+
> 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:
232+
>
233+
> ```bash
234+
> mosquitto_pub --qos 1 --debug -h localhost --message hello --topic world --username client1 --pw password --cafile ca.crt --insecure
235+
> ```
236+
>
237+
> 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.
238+
>
239+
> 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.
240+
>
241+
> 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](howto-configure-tls-auto.md#optional-configure-server-certificate-parameters).
185242

186243
#### Use port forwarding
187244

@@ -190,14 +247,14 @@ With [minikube](https://minikube.sigs.k8s.io/docs/), [kind](https://kind.sigs.k8
190247
1. To access the broker, forward the broker listening port 8883 to the host.
191248

192249
```bash
193-
kubectl port-forward service/aio-mq-dmqtt-frontend 8883:mqtts-8883 -n azure-iot-operations
250+
kubectl port-forward --namespace azure-iot-operations service/aio-mq-dmqtt-frontend 8883:mqtts-8883
194251
```
195252

196253
1. 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.
197254

198255
Port forwarding is also useful for testing IoT MQ locally on your development machine without having to modify the broker's configuration.
199256

200-
To learn more, see [Use Port Forwarding to Access Applications in a Cluster](https://kubernetes.io/docs/tasks/access-application-cluster/port-forward-access-application-cluster/) for minikube.
257+
To learn more, see [Use Port Forwarding to Access Applications in a Cluster](https://kubernetes.io/docs/tasks/access-application-cluster/port-forward-access-application-cluster/) for minikube and [Expose Kubernetes services to external devices](/azure/aks/hybrid/aks-edge-howto-expose-service) for Azure Kubernetes Services Edge Essentials.
201258

202259
## No TLS and no authentication
203260

@@ -227,10 +284,15 @@ If you understand the risks and need to use an insecure port in a well-controlle
227284

228285
The `authenticationEnabled` and `authorizationEnabled` fields are set to `false` to turn off authentication and authorization. The `port` field is set to `1883` to use common MQTT port.
229286

230-
1. Wait for the service to be updated. You should see output similar to the following:
287+
1. Wait for the service to be updated.
231288

232289
```console
233-
$ kubectl get service my-unique-service-name -n azure-iot-operations
290+
kubectl get service my-unique-service-name --namespace azure-iot-operations
291+
```
292+
293+
Output should look similar to the following:
294+
295+
```Output
234296
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
235297
my-unique-service-name LoadBalancer 10.43.144.182 XXX.XX.X.X 1883:31001/TCP 5m11s
236298
```
@@ -240,7 +302,12 @@ If you understand the risks and need to use an insecure port in a well-controlle
240302
1. Use mosquitto client to connect to the broker:
241303

242304
```console
243-
$ mosquitto_pub -q 1 -d -h localhost -m hello -t world
305+
mosquitto_pub --qos 1 --debug -h localhost --message hello --topic world
306+
```
307+
308+
The output should look similar to the following:
309+
310+
```Output
244311
Client mosq-7JGM4INbc5N1RaRxbW sending CONNECT
245312
Client mosq-7JGM4INbc5N1RaRxbW received CONNACK (0)
246313
Client mosq-7JGM4INbc5N1RaRxbW sending PUBLISH (d0, q1, r0, m1, 'world', ... (5 bytes))

0 commit comments

Comments
 (0)