分享方式:


使用共用存取簽章和安全性權杖來控制對 Azure IoT 中樞裝置佈建服務 (DPS) 的存取權

本文描述用於保護 Azure IoT 中樞裝置佈建服務 (DPS) 的可用選項。 佈建服務會使用「驗證」和「權限」,以授與每個端點的存取權。 權限允許授權程序根據功能,限制對服務執行個體的存取權。

本文討論:

  • 佈建服務所使用的驗證程序和權杖,可用來驗證服務和裝置 REST API 的權限。

  • 您可授與後端應用程式的不同權限,用於存取服務 API。

驗證

裝置 API 支援金鑰型和 X.509 憑證型的裝置驗證。

服務 API 支援後端應用程式的金鑰型驗證。

當使用金鑰型驗證時,裝置佈建服務會使用安全性權杖來驗證服務,以避免透過線路傳送金鑰。 此外,安全性權杖在時間有效性和範圍內也會受到限制。 Azure IoT 裝置佈建 SDK 不需要特殊設定,即可自動產生權杖。

在某些情況下,您可能必須直接使用 HTTP 裝置佈建服務 REST API,而並非使用 SDK。 下列各節說明如何直接針對 REST API 進行驗證。

裝置 API 驗證

裝置會使用裝置 API 來證明裝置佈建服務並接收 IoT 中樞連線。

注意

為了接收驗證連線,必須先透過註冊在裝置佈建服務中登錄裝置。 使用服務 API,透過註冊以程式設計方式登錄裝置。

裝置必須向裝置 API 驗證作為佈建程序的一部分。 當您設定註冊群組或個別註冊時,將會定義裝置用來驗證的方法。 無論驗證方法為何,裝置必須向下列 URL 發出 HTTPS PUT,才能自行佈建。

    https://global.azure-devices-provisioning.net/[ID_Scope]/registrations/[registration_id]/register?api-version=2021-06-01

如果使用金鑰型驗證,安全性權杖會以下列格式傳遞於 HTTP 授權要求標頭:

    SharedAccessSignature sig={signature}&se={expiry}&skn={policyName}&sr={URL-encoded-resourceURI} 

金鑰型驗證的安全性權杖結構

安全性權杖會以下列格式傳遞於 HTTP 授權要求標頭:

    SharedAccessSignature sig={signature}&se={expiry}&skn={policyName}&sr={URL-encoded-resourceURI} 

預期的值如下:

Description
{signature} HMAC-SHA256 簽章字串,格式為: {URL-encoded-resourceURI} + "\n" + expiry。 重要事項:金鑰是從 base64 解碼而來,並且會作為用來執行 HMAC-SHA256 計算的金鑰。
{expiry} 從新紀元時間 (Epoch) 1970 年 1 月 1日 00:00:00 UTC 時間至今秒數的 UTF8 字串。
{URL-encoded-resourceURI} {ID_Scope}/registrations/{registration_id} 的小寫 URL 編碼
{policyName} 針對裝置 API,此原則一律是「登錄」。

下列 Python 程式碼片段顯示名為 generate_sas_token 的函式,針對使用對稱金鑰驗證類型的個別註冊,計算輸入 urikeypolicy_nameexpiry 的權杖。


from base64 import b64encode, b64decode, encode 
from hashlib import sha256 
from time import time 
from urllib.parse import quote_plus, urlencode 
from hmac import HMAC 

 def generate_sas_token(uri, key, policy_name, expiry=3600): 
    ttl = time() + expiry 
    sign_key = "%s\n%d" % ((quote_plus(uri)), int(ttl)) 
    signature = b64encode(HMAC(b64decode(key), sign_key.encode('utf-8'), sha256).digest()) 

    rawtoken = { 
        'sr' :  uri, 
        'sig': signature, 
        'se' : str(int(ttl)), 
        'skn' : policy_name 
    } 

    return 'SharedAccessSignature ' + urlencode(rawtoken) 

print(generate_sas_token("myIdScope/registrations/mydeviceregistrationid", "00mysymmetrickey", "registration"))

結果應與下列輸出相似:


SharedAccessSignature sr=myIdScope%2Fregistrations%2Fmydeviceregistrationid&sig=SDpdbUNk%2F1DSjEpeb29BLVe6gRDZI7T41Y4BPsHHoUg%3D&se=1630175722&skn=registration 

下列範例顯示如何接著使用共用存取簽章來向裝置 API 進行驗證。


curl -L -i -X PUT -H 'Content-Type: application/json' -H 'Content-Encoding:  utf-8' -H 'Authorization: [token]' -d '{"registrationId": "[registration_id]"}' https://global.azure-devices-provisioning.net/[ID_Scope]/registrations/[registration_id]/register?api-version=2021-06-01 

