Controlar o acesso ao Serviço de Provisionamento de Dispositivos (DPS) no Hub IoT do Azure com assinaturas de acesso compartilhado e tokens de segurança

Este artigo descreve as opções disponíveis para proteger o DPS (Serviço de Provisionamento de Dispositivos) no Hub IoT do Azure. O serviço de provisionamento usa autenticação e permissões para conceder acesso a cada ponto de extremidade. As permissões permitem que o processo de autenticação limite o acesso a uma instância de serviço com base na funcionalidade.

Este artigo discute o seguinte:

  • O processo de autenticação e os tokens que o serviço de provisionamento usa para verificar as permissões em relação às APIs REST do serviço e do dispositivo.

  • As diferentes permissões que você pode conceder a um aplicativo de back-end para acessar a API do serviço.

Autenticação

A API do Dispositivo dá suporte à autenticação de dispositivo baseada em chave e X.509 baseada em certificado.

A API de Serviço dá suporte à autenticação baseada em chave para aplicativos de back-back.

Ao usar a autenticação com senha, os Serviços de Provisionamento de Dispositivo usam tokens de segurança para autenticar serviços para evitar o envio de chaves durante a transmissão. Além disso, os tokens de segurança têm limite de escopo e de prazo de validade. Os SDKs de Provisionamento de Dispositivo do Internet das Coisas do Azure geram tokens automaticamente sem precisar de configuração especial.

Em alguns casos, talvez seja necessário usar as APIs REST do Serviço de Provisionamento de Dispositivos HTTP diretamente, sem usar os SDKs. As seções a seguir descrevem como autenticar diretamente nas APIs REST.

Autenticação de API do dispositivo

A API do Dispositivo é usada por dispositivos para atestar o Serviço de Provisionamento de Dispositivos e receber uma conexão do Hub IoT.

Observação

Para receber uma conexão autenticada, os dispositivos devem primeiro ser registrados no Serviço de Provisionamento de Dispositivos por meio de um registro. Use a API de Serviço para registrar programaticamente um dispositivo por meio de um registro.

Um dispositivo deve se autenticar na API do Dispositivo como parte do processo de provisionamento. O método usado por um dispositivo para autenticar é definido quando você configura um grupo de registro ou um registro individual. Seja qual for o método de autenticação, o dispositivo deve emitir um HTTPS PUT para a URL a seguir para provisionar a si mesmo.

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

Se estiver usando a autenticação baseada em chave, um token de segurança será passado no cabeçalho da solicitação de Autorização HTTP no seguinte formato:

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

Estrutura de token de segurança para autenticação baseada em chave

O token de segurança será passado no cabeçalho da solicitação de Autorização HTTP no seguinte formato:

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

Os valores esperados são:

Valor Descrição
{signature} Uma cadeia de caracteres de assinatura HMAC-SHA256 no formato: {URL-encoded-resourceURI} + "\n" + expiry. Importante: a chave é decodificada da base64 e usada como chave para executar o cálculo de HMAC-SHA256.
{expiry} As cadeias de caracteres UTF8 para o número de segundos desde a época 00:00:00 UTC em 1º de janeiro de 1970.
{URL-encoded-resourceURI} Codificação de URL em caso inferior de {ID_Scope}/registrations/{registration_id}
{policyName} Para a API do Dispositivo, essa política é sempre "registro".

O snippet Python a seguir mostra uma função chamada generate_sas_token que calcula o token das entradas uri, key, policy_name, expiry para um registro individual usando um tipo de autenticação de chave simétrica.


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

A saída deve ser semelhante ao exemplo a seguir:


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

O exemplo a seguir mostra como a assinatura de acesso compartilhado é usada para autenticar com a API do dispositivo.


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 

