共用方式為


設定 MQTT 代理授權

重要事項

本頁包含使用 Kubernetes 部署清單管理 Azure IoT Operations 元件的說明,該清單已在預覽中。 此功能的提供具有數項限制,因此不應用於生產工作負載。

請參閱 Microsoft Azure 預覽版增補使用規定,以了解適用於 Azure 功能 (搶鮮版 (Beta)、預覽版,或尚未正式發行的版本) 的法律條款。

授權原則會決定用戶端可以在訊息代理程式上執行的動作,例如連線、發佈或訂閱主題。 設定 MQTT 代理以使用一或多個授權原則搭配 BrokerAuthorization 資源。 每個 BrokerAuthorization 資源都包含一份規則清單,其會指定授權原則的主體和資源。

如何評估規則

  • 原則為僅允許。 如果沒有規則明確允許對主體的資源執行動作,則會拒絕該動作。
  • 規則由三個因素定義:主體 (動作者)、動作 (連線/發佈/訂閱或狀態存放區作業) 和資源 (主題或索引鍵)。
  • 規則內的主體會使用邏輯 OR 比對。 例如,任何列出的使用者名稱、clientId 或屬性相符都會授與規則中資源的存取權。

權杖替換和萬用字元

  • 對於主題和索引鍵,您可以使用權杖替代來建立適合每個用戶端的規則:{principal.username}{principal.clientId}{principal.attributes.<attributeName>}
  • + 中支援 MQTT 主題萬用字元 #brokerResources.topics
  • 在主題中使用權杖替代時,權杖必須是其路徑區段中唯一的文字。 例如,clients/{principal.clientId}/# 有效,但 client-{principal.clientId}/# 無效。
  • 連線動作不應包含主題。

若要將 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 入口網站來建立代理程式授權規則的螢幕擷取畫面。

此代理程式授權會允許具有用戶端識別碼 temperature-sensorhumidity-sensor 的用戶端,或具有 organization 屬性且值為 contosocity,以及值 seattle 的用戶端,執行下列動作:

  • 連線到訊息代理程式。
  • 將訊息發佈到範圍限定在用戶端識別碼和組織的主題。 例如:
    • temperature-sensor 可以發佈至 /sensor/temperature-sensor/sensor/contoso
    • humidity-sensor 可以發佈至 /sensor/humidity-sensor/sensor/contoso
    • some-other-username 可以發佈至 /sensor/contoso
  • 訂閱範圍限定在組織的 /commands/ 主題。 例如:
    • temperature-sensor 可以訂閱 /commands/contoso
    • some-other-username 可以訂閱 /commands/contoso

使用使用者名稱進行授權

若要使用 MQTT 使用者名稱進行授權,請將它們指定為 principals.usernames 下的陣列。 根據驗證方法,可能無法驗證使用者名稱:

  • Kubernetes SAT:使用者名稱不應用於授權,因為它未針對具有增強式驗證的 MQTTv5 進行驗證。
  • X.509:使用者名稱符合憑證的一般名稱 (CN),並可用於授權規則。
  • 自訂:只有在自訂驗證可驗證使用者名稱時,才應該將使用者名稱用於授權規則。

若要防止安全性問題,請只在可以驗證時,才使用 MQTT 使用者名稱進行代理程式授權。

小提示

若要要求 MQTT 使用者名稱符合用戶端識別碼,請使用權杖取代:

principals:
  usernames:
    - "{principal.clientId}"

根據用戶端識別碼進一步限制存取

因為 principals 欄位是邏輯 OR,因此您可以藉由將 clientIds 欄位新增至 brokerResources 欄位,以根據用戶端識別碼進一步限制存取。 例如,若要允許用戶端識別碼開頭為大樓編號的用戶端,可連線並發佈至範圍限定在其大樓的主題,請使用下列設定:

在授權原則的代理程式授權規則中,使用下列設定:

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

在這裡,如果未在 clientIds 方法下設定 Connect,只要用戶端的 building 屬性設定為 building22building23,具有任何用戶端識別碼的用戶端就可以連線。 當您新增 clientIds 欄位時,只有用戶端識別碼開頭為 building22building23 的用戶端可以連線。 此指定可確保用戶端具有正確的屬性,且用戶端識別碼符合預期的模式。