如果使用對稱金鑰型註冊群組,您必須先使用註冊群組金鑰來產生 device symmetric 金鑰。 使用註冊群組主要或次要金鑰來計算裝置登錄識別碼的 HMAC-SHA256。 結果接著會轉換成 Base64 格式以取得衍生裝置金鑰。 若要檢視程式碼範例,請參閱如何使用對稱金鑰註冊群組佈建裝置。 衍生裝置對稱金鑰之後,您可使用上述範例來登錄裝置。

警告

若要避免在裝置程式碼中包含群組主要金鑰,衍生裝置金鑰程序應在裝置外部進行。

憑證型驗證

如果您已設定 X.509 憑證型驗證的個別註冊或註冊群組,裝置必須使用其發出的 X.509 憑證來向裝置 API 證明。 如需瞭解如何設定註冊並產生裝置憑證,請參閱下列文章。

設定註冊並發出裝置憑證之後,下列範例示範如何使用裝置的 X.509 憑證向裝置 API 進行驗證。


curl -L -i -X PUT –cert ./[device_cert].pem –key ./[device_cert_private_key].pem -H 'Content-Type: application/json' -H 'Content-Encoding:  utf-8' -d '{"registrationId": "[registration_id]"}' https://global.azure-devices-provisioning.net/[ID_Scope]/registrations/[registration_id]/register?api-version=2021-06-01 

服務 API 驗證

服務 API 會用來擷取登錄狀態和移除裝置登錄。 後端應用程式也會使用服務,以程式設計方式管理個別群組註冊群組。 服務 API 支援後端應用程式的金鑰型驗證。

您必須具有適當權限,才能存取任何服務 API 端點。 例如,後端應用程式必須包含權杖,其中包含安全性認證,以及傳送到服務的每個訊息。

Azure IoT 中樞裝置佈建服務可根據共用存取原則驗證權杖,以授與端點的存取權。 安全性認證 (如對稱金鑰) 永不透過網路傳送。

存取控制及權限

您可以透過下列方式授與權限

  • 共用存取授權原則。 共用存取原則可以授與上面所列權限的任意組合。 您可以在 Azure 入口網站中定義原則,或使用裝置佈建服務 REST API 以程式設計方式定義原則。 新建立的佈建服務具有以下預設原則:

  • provisioningserviceowner︰具備所有權限的原則。 如需詳細資訊,請參閱權限

注意

如同 Azure Resource Manager 中的所有提供者一樣,裝置佈建服務資源提供者也是透過您的 Azure 訂用帳戶而受保護。

如需如何建構和使用安全性權杖的詳細資訊,請參閱下一節。

HTTP 是唯一支援的通訊協定,是以在 Authorization 要求標頭中包含有效權杖的方式實作驗證。

範例

