チュートリアル: Azure IoT Operations MQTT ブローカーを使用した TLS、X.509 クライアント認証、属性ベースのアクセス制御 (ABAC) 認可
このチュートリアルでは、TLS 暗号化と X.509 クライアント認証を使用して Azure IoT Operations MQTT ブローカーを設定する手順について説明します。 これには、ブローカーとクライアントの両方の証明書を作成するための詳しい手順とスクリプトが含まれています。 このチュートリアルでは、クライアントとブローカーに対して異なるルート証明機関 (CA) を使用して MQTT ブローカーを構成する方法について説明します。 また、クライアント証明書チェーンに基づく属性ベースのアクセス制御 (ABAC) 認可ポリシーの設定についても説明します。 最後に、このチュートリアルでは、Mosquitto クライアントを使用してさまざまなシナリオをテストし、セットアップが正しく動作することを確かめます。
このチュートリアルでは、Fabrikam によって製造されたデバイスを使用して、Contoso ファクトリに Azure IoT Operations がインストールされている環境をシミュレートします。 TLS と X.509 認証を機能させるには:
- Contoso ファクトリにインストールされている Azure IoT Operations MQTT ブローカーで、Fabrikam ルート CA が信頼されている必要がある
- サーモスタットなどの Fabrikam センサーで、Contoso ルート CA が信頼されている必要がある
- 各エンティティに、正しいルート CA によって発行された独自のリーフ証明書が必要である
前提条件
このチュートリアルを実行するには、次が必要です。
- ポート 8883 に対してポート フォワーディングが有効になっている Kubernetes クラスター。
- 既存のロード バランサー リスナーなしでデプロイされた Azure IoT Operations。
- Kubernetes シークレットと構成マップを作成するためのクラスターへの Kubectl アクセス。
localhost
アクセスのために Kubernetes クラスターと同じマシンで実行されている MQTT メッセージを発行してサブスクライブする Mosquitto クライアント。localhost
を使用しない場合は、「省略可能:localhost
ではなく、実際のホスト名または IP アドレスを使用する」を参照してください。- 証明書を作成するための Step CLI。
ヒント
これらの要件を満たすには、クイックスタートの codespace を使用します。 クイックスタートの codespace では、これらのコンポーネントをすぐに使用できるようにして、セットアップ プロセスを簡略化します。
さらに、公開キーの暗号化と用語 (ルート CA、プライベート キー、中間証明書など) に関する知識が役立ちます。
省略可能: localhost
ではなく、実際のホスト名または IP アドレスを使用する
このチュートリアルをシンプルに保つために、localhost
を使用して MQTT ブローカーにアクセスします。 この方法により、確実にブローカーのサーバー証明書に、ブローカーへのアクセスに使用されるホスト名と一致するサブジェクトの別名 (SAN) が設定されます。 SAN は既に正しく設定されているため、localhost
を使用すると、セットアップが簡略化されます。
実際のシナリオでは、localhost
ではなく、ブローカーのホスト名または外部 IP を使用し、ネットワーク上の別のデバイスから接続します。 この場合は、サーバー証明書を作成するときに、正しいホスト名または IP アドレスを特定し、SAN として使用する必要があります。
- ホスト名または IP アドレスが既にわかっている場合 (たとえば、DNS レコードや静的 IP を通じて) は、サーバー証明書の作成時に SAN として使用します。 その後、
localhost
ではなく、そのホスト名または IP を使用してブローカーに接続します。 - ホスト名や IP アドレスがまだわからない場合は、プレースホルダー サービスを使用して外部 IP アドレスを特定できます。
- 使用されていないポート (8080 など) で LoadBalancer サービスを作成します。
kubectl create service loadbalancer placeholder-service --tcp=8080:8080
- 外部 IP を取得します。
kubectl get svc placeholder-service
- 外部 IP が次のような場合:
192.168.X.X
などの値が表示されている - サーバー証明書とシークレットを作成するときに、その IP を SAN として使用します。 その後、localhost
ではなく、その IP を使用してブローカーに接続します。<pending>
が表示されている - 使用する Kubernetes ディストリビューションでは、外部 IP の自動割り当てがサポートされていない可能性があります。 外部 IP を見つけるには、ご利用のディストリビューションおよびホスト環境に関する Kubernetes ドキュメントの手順に従います。 また、ネットワークのセットアップに応じて、ポート フォワーディングまたは VPN を構成する必要がある場合があります。
- 外部 IP を特定した後、プレースホルダー サービスを削除します。
kubectl delete svc placeholder-service
- 使用されていないポート (8080 など) で LoadBalancer サービスを作成します。
この方法により、確実にサーバー証明書が外部 IP アドレスと一致し、MQTT ブローカーへの安全なアクセスが可能になります。
サーバー側の証明書と完全なチェーンを準備する
まず、サーバー側のルート CA を作成します。 この CA は、後で作成されるクライアント側のルート CA とは別です。 別であることを明確にするために、サーバー側のすべてに "Contoso" という名前を付けます。 後の手順をより簡単にするために、秘密キーを暗号化するためのパスワードはスキップします。 この方法は、チュートリアルの設定でのみ許容されます。
step certificate create "Contoso Root CA" \
contoso_root_ca.crt contoso_root_ca.key \
--profile root-ca \
--no-password --insecure
次に、このルート CA によって署名された中間 CA を作成します。
step certificate create "Contoso Intermediate CA 1" \
contoso_intermediate_ca.crt contoso_intermediate_ca.key \
--profile intermediate-ca \
--ca ./contoso_root_ca.crt --ca-key ./contoso_root_ca.key \
--no-password --insecure
最後に、この中間 CA を使用して、MQTT ブローカーのブローカー フロントエンドのサーバー証明書に署名します。 ここでは、localhost
はこのチュートリアルで使用されるサブジェクトの別名 (SAN) です。
step certificate create mqtts-endpoint \
mqtts-endpoint.crt mqtts-endpoint.key \
--profile leaf \
--ca ./contoso_intermediate_ca.crt --ca-key ./contoso_intermediate_ca.key \
--bundle \
--san localhost \
--not-after 2400h --no-password --insecure
--bundle
フラグを使用すると、サーバー証明書は署名中間証明書にバンドルされます。 TLS ハンドシェイクでは、完全なチェーンを検証するためにバンドルが必要です。
クライアント側の証明書と完全なチェーンを準備する
同様に、Fabrikam のルート CA と中間 CA を作成します。
step certificate create --profile root-ca "Fabrikam Root CA" \
fabrikam_root_ca.crt fabrikam_root_ca.key \
--no-password --insecure
step certificate create "Fabrikam Intermediate CA 1" \
fabrikam_intermediate_ca.crt fabrikam_intermediate_ca.key \
--profile intermediate-ca \
--ca ./fabrikam_root_ca.crt --ca-key ./fabrikam_root_ca.key \
--no-password --insecure
次に、サーモスタット、湿度計、ヒーター、電球のクライアント証明書を生成します。
# Create a client certificate for the thermostat
step certificate create thermostat thermostat.crt thermostat.key \
--ca ./fabrikam_intermediate_ca.crt --ca-key ./fabrikam_intermediate_ca.key --bundle \
--not-after 2400h --no-password --insecure
# Create a client certificate for the hygrometer
step certificate create hygrometer hygrometer.crt hygrometer.key \
--ca ./fabrikam_intermediate_ca.crt --ca-key ./fabrikam_intermediate_ca.key --bundle \
--not-after 2400h --no-password --insecure
# Create a client certificate for the heater
step certificate create heater heater.crt heater.key \
--ca ./fabrikam_intermediate_ca.crt --ca-key ./fabrikam_intermediate_ca.key --bundle \
--not-after 2400h --no-password --insecure
# Create a client certificate for the lightbulb
step certificate create lightbulb lightbulb.crt lightbulb.key \
--ca ./fabrikam_intermediate_ca.crt --ca-key ./fabrikam_intermediate_ca.key --bundle \
--not-after 2400h --no-password --insecure
Kubernetes を構成する
新しく生成されたサーバー証明書と秘密キーを Kubernetes シークレットにインポートします。 このシークレットは、後で MQTT ブローカーの TLS リスナーを構成するために使用されます。
kubectl create secret tls broker-server-cert -n azure-iot-operations \
--cert mqtts-endpoint.crt \
--key mqtts-endpoint.key
また、Fabrikam (クライアント側) ルート CA を含む構成マップを作成します。 この構成マップは、MQTT ブローカーが X.509 認証で信頼するために必要です。
kubectl create configmap fabrikam-ca -n azure-iot-operations \
--from-file=client_ca.pem=fabrikam_root_ca.crt
MQTT ブローカーを構成する
次の手順では、TLS 暗号化と X.509 クライアント認証を使用して MQTT ブローカーを構成します。 このチュートリアルでは、Azure portal を使用して MQTT ブローカーを構成します。
認証
Fabrikam ルート CA によって発行された X.509 証明書を使用してクライアントが認証できるようにするには、Fabrikam ルート CA 証明書を信頼し、クライアント証明書を ABAC の認可属性にマップする認証ポリシーを作成します。
Azure portal で、IoT Operations インスタンスに移動します。
[コンポーネント] で、[MQTT ブローカー] を選択します。
認証 タブを選択します。
[認証ポリシーの作成] を選択します。
[ポリシー名] に「
x509-auth
」と入力します。[方法の追加] を選択して、新しい方法を追加します。
ドロップダウン リストから方法の種類 [X.509] を選択し、[詳細の追加] を選択して方法を構成します。
[X.509 認証の詳細] ペインで、Fabrikam の信頼された CA 証明書の ConfigMap 名
fabrikam-ca
と属性を指定します。{ "trustedClientCaCert": "fabrikam-ca", "authorizationAttributes": { "thermostat": { "subject": "CN = thermostat", "attributes": { "group": "thermostat_group" } }, "hygrometer": { "subject": "CN = hygrometer", "attributes": { "group": "hygrometer_group" } }, "intermediate": { "subject": "CN = Fabrikam Intermediate CA 1", "attributes": { "manufacturer": "fabrikam" } } } }
[適用]、[追加] の順に選択して変更を保存します。
リスナー
認証ポリシーを設定した状態で、X.509 認証ポリシーを使用するリスナーを作成します。 また、X.509 認証には TLS が必要であるため、先ほど作成した Contoso サーバー証明書と秘密キーを使用するようにリスナーを構成します。
Azure portal で、IoT Operations インスタンスに移動します。
[コンポーネント] で、[MQTT ブローカー] を選択します。
[LoadBalancer の MQTT ブローカー リスナー]>[作成] を選択します。 次の情報を入力します :
設定 内容 Name 「 mqtts-endpoint
」と入力します。サービス名 Kubernetes サービスの名前。 リスナー名 mqtts-endpoint
をサービス名として使用する場合は、空のままにします。サービスの種類 LoadBalancer が既に選択されています。 [ポート] で、最初のポート用に次の設定を入力します。
設定 説明 ポート 「8883」と入力します 認証 [x509-auth] を選びます 承認 [なし] を選択します Protocol [MQTT] を選択します TLS [追加] を選択します。 [TLS 構成] ペインで、次の設定を入力します。
設定 説明 TLS モード [手動] を選びます 発行者名 「 broker-server-cert
」と入力します[適用] と [リスナーの作成] を選択します。
1、2 分後に、mqtts-endpoint
LoadBalancer サービスが作成されます。
$ kubectl get service mqtts-endpoint -n azure-iot-operations
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
mqtts-endpoint LoadBalancer 10.43.28.140 XXX.XX.X.X 8883:30988/TCP 104s
このチュートリアルでは、外部 IP を使用する代わりに、localhost
を使用します。
ヒント
codespace 構成では、8883 のポート フォワーディングが自動的に設定されます。 その他の環境をセットアップする場合は、「ポート フォワーディングを使用する」を参照してください。
単一の Mosquito クライアントを使用して TLS 経由でメッセージを発行する
証明書ファイル (contoso_root_ca.crt
、thermostat.crt
、thermostat.key
) と同じフォルダーから、Mosquito クライアントを使用してメッセージを発行します。 --cafile contoso_root_ca.crt
フラグは、Mosquito でサーバー証明書の検証を実行するためのものです。
mosquitto_pub -t "example/topic" -m "example temperature measurement" -i thermostat \
-q 1 -V mqttv5 -d \
-h localhost \
--key thermostat.key \
--cert thermostat.crt \
--cafile contoso_root_ca.crt
発行は成功します。これは、Mosquito で fabrikam_root_ca.crt
にルート化されたクライアント証明書を使用するためです。 x509-auth
認証ポリシーは以前に作成されているため、MQTT ブローカーはこの証明書を信頼します。 さらに、MQTT ブローカーは現在、認証されたクライアントが任意のトピックに発行することを許可しています。
Client thermostat sending CONNECT
Client thermostat received CONNACK (0)
Client thermostat sending PUBLISH (d0, q1, r0, m1, 'example/topic', ... (31 bytes))
Client thermostat received PUBACK (Mid: 1, RC:0)
Client thermostat sending DISCONNECT
X.509 を使用して複数のクライアントの MQTT トピックへの認可を構成する
クライアント証明書属性に基づいて MQTT トピックへのアクセスを制限するには、クライアント証明書属性を特定のトピックで許可されるアクションにマップする認可ポリシーを作成します。
Azure portal で、IoT Operations インスタンスに移動します。
[コンポーネント] で、[MQTT ブローカー] を選択します。
承認タブを選択します。
[認可ポリシーの作成] を選択します。
[ポリシー名] に「
abac-authz
」と入力します。[規則] で、次の規則を入力します。
[ { "principals": { "attributes": [ { "group": "thermostat_group" } ] }, "brokerResources": [ { "method": "Connect" }, { "method": "Publish", "topics": [ "telemetry/temperature" ] } ] }, { "principals": { "attributes": [ { "group": "hygrometer_group" } ] }, "brokerResources": [ { "method": "Connect" }, { "method": "Publish", "topics": [ "telemetry/humidity" ] } ] }, { "principals": { "attributes": [ { "manufacturer": "fabrikam" } ] }, "brokerResources": [ { "method": "Connect" }, { "method": "Publish", "topics": [ "health/heartbeat" ] } ] }, { "principals": { "usernames": [ "heater" ] }, "brokerResources": [ { "method": "Connect" }, { "method": "Subscribe", "topics": [ "telemetry/temperature", "telemetry/humidity" ] } ] } ]
[追加] を選択して変更内容を保存します。
次に、新しい認可ポリシーを使用するように MQTT ブローカー リスナーを更新します。
- [リスナー] タブを選択します。
- [mqtts-endpoint] リスナーを選択します。
- [ポート]>[8883]>[認可] で、[abac-authz] を選びます。
- [保存] を選択します。
制限付きトピックにメッセージを発行する
このセクションでは、新しく適用された認可ポリシーをテストします。
まず、thermostat
に接続し、トピック telemetry/humidity
で発行してみます。
mosquitto_pub -t "telemetry/humidity" -m "example temperature measurement" -i thermostat \
-q 1 -V mqttv5 -d \
-h localhost \
--key thermostat.key \
--cert thermostat.crt \
--cafile contoso_root_ca.crt
thermostat
は thermostat_group
の一部であり、湿度トピックへの発行は許可されていないため、発行は失敗します。
Client thermostat sending CONNECT
Client thermostat received CONNACK (0)
Client thermostat sending PUBLISH (d0, q1, r0, m1, 'telemetry/humidity', ... (6 bytes))
Client thermostat received PUBACK (Mid: 1, RC:135)
Warning: Publish 1 failed: Not authorized.
telemetry/temperature
に発行するように変更します。これは許可され、発行は成功します。 コマンドは実行したままにします。
mosquitto_pub -t "telemetry/temperature" -m "example temperature measurement" -i thermostat \
-q 1 -V mqttv5 -d \
-h localhost \
--repeat 10000 \
--repeat-delay 3 \
--key thermostat.key \
--cert thermostat.crt \
--cafile contoso_root_ca.crt
制限付きトピックのメッセージをサブスクライブする
別のターミナル セッションで、heater
に接続して health/heartbeat
をサブスクライブします。
mosquitto_sub -q 1 -t "health/heartbeat" -d -V mqttv5 \
-i heater \
-h localhost \
--key heater.key \
--cert heater.crt \
--cafile contoso_root_ca.crt
heater
はハートビート トピックをサブスクライブする権限がないため、サブスクリプションは失敗します。 ここで、コード 135 は認可されていないことを意味します。
Client heater sending CONNECT
Client heater received CONNACK (0)
Client heater sending SUBSCRIBE (Mid: 1, Topic: health/heartbeat, QoS: 1, Options: 0x00)
Client heater received SUBACK
Subscribed (mid: 1): 135
サブスクリプション トピックを telemetry/temperature
に切り替えます。thermostat
はまだメッセージを送信しています。
mosquitto_sub -q 1 -t "telemetry/temperature" -d -V mqttv5 \
-i heater \
-h localhost \
--key heater.key \
--cert heater.crt \
--cafile contoso_root_ca.crt
heater
は、ユーザー名で認可されているため、ここでメッセージの受信を開始します。
"もう 1 つの" 別のターミナル セッションで、lightbulb
を使用してメッセージを health/heartbeat
に発行します。
mosquitto_pub -q 1 -t "health/heartbeat" -m "example heartbeat" -d -V mqttv5 \
-i lightbulb \
-h localhost \
--repeat 100 \
--repeat-delay 3 \
--key lightbulb.key \
--cert lightbulb.crt \
--cafile contoso_root_ca.crt
lightbulb
には、属性 manufacturer=fabrikam
にマップされた CN = Fabrikam Intermediate CA 1
の中間証明書があるため、発行は成功します。 その属性を持つクライアントは、health/heartbeat
に発行できます。 クライアントがメッセージの送信を開始すると、先ほど開始した heater
は何も受信しません。
リソースをクリーンアップする
このチュートリアルで作成したリソースをクリーンアップするには、リスナーと認証および認可ポリシーを削除します。
- Azure portal で、IoT Operations インスタンスに移動します。
- [コンポーネント] で、[MQTT ブローカー] を選択します。
- [リスナー] タブを選択します。
- [mqtts-endpoint] リスナーの横にあるチェックボックスをオンにします。
- [削除] を選択します。
- 削除を確認します。
- 認証 タブを選択します。
- [x509-auth] の横にあるチェックボックスをオンにします。
- [削除] を選択します。
- 削除を確認します。
- 承認タブを選択します。
- [abac-authz] の横にあるチェックボックスをオンにします。
- [削除] を選択します。
- 削除を確認します。
また、Kubernetes シークレットと構成マップを削除します。
kubectl delete secret broker-server-cert -n azure-iot-operations
kubectl delete configmap fabrikam-ca -n azure-iot-operations
最後に、先ほど生成した証明書とキーを削除します。
rm contoso_root_ca.crt contoso_root_ca.key contoso_intermediate_ca.crt contoso_intermediate_ca.key mqtts-endpoint.crt mqtts-endpoint.key
rm fabrikam_root_ca.crt fabrikam_root_ca.key fabrikam_intermediate_ca.crt fabrikam_intermediate_ca.key thermostat.crt thermostat.key hygrometer.crt hygrometer.key heater.crt heater.key lightbulb.crt lightbulb.key