Se estiver usando um grupo de registro baseado em chave simétrica, primeiro você precisará gerar uma chave usando a chave device symmetric do grupo de registro. Use a chave primária ou secundária do grupo de registro para calcular um HMAC-SHA256 da ID de registro do dispositivo. O resultado é então convertido no formato Base64 para obter a chave de dispositivo derivada. Para ver exemplos do código de visualização, consulte Como provisionar dispositivos usando grupos de registro de chave simétrica. Depois que a chave simétrica do dispositivo tiver sido derivada, você poderá registrar o dispositivo usando os exemplos anteriores.

Aviso

Para evitar a inclusão da chave mestra de grupo no código do dispositivo, o processo de derivação da chave do dispositivo deve ser feito fora do dispositivo.

Autenticação baseada em certificado

Se você tiver definido um registro individual ou um grupo de registro para autenticação baseada em certificado X.509, o dispositivo precisará usar seu certificado X.509 emitido para atestar a API do dispositivo. Consulte os artigos a seguir sobre como configurar o registro e gerar o certificado do dispositivo.

Depois que o registro tiver sido definido e o certificado do dispositivo emitido, o exemplo a seguir demonstrará como autenticar na API do dispositivo com o certificado X.509 do dispositivo.


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 

Autenticação de API de serviço

A API de Serviço é usada para recuperar o estado de registro e remover registros de dispositivo. O serviço também é usado por aplicativos de back-end para gerenciar programaticamente grupos individuais egrupos de registro. A API de Serviço dá suporte à autenticação baseada em chave para aplicativos de back-back.

Você deve ter permissões adequadas para acessar qualquer um dos pontos de extremidade da API de serviços. Por exemplo, um aplicativo de back-end deve incluir um token que contém credenciais de segurança juntamente com cada mensagem que ele envia para o serviço.

O Serviço de Provisionamento do Hub IoT do Azure concede acesso aos pontos de extremidade, verificando um token com base nas políticas de acesso compartilhado. As credenciais de segurança, como as chaves simétricas, nunca são enviadas pela conexão.

Controle e permissões de acesso

Você pode conceder permissões das seguintes maneiras:

  • Políticas de autorização de acesso compartilhado. As políticas de acesso compartilhado podem conceder qualquer combinação de permissões. Você pode definir políticas no Portal do Azure ou de forma programática usando as APIs REST do Serviço de Provisionamento de Dispositivo. Um serviço de provisionamento recém-criado tem a seguinte política padrão:

  • provisioningserviceowner: política com todas as permissões. Para obter informações detalhadas, consulte permissões.

Observação

O provedor de recursos do Serviço de Provisionamento de Dispositivo é protegido por meio de sua assinatura do Azure, assim como todos os provedores no Azure Resource Manager.

Para saber mais sobre como construir e usar os tokens de segurança, veja a próxima seção.

O HTTP é o único protocolo com suporte e implementa a autenticação incluindo um token válido no cabeçalho da solicitação Authorization.

Exemplo

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

Observação

Os SDKs do Serviço de Provisionamento de Dispositivo de IoT do Azure geram tokens automaticamente durante a conexão com o serviço.

Tokens de segurança

Os Serviços de Provisionamento de Dispositivo usam tokens de segurança para autenticar serviços para evitar o envio de chaves durante a transmissão. Além disso, os tokens de segurança têm limite de escopo e de prazo de validade. Os SDKs do Serviço de Provisionamento de Dispositivo do IoT do Azure geram tokens automaticamente sem precisar de configuração especial. Alguns cenários exigem que você gere e use tokens de segurança diretamente. Esses cenários incluem o uso direto da superfície HTTP.

Estrutura do token de segurança

Você usa tokens de segurança para conceder acesso vinculado ao tempo para serviços para uma funcionalidade específica no Serviço de Provisionamento de Dispositivo de IoT. Para obter autorização para se conectar ao serviço de provisionamento, os dispositivos e serviços devem enviar tokens de segurança assinados com um acesso compartilhado ou uma chave simétrica.

Um token assinado com uma chave de acesso compartilhada concede acesso a todas funcionalidades associadas às permissões da política de acesso compartilhado.