授權使用 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 代理程式提供狀態存放區,用戶端可用來儲存狀態。 您也可以將狀態存放區設定為高度可用。

若要為使用狀態存放區的用戶端設定授權,請提供通訊協定主題和索引鍵的權限:

  • 發佈要求至:statestore/v1/FA9AE35F-2F64-47CD-9BFF-08E2B32A0FE8/command/invoke
  • 訂閱您在發佈時設定的回應主題,通常為:clients/{principal.clientId}/services/statestore/v1/FA9AE35F-2F64-47CD-9BFF-08E2B32A0FE8/command/invoke/response/#
  • 根據以下指導授與 stateStoreResources 下的索引鍵存取權。

狀態存放區索引鍵

狀態存放區是透過主題 statestore/v1/FA9AE35F-2F64-47CD-9BFF-08E2B32A0FE8/command/invoke 上的 MQTT 代理程式存取。 由於用戶端可以存取主題,因此您可以在 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}/sensor/*"
        ]
      },
      {
        "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

快取行為

若要減少高輸送量主題上的授權額外負荷,請使用 authorizationPolicies.cache: Enabled 啟用記憶體內快取。

  • 決策會依用戶端、動作和資源的 Tuple 快取。 重複的操作會命中快取。
  • 高度變動的資源 (例如,每個訊息的唯一主題區段) 會降低快取命中率。
  • 快取會隨著唯一 Tuple 的數目而成長。 監視記憶體是否有非常高的流失模式。

停用授權

  1. 在 Azure 入口網站中,移至您的 IoT 操作執行個體。
  2. 在 [元件] 底下,選取 [MQTT 代理程式]
  3. 從清單中選取您要編輯的代理程式接聽程式。
  4. 在您要停用授權的連接埠上,選取 [授權] 下拉式清單中的 [無]

MQTT 3.1.1 中未經授權的發佈

使用 MQTT 3.1.1 時,當發佈遭到拒絕時,用戶端會在沒有錯誤的情況下收到 PUBACK,因為通訊協定版本不支援傳回錯誤碼。 當發佈遭到拒絕時,MQTTv5 會傳回原因代碼 135 (未授權) 的 PUBACK。

故障排除

驗證規則

  1. 檢閱您的 BrokerAuthorization YAML/JSON 是否有結構描述問題。
  2. 套用設定時檢查輸出;結構描述錯誤由 API 伺服器報告。
  3. 將前端 Pod 記錄設定為 debugtrace,重新啟動 Pod,並檢查是否有標記為 authz 顯示剖析和有效規則的項目。

狀況良好記錄範例 (簡略):

<7>2025-02-10T16:28:31.986Z aio-broker-frontend-0 [mq@311 tid="1" module="authz"] - adding broker config ... and store config ...
<6>2025-02-10T16:28:31.986Z aio-broker-frontend-0 [mq@311 tid="1"] - starting broker authorization engine with basic rules. Cache enabled: true
<7>2025-02-10T16:28:31.987Z aio-broker-frontend-0 [mq@311 tid="1" module="authz"] - set broker authorization engine data: {"rules":[{...}]}

MQTT 代理程式作業

拒絕發佈範例:

<7>2025-02-10T16:32:19.398Z aio-broker-frontend-0 [mq@311 tid="15" module="authz"] - checking authorization for {"action":"publish","clientId":"test-publisher","topic":"test"}
<7>2025-02-10T16:32:19.411Z aio-broker-frontend-0 [mq@311 tid="15" module="authz"] - publish from client 'test-publisher' was denied ... reason_code: NotAuthorized

狀態存放區作業

拒絕取得範例:

<7>2025-02-10T16:41:31.314Z aio-broker-frontend-0 [mq@311 tid="8" module="authz"] - checking authorization for {"action":"get","clientId":"statestore-cli","key":"dGVzdA=="}
<7>2025-02-10T16:41:31.322Z aio-broker-frontend-0 [mq@311 tid="8" module="authz"] - cached new authorization result ...: Denied("no rule matched")

後續步驟