SharedAccessSignature sr = 
   mydps.azure-devices-provisioning.net&sig=kPszxZZZZZZZZZZZZZZZZZAhLT%2bV7o%3d&se=1487709501&skn=provisioningserviceowner`\

注意

Azure IoT 裝置佈建服務 SDK 會在連接至服務時自動產生權杖。

安全性權杖

裝置佈建服務使用安全性權杖對服務進行驗證,以避免在網路上傳送金鑰。 此外,安全性權杖在時間有效性和範圍內也會受到限制。 Azure IoT 裝置佈建服務 SDK 不需要特殊設定,即可自動產生權杖。 有些場景確實需要您直接產生並使用安全性權杖。 這樣的場景包括直接使用 HTTP 表面。

安全性權杖結構

您使用安全性權杖授與對 IoT 裝置佈建服務中特定功能之服務的時間限制存取。 若要取得連線至佈建服務的授權,服務必須傳送使用共用存取或對稱金鑰簽署的安全性權杖。

使用共用存取金鑰簽署的權杖授與對與共用存取原則權限相關聯的所有功能之存取。

安全性權杖具有以下格式:

SharedAccessSignature sig={signature}&se={expiry}&skn={policyName}&sr={URL-encoded-resourceURI}

以下是預期的值

Description
{signature} HMAC-SHA256 簽章字串,格式為: {URL-encoded-resourceURI} + "\n" + expiry重要事項:金鑰是從 base64 解碼而來,並且會作為用來執行 HMAC-SHA256 計算的金鑰。
{expiry} 從新紀元時間 (Epoch) 1970 年 1 月 1日 00:00:00 UTC 時間至今秒數的 UTF8 字串。
{URL-encoded-resourceURI} 小寫資源 URI 的小寫 URL 編碼。 可以使用此權杖存取之端點的 URI 首碼 (依區段),從 IoT 裝置佈建服務的主機名稱開始 (無通訊協定)。 例如: mydps.azure-devices-provisioning.net
{policyName} 此權杖所參考的共用存取原則名稱。

注意

URI 首碼是依區段計算的,而不是依字元計算的。 例如,/a/b/a/b/c 的首碼,但不是 /a/bc 的首碼。

下列 Node.js 程式碼片段顯示稱為 generateSasToken 的函式,它會從輸入 resourceUri, signingKey, policyName, expiresInMins 計算權杖。 接下來的區段詳細介紹了如何為不同的權杖使用案例初始化不同的輸入。

var generateSasToken = function(resourceUri, signingKey, policyName, expiresInMins) {
    resourceUri = encodeURIComponent(resourceUri);

    // Set expiration in seconds
    var expires = (Date.now() / 1000) + expiresInMins * 60;
    expires = Math.ceil(expires);
    var toSign = resourceUri + '\n' + expires;

    // Use crypto
    var hmac = crypto.createHmac('sha256', new Buffer(signingKey, 'base64'));
    hmac.update(toSign);
    var base64UriEncoded = encodeURIComponent(hmac.digest('base64'));

    // Construct authorization string
    var token = "SharedAccessSignature sr=" + resourceUri + "&sig="
    + base64UriEncoded + "&se=" + expires + "&skn="+ policyName;
    return token;
};

作為比較,產生安全性權杖的對等 Python 程式碼是:

from base64 import b64encode, b64decode
from hashlib import sha256
from time import time
from urllib.parse import quote_plus, urlencode
from hmac import HMAC

def generate_sas_token(uri, key, policy_name, expiry=3600):
    ttl = time() + expiry
    sign_key = "%s\n%d" % ((quote_plus(uri)), int(ttl))
    print sign_key
    signature = b64encode(HMAC(b64decode(key), sign_key, sha256).digest())

    rawtoken = {
        'sr' :  uri,
        'sig': signature,
        'se' : str(int(ttl)),
        'skn' : policy_name
    }

    return 'SharedAccessSignature ' + urlencode(rawtoken)

注意

由於權杖的時效性會在 IoT 裝置佈建服務機器上驗證,因此產生權杖之機器上的時鐘飄移必須降低最低。

使用服務元件中的安全性權杖

服務元件只能使用授與適當權限的共用存取原則產生安全性權杖,如前所述。

以下是在端點上公開的服務功能︰

端點 功能
{your-service}.azure-devices-provisioning.net/enrollments 使用裝置佈建服務提供裝置註冊作業。
{your-service}.azure-devices-provisioning.net/enrollmentGroups 提供管理裝置註冊群組的作業。
{your-service}.azure-devices-provisioning.net/registrations/{id} 提供擷取和管理裝置註冊狀態的作業。

舉例來說,使用名為 enrollmentread 的預先建立共用存取原則產生的服務,將會使用下列參數來建立權杖︰

  • 資源 URI:{mydps}.azure-devices-provisioning.net,
  • 簽署金鑰:enrollmentread 原則的金鑰之一,
  • 原則名稱:enrollmentread
  • 任何到期 time.backn
var endpoint ="mydps.azure-devices-provisioning.net";
var policyName = 'enrollmentread'; 
var policyKey = '...';

var token = generateSasToken(endpoint, policyKey, policyName, 60);

將授與讀取所有註冊記錄的存取的結果會是:

SharedAccessSignature sr=mydps.azure-devices-provisioning.net&sig=JdyscqTpXdEJs49elIUCcohw2DlFDR3zfH5KqGJo4r4%3D&se=1456973447&skn=enrollmentread

SDK 與範例

參考主題:

下列參考主題會提供您有關控制 IoT 裝置佈建服務存取權的詳細資訊。

裝置佈建服務權限

下表列出了您可以用來控制存取 IoT 裝置佈建服務的權限。

權限 備註
ServiceConfig 授與變更服務設定的存取。
此權限由後端雲端服務使用。
EnrollmentRead 授與對裝置註冊和註冊群組的讀取存取。
此權限由後端雲端服務使用。
EnrollmentWrite 授與對裝置註冊和註冊群組的寫入權限。
此權限由後端雲端服務使用。
RegistrationStatusRead 授與對裝置註冊狀態的讀取存取。
此權限由後端雲端服務使用。
RegistrationStatusWrite 授與對裝置註冊狀態的删除存取。
此權限由後端雲端服務使用。