Contrôler l’accès au service Azure IoT Hub Device Provisioning (DPS) avec des signatures d’accès partagé et des jetons de sécurité

Cet article décrit les options disponibles permettant de sécuriser votre Service Azure IoT Hub Device Provisioning (DPS). Le service de provisionnement utilise une authentification et des autorisations pour accorder l’accès à chaque point de terminaison. Les autorisations permettent le processus d’authentification pour limiter l’accès à une instance de service en fonction des fonctionnalités.

Cet article aborde ce qui suit :

  • Le processus d’authentification et les jetons utilisés par le service d’approvisionnement pour vérifier les autorisations sur les API REST Service et de messagerie des appareils.

  • Les différentes autorisations que vous pouvez accorder à une application principale pour lui permettre d’accéder à l’API Service.

Authentification

L’API de messagerie des appareils prend en charge l’authentification des appareils basée sur les certificats basés sur les clés et X.509.

L’API Service prend en charge l’authentification basée sur les clés pour les applications principales.

Lors de l’utilisation basée sur les clés, le service de provisionnement d’appareils utilise des jetons de sécurité pour authentifier les services et éviter l’envoi de clés. En outre, la validité et la portée des jetons sont limitées dans le temps. Les kits SDK Azure IoT Device Provisioning génèrent automatiquement des jetons sans demander de configuration particulière.

Dans certains cas, vous pouvez avoir besoin d'utiliser les API REST HTTP Device Provisioning Service directement sans les SDK. Les sections suivantes décrivent comment s’authentifier directement sur les API REST.

Authentification avec l’API Device

L’API de messagerie des appareils est utilisée par les appareils pour attester auprès du service Device Provisioning et recevoir une connexion IoT Hub.

Remarque

Pour pouvoir recevoir une connexion authentifiée, les appareils doivent d’abord être inscrits auprès du service Device Provisioning par le biais d’une inscription. Utilisez l’API Service pour inscrire un appareil de façon programmatique par le biais d’une inscription.

Un appareil doit s’authentifier auprès de l’API de messagerie des appareils dans le cadre du processus de configuration. La méthode utilisée par un appareil pour l’authentification est définie lorsque vous configurez un groupe d’inscription ou une inscription individuelle. Quelle que soit la méthode d’authentification, l’appareil doit émettre une requête PUT HTTPS adjointe à l’URL suivante pour s’approvisionner lui-même.

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

Si vous utilisez l’authentification basée sur les clés, un jeton de sécurité est transmis à l’en-tête de requête HTTPAuthorization dans le format suivant :

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

Structure de jeton de sécurité pour l’authentification basée sur les clés

Le jeton de sécurité est transmis à l’en-tête de requête HTTPAuthorization dans le format suivant :

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

Les valeurs attendues sont les suivantes :

Valeur Description
{signature} Une chaîne de signature HMAC-SHA256 sous la forme : {URL-encoded-resourceURI} + "\n" + expiry. Important : la clé est décodée à partir de base64 et utilisée comme clé pour effectuer le calcul HMAC-SHA256.
{expiry} Chaînes UTF8 pour le nombre de secondes depuis l’époque 00:00:00 UTC 1er janvier 1970.
{URL-encoded-resourceURI} Encodage d’URL en minuscules de {ID_Scope}/registrations/{registration_id}
{policyName} Pour l’API de messagerie des appareils, cette stratégie est toujours « inscription ».

L'extrait Python suivant montre une fonction appelée generate_sas_token qui calcule le jeton à partir des entrées uri, key, policy_name et expiry pour une inscription individuelle en utilisant un type d’authentification à clé symétrique.


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"))

Le résultat doit ressembler à l'exemple suivant :


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

L’exemple suivant montre comment la signature d’accès partagé est ensuite utilisée pour s’authentifier auprès de l’API de messagerie des appareils.


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 

Si vous utilisez un groupe d’inscription basé sur une clé symétrique, vous devez d’abord générer une clé device symmetric à l’aide de la clé de groupe d’inscription. Utilisez la clé primaire ou secondaire du groupe d’inscription pour calculer un HMAC-SHA256 de l’ID d’inscription de l’appareil. Le résultat est ensuite converti au format Base64 pour obtenir la clé de l’appareil dérivée. Pour afficher des exemples de code, consultez Comment approvisionner des appareils à l’aide de groupes d’inscription avec des clés symétriques. Une fois la clé symétrique de l’appareil déduite, vous pouvez inscrire l’appareil à l’aide des exemples précédents.

