你当前正在访问 Microsoft Azure Global Edition 技术文档网站。 如果需要访问由世纪互联运营的 Microsoft Azure 中国技术文档网站,请访问 https://docs.azure.cn。
使用 BrokerListener 保护 MQTT 代理通信
重要
本页包含使用 Kubernetes 部署清单(目前为预览版)管理 Azure IoT 操作组件的说明。 此功能存在若干限制,不应该用于生产工作负载。
有关 beta 版本、预览版或尚未正式发布的版本的 Azure 功能所适用的法律条款,请参阅 Microsoft Azure 预览版的补充使用条款。
BrokerListener 对应于通过网络向客户端公开代理的网络终结点。 可以为每个代理提供一个或多个 BrokerListener 资源,每个资源则有多个端口和不同的访问控制。
每个 BrokerListener 端口都可以拥有自己的身份验证和授权规则,以定义谁可以连接到该侦听器端口,以及他们可以对该代理执行的操作。 可以使用 BrokerAuthentication 和 BrokerAuthorization 资源为每个侦听器端口指定访问控制策略。 借助这种灵活性,你可以根据 MQTT 客户端的需求和用例微调 MQTT 客户端的权限和角色。
提示
默认 MQTT 代理部署是一种群集 IP 服务,它要求客户端使用 TLS 进行连接,并使用服务帐户令牌进行身份验证。 从群集外部连接的客户端需要额外的配置,然后才能进行连接。
代理侦听器具有以下特征:
- 名称:侦听器的名称。 如果未被替代,则此名称也是 Kubernetes 服务名称。
- 服务类型:最多可以有三个侦听器,每个服务类型一个。 默认侦听器 为服务类型
ClusterIp
。 - 端口:每个侦听器均支持多个端口。 端口不能因不同侦听器发生冲突。
- 身份验证和授权引用:BrokerAuthentication 和 BrokerAuthorization 是按端口配置的。
- TLS:按端口应用手动或自动 TLS 配置。
- 协议:每个端口都可以启用 WebSockets 上的 MQTT。
有关所有可用设置的列表,请参阅代理侦听器 API 参考。
默认 BrokerListener
部署 Azure IoT 操作时,该部署还会创建名为 default
的 BrokerListener 资源。 此侦听器用于 Azure IoT 操作组件之间的加密内部通信。 默认侦听器是默认代理的一部分。
- 它可在端口 18883 上公开 ClusterIp 服务
- 它要求客户端使用 Kubernetes 服务帐户身份验证
- 它具有自动管理的 TLS 证书
- 它不会配置任何客户端授权策略
注意
为了避免中断内部 Azure IoT 操作通信,请保持默认侦听器不变,并专供内部使用。 对于外部通信,请创建新的侦听器。 如果需要使用 ClusterIp 服务,请将更多端口添加到默认侦听器,而不更改任何现有设置。
要查看或编辑默认侦听器,请:
在 Azure 门户中,导航到 IoT 操作实例。
在“组件”下,选择“MQTT 代理”。
从中转站侦听器列表中选择默认侦听器。
查看侦听器设置,但请避免修改任何现有设置。 请改为创建新的端口,并根据需要对其进行配置。
避免修改默认代理侦听器
要防止中断内部 Azure IoT 操作通信,请保持默认侦听器不变,并专供内部使用。 对于外部通信,请创建新的侦听器。
由于默认代理侦听器使用服务类型 ClusterIp,并且每个服务类型只能有一个侦听器,因此,如果需要使用 ClusterIp 服务,请将更多端口添加到默认侦听器,而不更改任何现有设置。
创建新的中转站侦听器
要创建新的侦听器,请指定以下设置:
- 名称:侦听器的名称。 如果未被替代,则此名称也是 Kubernetes 服务名称。
- 服务类型:Kubernetes 服务的类型。 请参阅服务类型。
- 端口:要侦听的端口列表。 请参阅端口。
- (可选)服务名称:替代 Kubernetes 服务名称。 请参阅服务名称。
示例:创建带有两个端口的新侦听器
此示例演示了如何创建带有负载均衡器服务类型的新侦听器。 BrokerListener 资源可定义两个接口来接受来自客户端的 MQTT 连接。
- 第一个端口侦听端口 1883,而不使用 TLS 和身份验证。 此设置仅适用于测试。 请勿在生产中使用此配置。
- 第二个端口在启用 TLS 和身份验证的情况下侦听端口 8883。 只有具有 Kubernetes 服务帐户令牌且经过身份验证的客户端才能连接。 TLS 设置为自动模式,使用证书管理器来管理来自默认颁发者的服务器证书。 此设置更接近于生产配置。
在 Azure 门户中,导航到 IoT 操作实例。
在“组件”下,选择“MQTT 代理”。
选择 LoadBalancer 的 MQTT 代理监听器>创建。
输入以下设置:
设置 说明 Name BrokerListener 资源的名称。 服务名称 Kubernetes 服务的名称。 留空以将侦听器名称 用作服务名称。 服务类型 已选择 LoadBalancer。 在“端口”下,为第一个端口输入以下设置:
设置 说明 端口 输入 1883 身份验证 选择“无” 授权 选择“无” 协议 选择“MQTT” TLS 请勿添加 选择“添加端口条目”以添加第二个端口并输入以下设置:
设置 说明 端口 输入 8883 身份验证 选择“默认” 授权 选择“无” 协议 选择“MQTT” TLS 选择“添加” 在“TLS 配置”窗格中输入以下设置:
设置 说明 TLS 模式 选择“自动” 颁发者名称 输入 azure-iot-operations-aio-certificate-issuer
证书颁发者类型 选择“ClusterIssuer” 将其他设置保留为默认值,然后选择“应用”。
选择“创建侦听器”。
服务类型
每个 BrokerListener 都会映射到一个 Kubernetes 服务。 服务类型会确定如何向网络公开代理。 支持的服务类型包括:
- ClusterIp:在群集内部 IP 上公开代理。 客户端可以从群集内部连接到代理。 这是默认侦听器的默认服务类型。
- NodePort:在静态端口公开每个节点 IP 上的代理。 客户端可以从群集外部连接到代理。 此服务类型可用于开发和测试。
- LoadBalancer:在外部公开代理。 服务分配有一个外部 IP 地址,客户端可以使用该地址连接到代理。 这是适用于生产部署的最常见服务类型。
每个服务类型仅限一个侦听器
每个服务类型只允许使用一个侦听器。 如果需要建立同一服务类型的更多连接,请将更多端口添加到该服务类型的现有侦听器。
服务名称
服务名称是与代理关联的 Kubernetes 服务的名称。 如果未指定,则代理侦听器名称将用作服务名称。 服务名称在命名空间中必须是唯一的。
提示
为了防止管理开销,建议将服务名称留空。 侦听器名称是唯一的,可用于标识服务。 仅当无法以侦听器命名服务时,才可以使用服务名称作为替代。
端口
每个侦听器可以拥有多个端口,并且每个端口可以拥有自己的身份验证、授权、协议和 TLS 设置。
要对端口使用自己的身份验证或授权设置,必须先创建相应的资源,然后再将其与侦听器一起使用。 有关详细信息,请参阅配置 MQTT 代理身份验证和配置 MQTT 代理授权。
要使用 TLS,请参阅使用自动证书管理配置 TLS 或使用手动证书管理配置 TLS部分。
跨侦听器使用同一端口
不支持跨不同侦听器使用相同的端口号。 每个端口号在 Azure IoT 操作 MQTT 代理中都必须是唯一的。
例如,如果拥有使用端口 1883 的侦听器,则无法使用端口 1883 创建另一个侦听器。 同样,默认侦听器使用端口 18883,因此无法使用端口 18883 创建另一个侦听器。
WebSockets 支持
Azure IoT 操作 MQTT 代理支持 WebSockets 上的 MQTT。 要启用 WebSockets,请将端口的协议设置为 WebSockets
。
使用自动证书管理配置 TLS
若要启用具有自动证书管理的 TLS,请在侦听器端口上指定 TLS 设置。
验证证书管理器安装
借助自动证书管理,可以使用证书管理器管理 TLS 服务器证书。 默认情况下,证书管理器已在cert-manager
命名空间中与 Azure IoT 操作一起安装。 在继续之前验证安装。
使用
kubectl
检查与证书管理器应用标签匹配的 Pod。kubectl get pods --namespace cert-manager -l 'app in (cert-manager,cainjector,webhook)'
NAME READY STATUS RESTARTS AGE aio-cert-manager-64f9548744-5fwdd 1/1 Running 4 (145m ago) 4d20h aio-cert-manager-cainjector-6c7c546578-p6vgv 1/1 Running 4 (145m ago) 4d20h aio-cert-manager-webhook-7f676965dd-8xs28 1/1 Running 4 (145m ago) 4d20h
如果看到显示为就绪且正在运行的 Pod,则已安装证书管理器并可供使用。
提示
要进一步验证安装,请查看证书管理器文档验证安装。 请记住使用cert-manager
命名空间。
为 TLS 服务器证书创建颁发者
证书管理器颁发者资源定义如何自动颁发证书。 证书管理器支持多种本机颁发者类型。 它还支持外部颁发者类型,用于将功能扩展到本机受支持的颁发者之外。 MQTT 代理可用于任何类型的证书管理器颁发者。
重要
在初始部署期间,Azure IoT 操作随 TLS 服务器证书的默认颁发者一起安装。 可以使用此颁发者进行开发和测试。 有关详细信息,请参阅Azure IoT 操作的默认根 CA 和颁发者。 只有当想要使用不同的颁发者时,才需要执行以下步骤。
创建颁发者的方法因场景而异。 以下部分列出了帮助入门的示例。
- 开发或测试
- 生产
CA 颁发者可用于开发和测试。 必须使用 Kubernetes 机密中存储的证书和私钥进行配置。
将根证书设置为 Kubernetes 机密
如有现有的 CA 证书,请使用 CA 证书和 CA 私钥 PEM 文件创建 Kubernetes 机密。 运行以下命令,以将 CA 证书导入为 Kubernetes 机密,并跳过下一部分。
kubectl create secret tls test-ca --cert tls.crt --key tls.key -n azure-iot-operations
如果没有 CA 证书,则证书管理器可以为你生成 CA 证书。 使用证书管理器生成 CA 证书称为使用自签名证书启动 CA 颁发者。
首先创建
ca.yaml
:apiVersion: cert-manager.io/v1 kind: Issuer metadata: name: selfsigned-ca-issuer namespace: azure-iot-operations spec: selfSigned: {} --- apiVersion: cert-manager.io/v1 kind: Certificate metadata: name: selfsigned-ca-cert namespace: azure-iot-operations spec: isCA: true commonName: test-ca secretName: test-ca issuerRef: # Must match Issuer name above name: selfsigned-ca-issuer # Must match Issuer kind above kind: Issuer group: cert-manager.io # Override default private key config to use an EC key privateKey: rotationPolicy: Always algorithm: ECDSA size: 256
使用以下命令创建自签名 CA 证书:
kubectl apply -f ca.yaml
证书管理器使用其默认值创建 CA 证书。 可以修改证书规范以更改此证书的属性。 有关有效选项列表,请参阅证书管理器文档。
分发根证书
前面的示例将 CA 证书存储在名为test-ca
的 Kubernetes 机密中。 可以使用以下命令从机密检索 PEM 格式的证书并将其存储在文件ca.crt
中:
kubectl get secret test-ca -n azure-iot-operations -o json | jq -r '.data["tls.crt"]' | base64 -d > ca.crt
此证书必须由所有客户端分发和信任。 例如,对 mosquitto 客户端使用 --cafile
标志。
基于 CA 证书创建颁发者
证书管理器需要基于在前面的步骤中生成或导入的 CA 证书颁发者。 按issuer-ca.yaml
创建以下文件:
apiVersion: cert-manager.io/v1
kind: Issuer
metadata:
name: my-issuer
namespace: azure-iot-operations
spec:
ca:
# Must match secretName of generated or imported CA cert
secretName: test-ca
使用以下命令创建颁发者:
kubectl apply -f issuer-ca.yaml
前面的命令会创建颁发者以颁发 TLS 服务器证书。 记下颁发者的名称和类型。 在此示例中,名称为 my-issuer
,类型为 Issuer
。 这些值稍后在 BrokerListener 资源中设置。
为端口启用 TLS 自动证书管理功能
下面是 BrokerListener 资源示例,该资源使用自动证书管理在端口 8884 上启用 TLS。
在 Azure 门户中,转到 IoT 操作实例。
在“组件”下,选择“MQTT 代理”。
选择或创建侦听器。 每个服务类型只能创建一个侦听器。 如果已有相同服务类型的侦听器,则可以向现有侦听器添加更多端口。
可以通过选择现有端口上的 TLS 或添加新端口,将 TLS 设置添加到侦听器。
输入以下设置:
设置 说明 Name BrokerListener 资源的名称。 输入 aio-broker-loadbalancer-tls
。端口 BrokerListener 侦听 MQTT 连接的端口号。 输入 8884。 身份验证 身份验证资源参考。 授权 授权资源引用。 TLS 选择“添加”按钮。 颁发者名称 cert-manager 证书颁发者的名称。 必需。 证书颁发者类型 cert-manager 证书颁发者的类型。 必需。 证书颁发者组 cert-manager 证书颁发者组。 必需。 私钥算法 私钥的算法。 私钥轮换策略 用于轮换私钥的策略。 DNS 名称 证书的 DNS 使用者备用名称。 IP 地址 证书使用者备用名称的 IP 地址。 密钥名称 包含 X.509 客户端证书的 Kubernetes 机密。 持续时间 TLS 服务器证书的总生存期默认为 90 天。 续订时间早于 开始续订证书的时间。 选择“应用”以保存 TLS 设置。
配置 BrokerListener 资源后,MQTT 代理会自动创建已启用指定端口和 TLS 的新服务。
可选:配置服务器证书参数
唯一必需的参数是证书颁发者名称和证书颁发者类型。 所生成 TLS 服务器证书的所有其他属性都是自动选择的。 但 MQTT 代理允许按照与证书管理器证书相同的语法自定义某些属性。 例如,可以指定私钥算法和轮换策略。 这些设置位于 Azure 门户中的“tls.certManagerCertificateSpec
”下或“TLS 配置”窗格中。
有关这些设置的完整列表,请参阅代理侦听器 CertManagerCertificateSpec API 参考。
验证部署
使用 kubectl 检查与 BrokerListener 资源关联的服务是否正在运行。 在上面的示例中,服务名称为aio-broker-loadbalancer-tls
,命名空间为azure-iot-operations
。 以下命令检查服务状态:
$ kubectl get service my-new-tls-listener -n azure-iot-operations
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
aio-broker-loadbalancer-tls LoadBalancer 10.X.X.X 172.X.X.X 8884:32457/TCP 33s
使用 TLS 连接到代理
配置服务器证书后,会启用 TLS。 要使用 mosquitto 进行测试:
mosquitto_pub -h $HOST -p 8884 -V mqttv5 -i "test" -t "test" -m "test" --cafile ca.crt
--cafile
参数在 mosquitto 客户端上启用 TLS,并指定客户端应信任给定文件颁发的所有服务器证书。 必须指定文件,其中包含配置的 TLS 服务器证书的颁发者。
将$HOST
替换为相应的主机:
- 如果从同一群集中的进行连接,请替换为给定的服务名称(例如
my-new-tls-listener
)或服务CLUSTER-IP
。 - 如果从群集外部进行连接,请替换为服务
EXTERNAL-IP
。
请记得根据需要指定身份验证方法。
默认根 CA 和颁发者
为了帮助你入门,Azure IoT 操作的部署使用了默认的“快速入门”CA 证书以及 TLS 服务器证书的颁发者。 可以使用此颁发者进行开发和测试。 有关详细信息,请参阅 TLS 服务器证书的默认根 CA 和颁发者。
对于生产,必须使用来自受信任 CA 的证书配置 CA 颁发者,如前面的部分所述。
使用手动证书管理配置 TLS
要手动配置 MQTT 代理以使用特定的 TLS 证书,请通过引用 Kubernetes 机密在 BrokerListener 资源中指定它,然后使用 kubectl 部署它。 本文演示了使用自签名证书配置 TLS 以进行测试的示例。
使用步骤 CLI 创建证书颁发机构
步骤是证书管理器,可在创建和管理自己的专用 CA 时快速启动并运行。
安装步骤 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)。 要通过 Internet 建立连接,请使用外部 IP 添加 --san
。 --no-password --insecure
标志用于测试,以跳过密码提示并禁用私钥的密码保护,因为它存储在 Kubernetes 机密中。 对于生产,请使用密码并将私钥存储在 Azure 密钥保管库等安全位置中。
证书密钥算法要求
支持 EC 和 RSA 密钥,但链中的所有证书都必须使用相同的密钥算法。 如果导入自己的 CA 证书,请确保服务器证书使用与 CA 相同的密钥算法。
将服务器证书链作为 Kubernetes 机密导入
创建完整的服务器证书链,其中证书的顺序很重要:服务器证书是文件中的第一个证书,中间证书是第二个证书。
cat mqtts-endpoint.crt intermediate_ca.crt > server_chain.crt
使用 kubectl 创建包含服务器证书链和服务器密钥的 Kubernetes 机密。
kubectl create secret tls server-cert-secret -n azure-iot-operations \ --cert server_chain.crt \ --key mqtts-endpoint.key
为端口启用 TLS 手动证书管理功能
下面是 BrokerListener 资源示例,该资源使用手动证书管理在端口 8884 上启用 TLS。
在 Azure 门户中,导航到 IoT 操作实例。
在“组件”下,选择“MQTT 代理”。
选择或创建侦听器。 每个服务类型只能创建一个侦听器。 如果已有相同服务类型的侦听器,则可以向现有侦听器添加更多端口。 要遵循该示例,请将侦听器服务名称指定为
mqtts-endpoint
。可以通过选择现有端口上的 TLS 或添加新端口,将 TLS 设置添加到侦听器。
输入以下设置:
设置 说明 端口 BrokerListener 侦听 MQTT 连接的端口号。 必需。 身份验证 身份验证资源参考。 授权 授权资源引用。 TLS 选择“添加”按钮。 密钥名称 包含 X.509 客户端证书的 Kubernetes 机密。 选择“应用”以保存 TLS 设置。
使用 TLS 连接到代理
若要使用 mosquitto 客户端测试 TLS 连接,请发布消息并在参数 --cafile
中传递根 CA 证书。
mosquitto_pub -d -h localhost -p 8885 -i "my-client" -t "test-topic" -m "Hello" --cafile root_ca.crt
如果已启用 MQTT 代理身份验证,请记得指定用户名、密码等。
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
添加转发端口。
注意
要连接到代理,需要将信任根(也称为信任捆绑包)分发所有到客户端。 在这种情况下,信任根是由 Step CLI 创建的自签名根 CA。 客户端需要分发信任根才能验证服务器证书链。 如果 MQTT 客户端是 Kubernetes 群集上的工作负载,则还需要使用根 CA 创建 ConfigMap 并将其装载到 Pod 中。
对服务器证书使用外部 IP
要通过 TLS 在 Internet 上进行连接,MQTT 代理的服务器证书必须将其外部主机名或 IP 地址用作 SAN。 在生产中,这通常是 DNS 名称或已知的 IP 地址。 但是,在开发/测试期间,你可能不知道在部署之前分配了哪些主机名或外部 IP。 要解决此问题,请先部署不带服务器证书的侦听器,然后使用外部 IP 创建服务器证书和机密,再将机密导入侦听器。
如果尝试部署示例 TLS 侦听器manual-tls-listener
但引用的 Kubernetes 机密server-cert-secret
不存在,会创建关联的服务,但 Pod 不会启动。 会创建服务,因为操作员需要为侦听器保留外部 IP。
kubectl get svc mqtts-endpoint -n azure-iot-operations
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
mqtts-endpoint LoadBalancer 10.X.X.X 172.X.X.X 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.
注意
通常,在分布式系统中,Pod 日志具有不确定性,应谨慎使用。 呈现此类信息的正确方法是通过 Kubernetes 事件和自定义资源状态(位于积压工作中)。 将上一步视为临时解决方法。
即使前端 Pod 未启动,外部 IP 也已可用。
kubectl get svc mqtts-endpoint -n azure-iot-operations
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
mqtts-endpoint LoadBalancer 10.X.X.X 172.X.X.X 8885:30674/TCP 1m15s
在此处,按照与之前相同的步骤,在--san
中创建具有此外部 IP 的服务器证书,并采用相同的方式创建 Kubernetes 机密。 创建机密后,它会自动导入到侦听器。