MQTT クライアントを使用して MQTT ブローカーへの接続をテストする
重要
Azure Arc によって有効にされる Azure IoT Operations Preview は、 現在プレビュー段階です。 運用環境ではこのプレビュー ソフトウェアを使わないでください。
一般公開されたリリースが利用可能になった場合に、新しい Azure IoT Operations を表示する必要があります。プレビュー段階のインストールをアップグレードすることはできません。
ベータ版、プレビュー版、または一般提供としてまだリリースされていない Azure の機能に適用される法律条項については、「Microsoft Azure プレビューの追加使用条件」を参照してください。
この記事では、MQTT クライアントを使用して非運用環境で MQTT ブローカーへの接続をテストするさまざまな方法について説明します。
既定値の MQTT ブローカー:
サービスの種類として ClusterIp を指定し、ポート 8883 に TLS 対応リスナーを配置します。 ClusterIp は、ブローカーが Kubernetes クラスター内からのみアクセス可能であることを意味します。 クラスターの外部からブローカーにアクセスするには、サービスの種類を LoadBalancer または NodePort として構成する必要があります。
クラスター内からの接続に対して認証用の Kubernetes サービス アカウントのみを受け入れます。 クラスターの外部から接続するには、別の認証方法を構成する必要があります。
注意事項
運用環境のシナリオでは、TLS とサービス アカウント認証を使用して IoT ソリューションをセキュリティで保護する必要があります。 詳細については、以下を参照してください:
- MQTT ブローカーで MQTT 通信をセキュリティで保護するために、自動の証明書管理で TLS を構成する
- MQTT ブローカーで認証を構成する
- Azure Kubernetes Services Edge Essentials でポート フォワーディングまたは仮想スイッチを使用して、Kubernetes サービスを外部デバイスに公開する。
始める前に、IoT Operations をインストールまたは構成します。 非運用環境で MQTT クライアントを使用して MQTT ブローカーへの接続をテストするには、次のオプションを使用します。
既定の構成でクラスター内のポッドから接続する
最初のオプションは、クラスター内から接続するものです。 このオプションでは既定の構成が使用され、追加の更新は必要ありません。 次の例は、プレーンな Alpine Linux と一般的に使用される MQTT クライアントを使用してクラスター内から接続する方法を示しています。サービス アカウントと既定のルート CA 証明書を使用します。
次の構成を使用して
client.yaml
という名前のファイルを作成します。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
kubectl apply -f client.yaml
を使用して構成をデプロイします。 わずか数秒で開始します。ポッドが実行されたら、
kubectl exec
を使用してポッド内でコマンドを実行します。たとえば、ブローカーにメッセージを発行するには、ポッド内でシェルを開きます。
kubectl exec --stdin --tty mqtt-client --namespace azure-iot-operations -- sh
ポッドのシェルで次のコマンドを実行し、ブローカーにメッセージを発行します。
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)
出力は次のようになります。
Client (null) sending CONNECT Client (null) received CONNACK (0) Client (null) sending PUBLISH (d0, q0, r0, m1, 'world', ... (5 bytes)) Client (null) sending DISCONNECT
mosquitto クライアントは、
/var/run/secrets/tokens/mq-sat
にマウントされたサービス アカウント トークンを使用してブローカーで認証します。 トークンの有効期間は 24 時間です。 また、クライアントは、/var/run/certs/ca.crt
にマウントされている既定のルート CA 証明書を使用して、ブローカーの TLS 証明書チェーンを検証します。トピックにサブスクライブするには、次のコマンドを実行します。
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)
出力は次のようになります。
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
mosquitto クライアントは、同じサービス アカウント トークンとルート CA 証明書を使用してブローカーで認証し、トピックにサブスクライブします。
ポッドを削除するには、
kubectl delete pod mqtt-client -n azure-iot-operations
を実行します。
クラスターの外部からクライアントを接続して、既定の TLS ポートに接続します
TLS 信頼チェーン
ブローカーは TLS を使用するため、クライアントはブローカーの TLS 証明書チェーンを信頼する必要があります。 ブローカーによって使用されるルート CA 証明書を信頼するようにクライアントを構成する必要があります。
既定のルート CA 証明書を使用するには、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
ダウンロードした ca.crt
ファイルを使用して、ブローカーの TLS 証明書チェーンを信頼するようにクライアントを構成します。
ブローカーで認証する
既定では、MQTT ブローカーはクラスター内からの接続に対して認証用の Kubernetes サービス アカウントのみを受け入れます。 クラスターの外部から接続するには、X.509 などの別の認証方法を構成する必要があります。 詳しくは、「認証の構成」をご覧ください。
資格情報をオフにできるのは、テスト目的の場合のみです
テスト目的で認証をオフにするには、BrokerListener
リソースを編集し、authenticationEnabled
フィールドを false
に設定します。
注意事項
認証をオフにする場合は、インターネットからアクセスできないテスト クラスターを使用し、使用をテスト目的のみに限る必要があります。
kubectl patch brokerlistener listener -n azure-iot-operations --type='json' -p='[{"op": "replace", "path": "/spec/authenticationEnabled", "value": false}]'
ポート接続
一部の Kubernetes ディストリビューションでは、ホスト システム (localhost) 上のポートで MQTT ブローカーを公開できます。 同じホスト上のクライアントが MQTT ブローカーにアクセスしやすくなるため、この方法を使用する必要があります。
たとえば、MQTT ブローカーの既定の MQTT ポート 8883 を localhost:8883 にマッピングした K3d クラスターを作成するには、次のようにします。
k3d cluster create --port '8883:8883@loadbalancer'
ただし、この方法で MQTT ブローカーを使用するには、クラスター IP ではなくロード バランサーを使用するように構成する必要があります。 これを行うには、2 つの方法があります。ロード バランサーを作成するか、既存の既定の BrokerListener リソース サービスの種類にパッチを適用してロード バランサーに適用します。
オプション 1: ロード バランサーを作成する
次の構成を使用して
loadbalancer.yaml
という名前のファイルを作成します。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
構成を適用してロード バランサー サービスを作成します。
kubectl apply -f loadbalancer.yaml
オプション 2: 既定のロード バランサーにパッチを適用する
BrokerListener
リソースを編集し、serviceType
フィールドをloadBalancer
に変更します。kubectl patch brokerlistener listener --namespace azure-iot-operations --type='json' --patch='[{"op": "replace", "path": "/spec/serviceType", "value": "loadBalancer"}]'
サービスが更新されるまで待ちます。
kubectl get service aio-mq-dmqtt-frontend --namespace azure-iot-operations
出力は次のようになります。
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
外部 IP アドレスを使用して、インターネット経由で MQTT ブローカーに接続できます。
localhost
の代わりに外部 IP アドレスを使用してください。mosquitto_pub --qos 1 --debug -h XXX.XX.X.X --message hello --topic world --username client1 --pw password --cafile ca.crt
ヒント
外部 IP アドレスを使用して、クラスターの外部から MQTT ブローカーに接続できます。 ポート転送オプションで K3d コマンドを使用した場合は、localhost
を使用して MQTT ブローカーに接続できます。 たとえば、mosquitto クライアントと接続するには、次のようにします。
mosquitto_pub --qos 1 --debug -h localhost --message hello --topic world --username client1 --pw password --cafile ca.crt --insecure
この例では、mosquitto クライアントは、ユーザー名とパスワードを使用して、ブローカーを認証します。その際、ブローカーの TLS 証明書チェーンを確認するために、ルート CA 証明書も使用します。 ここでは、ロード バランサーに発行される既定の TLS 証明書が、ロード バランサーの既定のサービス名 (aio-mq-dmqtt-frontend) と割り当てられた IP (localhost ではなく) に対してのみ有効であるため、--insecure
フラグが必要です。
認証と TLS なしで MQTT ブローカーポートをインターネットに公開しないでください。 これは危険であり、IoT デバイスへの不正アクセスを招いたり、未承諾のトラフィックがクラスターに送信されたりする恐れがあります。
セキュリティで保護されていないフラグを使用しないように、証明書のサブジェクトの別名 (SAN) に localhost を追加する方法については、「サーバー証明書パラメーターの構成」を参照してください。
ポート フォワーディングの使用
minikube、kind、およびその他のクラスター エミュレーション システムでは、外部 IP が自動的に割り当てられない可能性があります。 たとえば、保留中状態として表示される場合があります。
ブローカーにアクセスするには、ブローカー リスニング・ポート 8883 をホストに転送します。
kubectl port-forward --namespace azure-iot-operations service/aio-mq-dmqtt-frontend 8883:mqtts-8883
ポート フォワーディングを行わないで、例と同じ認証と TLS 構成を使用する場合、127.0.0.1 を使用してポート 8883 のブローカーに接続します。
ポート フォワーディングは、ブローカーの構成を変更することなく、開発用マシンで MQTT ブローカーをローカルでテストする場合にも役立ちます。 minikube の詳細については、ポート フォワーディングを使用してクラスターにあるアプリケーションにアクセスすることに関する記事をご覧ください
AKS Edge Essentials でのポート フォワーディング
Azure Kubernetes Services Edge Essentials の場合は、いくつかの手順を追加で実行する必要があります。 ポート フォワーディングの詳細については、Expose Kubernetes サービスを外部デバイスに公開するに関する記事をご覧くださいください。
ブローカーのサービスが、ロード バランサーを使用して外部 IP に公開されているとします。 たとえば、既定のロード バランサー
aio-mq-dmqtt-frontend
にパッチを適用した場合は、サービスの外部 IP アドレスを取得します。kubectl get service aio-mq-dmqtt-frontend --namespace azure-iot-operations
出力は次のようになります。
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
外部 IP アドレス
192.168.0.4
とポート8883
で、aio-mq-dmqtt-frontend
サービスへのポート フォワーディングを設定します。netsh interface portproxy add v4tov4 listenport=8883 connectport=8883 connectaddress=192.168.0.4
ファイアウォールでポートを開き、ブローカーのサービスへのトラフィックを許可します。
New-NetFirewallRule -DisplayName "AIO MQTT Broker" -Direction Inbound -Protocol TCP -LocalPort 8883 -Action Allow
ホストのパブリック IP アドレスを使用して MQTT ブローカーに接続します。
TLS と認証なし
MQTT ブローカーが既定で TLS とサービス アカウント認証を使用する理由は、最初からセキュリティで保護されたエクスペリエンスを提供することで、IoT ソリューションが攻撃者に対して不注意にさらされるのを最小限に抑えるためです。 運用環境では TLS と認証をオフにしないでください。
注意事項
運用環境では使用しないでください。 認証と TLS なしで MQTT ブローカーをインターネットに公開すると、不正アクセスや DDOS 攻撃につながる可能性があります。
リスクを理解したうえで、必要があり、管理の行き届いた環境で安全でないポートを使用する場合は、次の手順に従ってテスト目的で TLS と認証をオフにすることができます。
TLS 設定なしで新しい
BrokerListener
リソースを作成します。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
authenticationEnabled
とauthorizationEnabled
フィールドをfalse
に設定すると、認証と承認がオフにされます。port
フィールドを1883
に設定すると、共通の MQTT ポートが使用されます。サービスが更新されるまで待ちます。
kubectl get service my-unique-service-name --namespace azure-iot-operations
出力は次のようになります。
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
新しいポート 1883 が使用できるようになります。
mosquitto クライアントを使用してブローカーに接続します。
mosquitto_pub --qos 1 --debug -h localhost --message hello --topic world
出力は次のようになります。
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