Avertissement

Pour éviter d’inclure la clé principale de groupe dans le code de votre appareil, le processus de déduction de la clé d’appareil doit être effectué à partir de l’appareil.

Authentification par certificat

Si vous avez configuré un groupe d’inscription ou d’inscription individuel pour l’authentification basée sur un certificat X.509, l’appareil doit utiliser son certificat X.509 émis pour attester de l’API de messagerie des appareils. Reportez-vous aux articles suivants sur la configuration de l’inscription et la génération du certificat de l’appareil.

Une fois l’inscription configurée et le certificat de l’appareil émis, l’exemple suivant montre comment s’authentifier auprès de l’API de messagerie des appareils avec le certificat X.509 de l’appareil.


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 

Authentification avec l’API Service

L’API Service permet de récupérer l’état d’inscription et de supprimer les inscriptions d’appareils à distance. Le service est également utilisé par les applications principales pour gérer par programmation les groupes individuels et les groupes d’inscriptions. L’API Service prend en charge l’authentification basée sur les clés pour les applications principales.

Pour accéder à tout point de terminaison API Service, vous devez disposer des autorisations appropriées. Par exemple, une application principale doit ajouter un jeton contenant des informations d’identification de sécurité à chaque message qu’elle envoie au service.

Le Service IoT Hub Device Provisioning accorde l’accès aux points de terminaison en vérifiant la validité du jeton par rapport aux stratégies d’accès partagé. Les informations d’identification de sécurité telles que les clés symétriques ne sont jamais envoyées sur le réseau.

Contrôle d’accès et autorisations

Vous pouvez accorder des autorisations de différentes manières :

  • Stratégies d’autorisation d’accès partagé. Les stratégies d’accès partagé peuvent accorder n’importe quelle combinaison d’autorisations. Vous pouvez définir des stratégies dans le portail Azure, ou programmatiquement avec des API REST du service Device Provisioning. Tout service de provisionnement créé comporte la stratégie par défaut suivante :

  • provisioningserviceowner : stratégie avec toutes les autorisations. Pour plus d’informations, consultez la page Autorisations.

Remarque

Le fournisseur de ressources du service Device Provisioning est sécurisé par le biais de votre abonnement Azure, comme le sont tous les fournisseurs dans Azure Resource Manager.

Pour plus d’informations sur la façon de construire et d’utiliser les jetons de sécurité, consultez la section suivante.

HTTP est le seul protocole pris en charge. Il implémente l’authentification en incluant un jeton valide dans l’en-tête de demande d’autorisation.

Exemple

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

Remarque

Les kits SDK du service Azure IoT Device Provisioning génèrent automatiquement des jetons durant la connexion au service.

Jetons de sécurité

Le service de provisionnement d’appareils utilise des jetons de sécurité pour authentifier les services et éviter l’envoi de clés. En outre, la validité et la portée des jetons sont limitées dans le temps. Les kits SDK du service Azure IoT Device Provisioning génèrent automatiquement des jetons sans nécessiter de configuration particulière. Certains scénarios nécessitent toutefois que vous génériez et utilisiez directement des jetons de sécurité. Ces scénarios incluent l’utilisation directe du protocole HTTP.

Structure du jeton de sécurité

Vous utilisez des jetons de sécurité pour permettre aux services d’accéder de manière limitée dans le temps à des caractéristiques spécifiques du service de provisionnement d’appareils IoT. Pour obtenir l’autorisation de se connecter au service de provisionnement, les services doivent envoyer des jetons de sécurité signés avec une clé d’accès partagé ou une clé symétrique.

Un jeton signé avec une clé d’accès partagé accorde un accès à toutes les fonctionnalités associées aux autorisations de stratégie d’accès partagé.

Le jeton de sécurité présente le format suivant :

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

Voici les valeurs attendues

