你当前正在访问 Microsoft Azure Global Edition 技术文档网站。 如果需要访问由世纪互联运营的 Microsoft Azure 中国技术文档网站,请访问 https://docs.azure.cn

配置 MQTT 代理授权

重要

本页包含使用 Kubernetes 部署清单(目前为预览版)管理 Azure IoT 操作组件的说明。 此功能存在若干限制,不应该用于生产工作负载。

有关 beta 版本、预览版或尚未正式发布的版本的 Azure 功能所适用的法律条款,请参阅 Microsoft Azure 预览版的补充使用条款

授权策略确定客户端可以在代理上执行的操作,例如连接、发布或订阅主题。 将 MQTT 代理配置为将一个或多个授权策略与 BrokerAuthorization 资源配合使用。 每个 BrokerAuthorization 资源都包含一个规则列表,用于指定授权策略的主体和资源。

若要将 BrokerListener 链接到 BrokerAuthorization 资源,请在 BrokerListener 资源的 ports 设置中指定 authorizationRef 字段。 与 BrokerAuthentication 类似,BrokerAuthorization 资源可以链接到多个 BrokerListener 端口。 授权策略适用于所有链接的侦听器端口。 但是,与 BrokerAuthentication 相比,存在一个关键差异:

重要

若要将 BrokerAuthorization 配置应用于侦听器端口,还必须将至少一个 BrokerAuthentication 链接到该侦听器端口。

若要了解 BrokerListener 的详细信息,请参阅 BrokerListener 资源。

授权规则

若要配置授权策略,首先需要在 Kubernetes 群集中创建 BrokerAuthorization 资源。 以下部分提供了有关如何为使用用户名、属性、X.509 证书和 Kubernetes 服务帐户令牌 (SAT) 的客户端配置授权的示例。 有关可用设置的列表,请参阅代理身份验证 API 参考。

以下示例演示如何使用用户名和属性创建 BrokerAuthorization 资源:

  1. 在 Azure 门户中,导航到 IoT 操作实例。

  2. 在“组件”下,选择“MQTT 代理”

  3. 选择授权选项卡。

  4. 选择现有身份验证策略,或通过选择“创建授权策略”来创建新的身份验证策略

    使用 Azure 门户创建代理授权规则的屏幕截图。

此代理授权允许具有客户端 ID temperature-sensorhumidity-sensor 的客户端,或者具有属性 organization(值为 contoso)的客户端和具有属性 city(值为 seattle)的客户端:

  • 连接到中转站。
  • 将消息发布到其客户端 ID 和组织所在范围的遥测主题。 例如:
    • temperature-sensor 可以发布到 /telemetry/temperature-sensor/telemetry/contoso
    • humidity-sensor 可以发布到 /telemetry/humidity-sensor/telemetry/contoso
    • some-other-username 可以发布到 /telemetry/contoso
  • 订阅其组织所在范围的命令主题。 例如:
    • temperature-sensor 可以订阅 /commands/contoso
    • some-other-username 可以订阅 /commands/contoso

使用用户名进行授权

若要使用 MQTT 用户名进行授权,请将其以数组的形式指定在 principals.usernames 下。 但是,根据身份验证方法的不同,用户名可能无法验证:

  • Kubernetes SAT - 用户名不应用于授权,因为它未经过具有增强身份验证的 MQTTv5 的验证。
  • X.509 - 用户名与证书中的公用名相匹配,可用于授权规则。
  • 自定义 - 只有在自定义身份验证验证用户名的情况下,用户名才可以用于授权规则。

为了防止出现安全问题,只有当 MQTT 用户名可以验证时,才能将其用于代理授权。

根据客户端 ID 进一步限制访问

由于 principals 字段是逻辑 OR,因此可以通过将 clientIds 字段添加到 brokerResources 字段来进一步限制基于客户端 ID 的访问。 例如,若要允许客户端 ID 以生成编号开头的客户端连接遥测数据并将其发布到其生成范围的主题,请使用以下配置:

在授权策略的代理授权规则中,使用以下配置:

[
  {
    "brokerResources": [
      {
        "clientIds": [
          "{principal.attributes.building}*"
        ],
        "method": "Connect",
        "topics": []
      },
      {
        "clientIds": [],
        "method": "Publish",
        "topics": [
          "sensors/{principal.attributes.building}/{principal.clientId}/telemetry"
        ]
      }
    ],
    "principals": {
      "attributes": [
        {
          "building": "building22"
        },
        {
          "building": "building23"
        }
      ]
    }
  }
]

此处,如果未在 Connect 方法下设置 clientIds,则只要客户端的 building 属性设置为 building22building23,则具有任何客户端 ID 的客户端就可以进行连接。 通过添加 clientIds 字段,只有客户端 ID 以 building22building23 开头的客户端才能连接。 这不仅可以确保客户端具有正确的属性,而且还确保客户端 ID 与预期模式匹配。

授权使用 X.509 身份验证的客户端

使用 X.509 证书进行身份验证的客户端可被授权访问其证书上基于 X.509 属性或其链上颁发证书的资源。

使用属性

若要基于客户端证书的属性、其根 CA 或中间 CA 创建规则,请在 BrokerAuthorization 资源中定义 X.509 属性。 有关详细信息,请参阅证书属性

使用客户端证书主体公用名作为用户名

若要仅基于客户端证书主体公用名 (CN) 创建授权策略,请基于 CN 创建规则。

例如,如果客户端具有主体为 CN = smart-lock 的证书,则其用户名为 smart-lock。 然后,像平时一样创建授权策略。