O token de segurança tem o seguinte formato:

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

Veja os valores esperados

Valor Descrição
{signature} Uma cadeia de caracteres de assinatura HMAC-SHA256 no formato: {URL-encoded-resourceURI} + "\n" + expiry. Importante: a chave é decodificada da base64 e usada como chave para executar o cálculo de HMAC-SHA256.
{expiry} As cadeias de caracteres UTF8 para o número de segundos desde a época 00:00:00 UTC em 1º de janeiro de 1970.
{URL-encoded-resourceURI} Codificação de URL em letras minúsculas do URI de recurso em letras minúsculas. Prefixo de URI (por segmento) dos pontos de extremidade que podem ser acessados com esse token, começando com o nome de host do Serviço de Provisionamento de Dispositivo de IoT (sem protocolo). Por exemplo, mydps.azure-devices-provisioning.net.
{policyName} O nome da política de acesso compartilhado a qual se refere esse token.

Observação

o prefixo URI é computado por segmento e não por caractere. Por exemplo, /a/b é um prefixo para /a/b/c, mas não para /a/bc.

O seguinte snippet de Node.js mostra uma função chamada generateSasToken que calcula o token a partir das entradas resourceUri, signingKey, policyName, expiresInMins. As seções a seguir detalharão como inicializar as entradas diferentes para casos de uso com token diferentes.

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

Como comparação, o código Python equivalente para gerar um token de segurança é:

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)

Observação

Como o prazo de validade do token é validado em computadores do Serviço de Provisionamento de Dispositivo de IoT, o descompasso no relógio do computador que gera o token deve ser mínimo.

Usar tokens de segurança de componentes de serviço

Os componentes de serviço só podem gerar tokens de segurança usando políticas de acesso compartilhado que concedem as permissões apropriadas, conforme explicado anteriormente.

Veja as funções de serviço expostas nos pontos de extremidade:

Ponto de extremidade Funcionalidade
{your-service}.azure-devices-provisioning.net/enrollments Fornece operações de registro de dispositivo com o Serviço de Provisionamento de Dispositivo.
{your-service}.azure-devices-provisioning.net/enrollmentGroups Fornece operações para gerenciar grupos de registro de dispositivo.
{your-service}.azure-devices-provisioning.net/registrations/{id} Fornece operações para recuperar e gerenciar o status de registros do dispositivo.

Como exemplo, um serviço gerado usando uma política de acesso compartilhado pré-criada chamada enrollmentread criaria um token com os seguintes parâmetros:

  • URI de recurso: {mydps}.azure-devices-provisioning.net,
  • chave de assinatura: uma das chaves da política enrollmentread ,
  • nome da política: enrollmentread,
  • qualquer validade 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);

O resultado, que concederia acesso para ler todos os relatórios do registro, seria:

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

SDKs e amostras

Tópicos de referência:

Os tópicos de referência a seguir fornecem a você mais informações sobre como controlar o acesso ao seu Serviço de Provisionamento de Dispositivo de IoT.

Permissões do Serviço de Provisionamento de Dispositivo

A tabela a seguir lista as permissões que você pode usar para controlar o acesso ao seu Serviço de Provisionamento de Dispositivo de IoT.

Permissão Observações
ServiceConfig Concede acesso para alterar as configurações de serviço.
Essa permissão é usada pelos serviços de nuvem back-end.
EnrollmentRead Concede acesso de leitura para os registros do dispositivo e os grupos de registro.
Essa permissão é usada pelos serviços de nuvem back-end.
EnrollmentWrite Concede acesso de gravação para os registros do dispositivo e os grupos de registro.
Essa permissão é usada pelos serviços de nuvem back-end.
RegistrationStatusRead Concede acesso de leitura ao status de registro do dispositivo.
Essa permissão é usada pelos serviços de nuvem back-end.
RegistrationStatusWrite Concede acesso de exclusão ao status de registro do dispositivo.
Essa permissão é usada pelos serviços de nuvem back-end.