Valeur Description
{signature} Une chaîne de signature HMAC-SHA256 sous la forme : {URL-encoded-resourceURI} + "\n" + expiry. Important : la clé est décodée à partir de base64 et utilisée comme clé pour effectuer le calcul HMAC-SHA256.
{expiry} Chaînes UTF8 pour le nombre de secondes depuis l’époque 00:00:00 UTC 1er janvier 1970.
{URL-encoded-resourceURI} Encodage de l’URL en minuscules à partir de l’URI de ressource en minuscules. Préfixe URI (par segment) des points de terminaison accessibles avec ce jeton, en commençant par le nom d’hôte du service de provisionnement d’appareils IoT (sans protocole). Par exemple : mydps.azure-devices-provisioning.net.
{policyName} Le nom de la stratégie d’accès partagé à laquelle ce jeton fait référence.

Notes

le préfixe URI est calculé par segment et non par caractère. Par exemple /a/b est un préfixe de /a/b/c, mais pas de /a/bc.

L’extrait de code Node.js suivant illustre une fonction appelée generateSasToken qui calcule le jeton à partir des entrées resourceUri, signingKey, policyName, expiresInMins. Les sections suivantes décrivent en détail comment initialiser les différentes entrées pour les différents cas d’utilisation des jetons.

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;
};

À titre de comparaison, le code Python équivalent pour générer un jeton de sécurité est :

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)

Remarque

Dans la mesure où la validité temporelle du jeton est vérifiée sur les machines du service de provisionnement d’appareils IoT, la dérive de l’horloge de la machine qui génère le jeton doit être minimale.

Utilisation de jetons de sécurité de composants du service

Les composants de service peuvent uniquement créer des jetons de sécurité utilisant des stratégies d’accès partagé pour accorder les autorisations adaptées, comme expliqué précédemment.

Voici les fonctions de service exposées sur les points de terminaison :

Point de terminaison Fonctionnalité
{your-service}.azure-devices-provisioning.net/enrollments Fournit les opérations relatives à l’inscription d’appareils auprès du service de provisionnement d’appareils.
{your-service}.azure-devices-provisioning.net/enrollmentGroups Fournit les opérations relatives à la gestion des groupes d’inscription d’appareils.
{your-service}.azure-devices-provisioning.net/registrations/{id} Fournit les opérations relatives à la récupération et à la gestion de l’état des inscriptions d’appareils.

Par exemple, un service généré à l’aide d’une stratégie d’accès partagé précréée appelée enrollmentread créerait un jeton avec les paramètres suivants :

  • URI de ressource : {mydps}.azure-devices-provisioning.net,
  • clé de signature : une des clés de la stratégie enrollmentread ,
  • nom de la stratégie : enrollmentread,
  • n’importe quel délai d’expiration time.backn

Create a shared access policy for your Device Provisioning Service instance in the portal

var endpoint ="mydps.azure-devices-provisioning.net";
var policyName = 'enrollmentread'; 
var policyKey = '...';

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

Le résultat, qui revient à accorder l’accès en lecture à tous les dossiers d’inscription, est le suivant :

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

SDK et exemples

Rubriques de référence :

Les rubriques de référence suivantes fournissent des informations supplémentaires sur le contrôle de l’accès à votre service de provisionnement d’appareils IoT.

Autorisations liées au service de provisionnement d’appareils

Le tableau suivant répertorie les autorisations qui vous permettent de contrôler l’accès à votre service de provisionnement d’appareils IoT.

Permission Notes
ServiceConfig Accorde l’accès pour changer les configurations du service.
Cette autorisation est utilisée par les services cloud principaux.
EnrollmentRead Accorde l’accès en lecture aux inscriptions d’appareils et aux groupes d’inscription.
Cette autorisation est utilisée par les services cloud principaux.
EnrollmentWrite Accorde l’accès en écriture aux inscriptions d’appareils et aux groupes d’inscription.
Cette autorisation est utilisée par les services cloud principaux.
RegistrationStatusRead Accorde l’accès en lecture à l’état d’inscription de l’appareil.
Cette autorisation est utilisée par les services cloud principaux.
RegistrationStatusWrite Accorde l’accès permettant de supprimer l’état d’inscription de l’appareil.
Cette autorisation est utilisée par les services cloud principaux.