授权使用 Kubernetes 服务帐户令牌的客户端

在“服务帐户注释”中设置 SAT 的授权属性。 例如,若要添加具有值 authz-sat 且名为 group 的授权属性,请运行以下命令:

kubectl annotate serviceaccount mqtt-client aio-broker-auth/group=authz-sat

属性注释必须以 aio-broker-auth/ 开头,以便将其与其他注释区分开来。

由于应用程序具有名为 authz-sat 的授权属性,因此无需提供 clientIdusername。 相应的 BrokerAuthorization 资源使用此属性作为主体,例如:

在授权策略的代理授权规则中,使用以下配置:

[
  {
    "brokerResources": [
      {
        "clientIds": [],
        "method": "Connect",
        "topics": []
      },
      {
        "clientIds": [],
        "method": "Publish",
        "topics": [
          "odd-numbered-orders"
        ]
      },
      {
        "clientIds": [],
        "method": "Subscribe",
        "topics": [
          "orders"
        ]
      }
    ],
    "principals": {
      "attributes": [
        {
          "group": "authz-sat"
        }
      ]
    }
  }
]

若要详细了解示例,请参阅使用 Dapr 客户端设置授权策略

状态存储

MQTT 代理会提供一个可供客户端用于存储状态的状态存储。 状态存储也可以配置为高度可用。

若要为使用状态存储的客户端设置授权,请提供以下权限:

  • 要发布到系统密钥值存储 $services/statestore/_any_/command/invoke/request 主题的权限
  • 用于订阅响应主题(是在初始发布期间作为参数来设置的)<response_topic>/# 的权限

状态存储键

状态存储是通过 MQTT 代理在主题 statestore/v1/FA9AE35F-2F64-47CD-9BFF-08E2B32A0FE8/command/invoke 上进行访问的。 由于客户端有权访问该主题,因此可以在 MQTT 代理 brokerResources 配置的 stateStoreResources 部分下指定键和访问级别。

stateStoreResources 部分格式包括访问级别、模式指示器和模式。

stateStoreResources 部分包含在授权策略的规则中。

"stateStoreResources": [
  {
    "method": "", // Values: read, write, readwrite 
    "keyType": "", //Values: string, pattern, binary. Default is pattern
    "keys": [
      // List of patterns to match
    ]
  },
]

method 字段指定访问级别。

  • 读取访问通过 read 指定,写入权限通过 write,读写访问权限通过 readwrite
  • 访问级别是必需的。
  • 读取访问级别意味着可以执行 getkeynotify 操作。
  • 写入访问级别意味着可以执行 setdelvdel 操作。

keyType 字段指定键匹配的类型。

  • pattern 使用 glob 样式模式匹配
  • 使用 string 进行精确匹配,例如,当键包含可能作为模式匹配的字符时(*?[0-9]
  • 使用 binary 来匹配二进制键

keys 字段指定要匹配的键。 可以将这些键指定为 Glob 样式模式、令牌替换或确切字符串

  • Glob 样式示例
    • colors/*:所有前缀为“colors/”的键
    • number[0-9]:从“number0”到“number9”的任意键
    • char?:前缀为“char”且后缀为单个数字的任意键,如“charA”
    • *:对所有键的完全访问权限。
  • 当键类型为 pattern 时,状态存储键还支持令牌替换,并为此保留大括号。 令牌替换示例:
    • clients/{principal.clientId}/*
    • usernames/{principal.username}/*
    • rooms/{principal.attributes.room}/*

下面是如何创作状态存储资源的示例:

在授权策略的代理授权规则中,添加类似的配置:

[
  {
    "brokerResources": [
      {
        "clientIds": [
          "{principal.attributes.building}*"
        ],
        "method": "Connect"
      },
      {
        "method": "Publish",
        "topics": [
          "sensors/{principal.attributes.building}/{principal.clientId}/telemetry/*"
        ]
      },
      {
        "method": "Subscribe",
        "topics": [
          "commands/{principal.attributes.organization}"
        ]
      }
    ],
    "principals": {
      "attributes": [
        {
          "building": "17",
          "organization": "contoso"
        }
      ],
      "usernames": [
        "temperature-sensor",
        "humidity-sensor"
      ]
    },
    "stateStoreResources": [
      {
        "method": "Read",
        "keyType": "Pattern",
        "keys": [
          "myreadkey",
          "myotherkey?",
          "mynumerickeysuffix[0-9]",
          "clients/{principal.clientId}/*"
        ]
      },
      {
        "method": "ReadWrite",
        "keyType": "Binary",
        "keys": [
          "xxxxxxxxxxxxxxxxxxxx"
        ]
      }
    ]
  }
]

更新授权

代理授权资源可以在运行时更新,而无需重启。 策略更新时连接的所有客户端都会断开连接。 还支持更改策略类型。

kubectl edit brokerauthorization my-authz-policies

禁用授权

  1. 在 Azure 门户中,导航到 IoT 操作实例。
  2. 在“组件”下,选择“MQTT 代理”
  3. 从列表中选择要编辑的代理侦听器。
  4. 在要禁用授权的端口上,在授权下拉列表中选择“无”。

MQTT 3.1.1 中未经授权的发布

使用 MQTT 3.1.1 时,若发布被拒绝,客户端会收到 PUBACK,而不会收到错误代码,因为协议版本不支持返回错误代码。 当发布被拒绝时,MQTTv5 返回原因代码为 135(未授权)的 PUBACK。