MQTT ブローカーで MQTT 通信をセキュリティで保護するために、手動の証明書管理で TLS を構成する
重要
Azure Arc によって有効にされる Azure IoT Operations Preview は、現在プレビュー段階です。 運用環境ではこのプレビュー ソフトウェアを使わないでください。
一般提供リリースが利用可能になったタイミングで新しい Azure IoT Operations のインストールをデプロイする必要があります。 プレビュー インストールをアップグレードすることはできません。
ベータ版、プレビュー版、または一般提供としてまだリリースされていない Azure の機能に適用される法律条項については、「Microsoft Azure プレビューの追加使用条件」を参照してください。
BrokerListener リソースを使用して、MQTT ブローカーとクライアントの間の MQTT 通信をセキュリティで保護するように TLS を構成できます。 手動または自動の証明書管理で TLS を構成できます。
特定の TLS 証明書を使用するように MQTT ブローカーを手動で構成するには、Kubernetes シークレットへの参照を使用して BrokerListener リソース内でこれを指定します。 次に、kubectl を使用してそれをデプロイします。 この記事では、テスト用の自己署名証明書を使用して TLS を構成する例を示します。
Step CLI を使用して証明機関を作成する
Step は、独自のプライベート CA を作成および管理するときにすぐに起動して実行できる証明書マネージャーです。
Step CLI をインストールし、ルート証明機関 (CA) の証明書とキーを作成します。
step certificate create --profile root-ca "Example Root CA" root_ca.crt root_ca.key
ルート CA によって署名された中間 CA 証明書とキーを作成します。
step certificate create --profile intermediate-ca "Example Intermediate CA" intermediate_ca.crt intermediate_ca.key \ --ca root_ca.crt --ca-key root_ca.key
サーバー証明書を作成する
手順 CLI を使用して、中間 CA によって署名されたサーバー証明書を作成します。
step certificate create mqtts-endpoint mqtts-endpoint.crt mqtts-endpoint.key \
--profile leaf \
--not-after 8760h \
--san mqtts-endpoint \
--san localhost \
--ca intermediate_ca.crt --ca-key intermediate_ca.key \
--no-password --insecure
ここで、mqtts-endpoint
と localhost
は、それぞれ Kubernetes およびローカル クライアントにおける MQTT ブローカーのフロントエンドのサブジェクトの別名 (SAN) です。 インターネット経由で接続するには、--san
に外部 IP を追加します。 --no-password --insecure
フラグは、パスワード プロンプトをスキップして秘密キーのパスワード保護を無効にするためにテスト目的で使用されます。その理由は、秘密キーが Kubernetes シークレットに格納されるためです。 運用環境では、パスワードを使用し、秘密キーを Azure Key Vault などの安全な場所に格納します。
証明書キー アルゴリズムの要件
EC キーと RSA キーの両方がサポートされていますが、チェーン内のすべての証明書で同じキー アルゴリズムを使用する必要があります。 独自の CA 証明書をインポートする場合、サーバー証明書では CA と同じキー アルゴリズムを使ってください。
サーバー証明書チェーンを Kubernetes シークレットとしてインポートする
完全なサーバー証明書チェーンを作成します。ここでは証明書の順序が重要です。サーバー証明書はファイルの最初、中間は 2 番目になります。
cat mqtts-endpoint.crt intermediate_ca.crt > server_chain.pem
kubectl を使用して、サーバー証明書チェーンとサーバー キーを持つ Kubernetes シークレットを作成します。
kubectl create secret tls server-cert-secret -n azure-iot-operations \ --cert server_chain.crt \ --key mqtts-endpoint.key
リスナーの TLS を有効にする
BrokerListener リソースの tls
設定を変更して、Kubernetes シークレットを参照する手動 TLS 構成を指定します。 TLS サーバー証明書に使用されるシークレットの名前をメモします (前の例の server-cert-secret
)。
apiVersion: mqttbroker.iotoperations.azure.com/v1beta1
kind: BrokerListener
metadata:
name: manual-tls-listener
namespace: azure-iot-operations
spec:
brokerRef: broker
serviceType: loadBalancer # Optional, defaults to clusterIP
serviceName: mqtts-endpoint # Match the SAN in the server certificate
ports:
port: 8885 # Avoid port conflict with default listener at 8883
tls:
manual:
mode: Manual
secretName: server-cert-secret
BrokerListener リソースが作成されると、オペレーターは自動的に Kubernetes サービスを作成し、リスナーをデプロイします。 kubectl get svc
を実行して、サービスの状態を確認できます。
TLS を使用してブローカーに接続する
mosquitto クライアントとの TLS 接続をテストするには、メッセージを発行し、パラメータ --cafile
にルート CA 証明書を渡します。
mosquitto_pub -d -h localhost -p 8885 -i "my-client" -t "test-topic" -m "Hello" --cafile root_ca.crt
Client my-client sending CONNECT
Client my-client received CONNACK (0)
Client my-client sending PUBLISH (d0, q0, r0, m1, 'test-topic', ... (5 bytes))
Client my-client sending DISCONNECT
ヒント
localhost を使用するには、ホスト コンピューターでポートを使用できる必要があります。 たとえば、kubectl port-forward svc/mqtts-endpoint 8885:8885 -n azure-iot-operations
のようにします。 K3d のような一部の Kubernetes ディストリビューションでは、k3d cluster edit $CLUSTER_NAME --port-add 8885:8885@loadbalancer
で転送されたポートを追加できます。
Note
ブローカーに接続するには、信頼のルートをクライアント (信頼バンドルとも呼ばれます) に配布する必要があります。 この場合、信頼のルートは自己署名ルート CA によって作成されたステップ CLI です。 クライアントがサーバー証明書チェーンを検証するには、信頼のルートの配布が必要です。 MQTT クライアントが Kubernetes クラスター上のワークロードである場合は、ルート CA を使用して ConfigMap を作成し、ポッドにマウントする必要もあります。
MQTT ブローカー認証が有効になっている場合は、必ずユーザー名やパスワードなどを指定してください。
サーバー証明書に対して外部 IP を使用する
TLS を使用してインターネット経由で接続するには、MQTT ブローカーのサーバー証明書に SAN としての外部ホスト名が必要です。 運用環境では、これは通常、DNS 名または既知の IP アドレスです。 ただし、開発/テスト中は、デプロイ前に割り当てられているホスト名または外部 IP がわからない場合があります。 これを解決するには、まずサーバー証明書なしでリスナーをデプロイし、次に外部 IP を使用してサーバー証明書とシークレットを作成し、最後にシークレットをリスナーにインポートします。
TLS リスナーのサンプル manual-tls-listener
をデプロイしようとしても、参照先の Kubernetes シークレット server-cert-secret
が存在しない場合は、関連付けられたサービスが作成されますが、ポッドは起動しません。 サービスが作成されるのは、オペレーターがリスナーの外部 IP を予約する必要があるためです。
kubectl get svc mqtts-endpoint -n azure-iot-operations
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
mqtts-endpoint LoadBalancer 10.43.93.6 172.18.0.2 8885:30674/TCP 1m15s
ただし、これは想定された動作であり、サーバー証明書をインポートする限り、そのままにしても問題ありません。 正常性マネージャー ログに、MQTT ブローカーがサーバー証明書を待機中であることが示されています。
kubectl logs -l app=health-manager -n azure-iot-operations
...
<6>2023-11-06T21:36:13.634Z [INFO] [1] - Server certificate server-cert-secret not found. Awaiting creation of secret.
Note
一般に、分散システムでは、ポッド ログは決定論的ではないため、慎重に使用する必要があります。 このような情報を表示する正しい方法は、Kubernetes イベントとカスタム リソースの状態 (バックログ内) を使用することです。 前の手順は、一時的な回避策と考えてください。
フロントエンド ポッドが稼働していない場合でも、外部 IP は既に使用できます。
kubectl get svc mqtts-endpoint -n azure-iot-operations
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
mqtts-endpoint LoadBalancer 10.43.93.6 172.18.0.2 8885:30674/TCP 1m15s
ここから、前と同じ手順に従って、--san
でこの外部 IP を使用してサーバー証明書を作成し、同じ方法で Kubernetes シークレットを作成します。 シークレットが作成されると、リスナーに自動的にインポートされます。