配置 MQTT 代理授权

重要

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

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

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

若要将 BrokerListener 资源链接到 BrokerAuthorization 资源,请在 BrokerListener 资源的 authorizationRef 设置中指定 ports 字段。 与 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
  • 订阅其组织所在范围的 /commands/ 主题。 例如:
    • temperature-sensor 可以订阅 /commands/contoso
    • some-other-username 可以订阅 /commands/contoso

使用用户名进行授权

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

  • Kubernetes SAT - 用户名不应用于授权,因为对于采用增强身份验证的 MQTTv5,用户名无法完成验证。
  • X.509 - 用户名与证书中的公用名 (CN) 相匹配,可用于授权规则。
  • 自定义 - 只有在自定义身份验证将验证用户名的情况下,用户名才可以用于授权规则。

为了防止出现安全问题,只有当可以验证 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"
        }
      ]
    }
  }
]

此处,如果未在 clientIds 方法下设置 Connect,则只要客户端的 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 的授权属性。 例如,若要添加具有值 group 且名为 authz-sat 的授权属性,请运行以下命令:

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 代理 stateStoreResources 配置的 brokerResources 部分下指定键和访问级别。

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 则会在发布被拒绝时返回 PUBACK 及原因代码 135(未授权)。