Autenticar o acesso aos recursos dos Event Hubs utilizando assinaturas de acesso partilhado (SAS)

Ao usar uma assinatura de acesso partilhada (SAS), pode controlar o tipo de acesso que concede aos clientes. Pode definir os seguintes controlos num SAS:

  • O intervalo durante o qual o SAS é válido, que inclui a hora de início e a hora de expiração.
  • As permissões concedidas pelo SAS. Por exemplo, um SAS para um namespace de Event Hubs pode conceder permissão para ouvir eventos, mas não para enviar eventos.

A autenticação SAS oferece os seguintes benefícios:

  • Somente clientes que apresentam credenciais válidas podem enviar dados para um hub de eventos.
  • Um cliente não pode fazer-se passar por outro cliente.
  • Podes bloquear um cliente malicioso de enviar dados para um hub de eventos.

Este artigo aborda a autenticação do acesso aos recursos dos Centros de Eventos através da utilização do SAS. Para saber como autorizar o acesso a recursos dos Centros de Eventos através do SAS, consulte Autorizar acesso aos recursos dos Centros de Eventos usando assinaturas de acesso partilhadas.

Note

Como melhor prática de segurança, utilize credenciais Microsoft Entra sempre que possível, em vez de usar assinaturas de acesso partilhadas, que podem ser mais facilmente comprometidas. Embora você possa continuar a usar assinaturas de acesso compartilhado (SAS) para conceder acesso refinado aos recursos dos Hubs de Eventos, o Microsoft Entra ID oferece recursos semelhantes sem a necessidade de gerenciar tokens SAS ou se preocupar em revogar um SAS comprometido.

Para obter mais informações sobre a integração do Microsoft Entra nos Hubs de Eventos do Azure, consulte Autorizar o acesso aos Hubs de Eventos usando a ID do Microsoft Entra.

Configurar autenticação SAS

Você pode configurar uma regra SAS em um namespace de Hubs de Eventos ou uma entidade (hub de eventos ou tópico Kafka). Configurar uma regra SAS num grupo de consumidores não é suportado, mas pode usar regras configuradas num namespace ou entidade para garantir o acesso a um grupo de consumidores. A imagem a seguir mostra como as regras de autorização se aplicam a entidades de exemplo.

Diagrama que mostra hubs de eventos com regras de escuta, envio e gerenciamento.

Neste exemplo, o namespace de Hubs de Eventos de exemplo (ExampleNamespace) tem duas entidades: eh1 e Kafka topic1. As regras de autorização são definidas no nível da entidade e também no nível do namespace.

As regras de autorização manageRuleNS, sendRuleNS e listenRuleNS aplicam-se a eh1 e topic1. As regras de autorização listenRule-eh e sendRule-eh aplicam-se apenas a eh1, e a regra de autorização sendRuleT aplica-se apenas a topic1.

Quando você usa a regra de autorização sendRuleNS, os aplicativos cliente podem enviar para eh1 e topic1. Quando a regra de autorização sendRuleT é usada, ela impõe acesso granular apenas ao topic1 e, portanto, os aplicativos cliente que usam essa regra para acesso agora não podem enviar para eh1, mas apenas para topic1.

Gerar um token de assinatura de acesso compartilhado

Qualquer cliente que tenha acesso ao nome de uma regra de autorização e a uma das suas chaves de assinatura pode gerar um token SAS. Gera o token criando uma string no seguinte formato:

  • se – Expiração instantânea do token. Inteiro que representa os segundos decorridos desde as 00:00:00 UTC de 1 de janeiro de 1970 (época UNIX), no momento em que o token expira.
  • skn – Nome da regra de autorização, que é o nome da chave SAS.
  • sr – URI do recurso que está sendo acessado.
  • sig – Assinatura.

A cadeia de assinatura é o HMAC-SHA256 hash calculado sobre o URI de recurso (âmbito descrito na secção anterior) e a representação da cadeia do instante de expiração do token, separados por um feed de linha (LF). Digite o hash com uma das chaves de assinatura da regra de autorização. O cálculo de hash devolve um valor de hash de 256 bits/32 bytes.

HMAC-SHA256(signingKey, 'https://<yournamespace>.servicebus.windows.net/' + '\n' + 1438205742)

O token contém os valores não hashados para que o destinatário possa recalcular o hash com os mesmos parâmetros e verificar se o emissor tem uma chave de assinatura válida.

O URI do recurso é o URI completo do recurso do Service Bus ao qual o acesso é reivindicado. Por exemplo, http://<namespace>.servicebus.windows.net/<entityPath> ou sb://<namespace>.servicebus.windows.net/<entityPath>, como http://contoso.servicebus.windows.net/eh1.

Codifica o URI por percentual.

Configure a regra SAS usada para assinar na entidade especificada por este URI ou por um dos seus pais hierárquicos. Por exemplo, http://contoso.servicebus.windows.net/eh1 ou http://contoso.servicebus.windows.net no exemplo anterior.

Um token SAS é válido para todos os recursos prefixados com o <resourceURI> usado na cadeia de caracteres de assinatura.

Note

Gera-se um token de acesso para os Event Hubs usando uma política de acesso partilhado. Para obter mais informações, consulte Política de autorização de acesso compartilhado.

Gerar uma assinatura (token) a partir de uma apólice

A secção seguinte mostra como gerar um token SAS utilizando políticas de assinatura de acesso partilhada.

Node.js

function createSharedAccessToken(uri, saName, saKey) { 
  if (!uri || !saName || !saKey) { 
          throw "Missing required parameter"; 
      } 
  var encoded = encodeURIComponent(uri); 
  var now = new Date(); 
  var week = 60*60*24*7;
  var ttl = Math.round(now.getTime() / 1000) + week;
  var signature = encoded + '\n' + ttl; 
  var hash = crypto.createHmac('sha256', saKey).update(signature, 'utf8').digest('base64'); 
  return 'SharedAccessSignature sr=' + encoded + '&sig=' +  
      encodeURIComponent(hash) + '&se=' + ttl + '&skn=' + saName; 
}

Para usar um nome de política e um valor de chave para se conectar a um hub de eventos, use o EventHubProducerClient construtor que usa o AzureNamedKeyCredential parâmetro.

const producer = new EventHubProducerClient("NAMESPACE NAME.servicebus.windows.net", eventHubName, new AzureNamedKeyCredential("POLICYNAME", "KEYVALUE"));

Adicionar uma referência a AzureNamedKeyCredential.

const { AzureNamedKeyCredential } = require("@azure/core-auth");

Para usar um token SAS que gera usando o código, use o EventHubProducerClient construtor que recebe o AzureSASCredential parâmetro.

var token = createSharedAccessToken("https://NAMESPACENAME.servicebus.windows.net", "POLICYNAME", "KEYVALUE");
const producer = new EventHubProducerClient("NAMESPACENAME.servicebus.windows.net", eventHubName, new AzureSASCredential(token));

Adicionar uma referência a AzureSASCredential.

const { AzureSASCredential } = require("@azure/core-auth");

Java

private static String GetSASToken(String resourceUri, String keyName, String key)
  {
      long epoch = System.currentTimeMillis()/1000L;
      int week = 60*60*24*7;
      String expiry = Long.toString(epoch + week);

      String sasToken = null;
      try {
          String stringToSign = URLEncoder.encode(resourceUri, "UTF-8") + "\n" + expiry;
          String signature = getHMAC256(key, stringToSign);
          sasToken = "SharedAccessSignature sr=" + URLEncoder.encode(resourceUri, "UTF-8") +"&sig=" +
                  URLEncoder.encode(signature, "UTF-8") + "&se=" + expiry + "&skn=" + keyName;
      } catch (UnsupportedEncodingException e) {

          e.printStackTrace();
      }

      return sasToken;
  }


public static String getHMAC256(String key, String input) {
    Mac sha256_HMAC = null;
    String hash = null;
    try {
        sha256_HMAC = Mac.getInstance("HmacSHA256");
        SecretKeySpec secret_key = new SecretKeySpec(key.getBytes(), "HmacSHA256");
        sha256_HMAC.init(secret_key);
        Encoder encoder = Base64.getEncoder();

        hash = new String(encoder.encode(sha256_HMAC.doFinal(input.getBytes("UTF-8"))));

    } catch (InvalidKeyException e) {
        e.printStackTrace();
    } catch (NoSuchAlgorithmException e) {
        e.printStackTrace();
   } catch (IllegalStateException e) {
        e.printStackTrace();
    } catch (UnsupportedEncodingException e) {
        e.printStackTrace();
    }

    return hash;
}

PHP

function generateSasToken($uri, $sasKeyName, $sasKeyValue) 
{ 
    $targetUri = strtolower(rawurlencode(strtolower($uri))); 
    $expires = time(); 	
    $expiresInMins = 60; 
    $week = 60*60*24*7;
    $expires = $expires + $week; 
    $toSign = $targetUri . "\n" . $expires; 
    $signature = rawurlencode(base64_encode(hash_hmac('sha256', 			
     $toSign, $sasKeyValue, TRUE))); 
    
    $token = "SharedAccessSignature sr=" . $targetUri . "&sig=" . $signature . "&se=" . $expires . 		"&skn=" . $sasKeyName; 
    return $token; 
}

C#

private static string createToken(string resourceUri, string keyName, string key)
{
    TimeSpan sinceEpoch = DateTime.UtcNow - new DateTime(1970, 1, 1);
    var week = 60 * 60 * 24 * 7;
    var expiry = Convert.ToString((int)sinceEpoch.TotalSeconds + week);
    string stringToSign = HttpUtility.UrlEncode(resourceUri) + "\n" + expiry;
    using (var hmac = new HMACSHA256(Encoding.UTF8.GetBytes(key)))
    {
        var signature = Convert.ToBase64String(hmac.ComputeHash(Encoding.UTF8.GetBytes(stringToSign)));
        var sasToken = String.Format(CultureInfo.InvariantCulture, "SharedAccessSignature sr={0}&sig={1}&se={2}&skn={3}", HttpUtility.UrlEncode(resourceUri), HttpUtility.UrlEncode(signature), expiry, keyName);
        return sasToken;
    }
}

PowerShell

[Reflection.Assembly]::LoadWithPartialName("System.Web")| out-null
$URI="myNamespace.servicebus.windows.net/myEventHub/"
$Access_Policy_Name="RootManageSharedAccessKey"
$Access_Policy_Key="myPrimaryKey"
#Token expires now+300
$Expires=([DateTimeOffset]::Now.ToUnixTimeSeconds())+300
$SignatureString=[System.Web.HttpUtility]::UrlEncode($URI)+ "`n" + [string]$Expires
$HMAC = New-Object System.Security.Cryptography.HMACSHA256
$HMAC.key = [Text.Encoding]::ASCII.GetBytes($Access_Policy_Key)
$Signature = $HMAC.ComputeHash([Text.Encoding]::ASCII.GetBytes($SignatureString))
$Signature = [Convert]::ToBase64String($Signature)
$SASToken = "SharedAccessSignature sr=" + [System.Web.HttpUtility]::UrlEncode($URI) + "&sig=" + [System.Web.HttpUtility]::UrlEncode($Signature) + "&se=" + $Expires + "&skn=" + $Access_Policy_Name
$SASToken

Bash

get_sas_token() {
    local EVENTHUB_URI='EVENTHUBURI'
    local SHARED_ACCESS_KEY_NAME='SHAREDACCESSKEYNAME'
    local SHARED_ACCESS_KEY='SHAREDACCESSKEYVALUE'
    local EXPIRY=${EXPIRY:=$((60 * 60 * 24))} # Default token expiry is 1 day

    local ENCODED_URI=$(echo -n $EVENTHUB_URI | jq -s -R -r @uri)
    local TTL=$(($(date +%s) + $EXPIRY))
    local UTF8_SIGNATURE=$(printf "%s\n%s" $ENCODED_URI $TTL | iconv -t utf8)

    local HASH=$(echo -n "$UTF8_SIGNATURE" | openssl sha256 -hmac $SHARED_ACCESS_KEY -binary | base64)
    local ENCODED_HASH=$(echo -n $HASH | jq -s -R -r @uri)

    echo -n "SharedAccessSignature sr=$ENCODED_URI&sig=$ENCODED_HASH&se=$TTL&skn=$SHARED_ACCESS_KEY_NAME"
}

Autenticar publicadores do Event Hubs com SAS

Um editor de eventos define um ponto de extremidade virtual para um hub de eventos. O publicador só pode ser usado para enviar mensagens para um hub de eventos e não para receber mensagens.

Normalmente, um hub de eventos emprega um editor por cliente. Todas as mensagens enviadas para qualquer um dos editores de um hub de eventos são enfileiradas dentro desse hub de eventos. Os editores permitem um controle de acesso refinado.

Um token exclusivo é atribuído a cada cliente do Event Hubs, sendo transferido para o cliente. Os tokens são produzidos de tal forma que cada token único concede acesso a diferentes editores exclusivos. Um cliente que possui um token só pode enviar para um editor e nenhum outro editor. Se vários clientes compartilharem o mesmo token, então cada um deles compartilha o publicador.

Todos os tokens são atribuídos com chaves SAS. Normalmente, todos os tokens são assinados com a mesma chave. Os clientes não estão cientes da chave, o que impede que os clientes fabriquem tokens. Os clientes operam com os mesmos tokens até que eles expirem.

Por exemplo, para definir regras de autorização reduzidas apenas ao envio ou publicação para Event Hubs, é necessário definir uma regra de autorização de envio. Pode criar a regra ao nível do namespace ou dar um âmbito mais granular a uma entidade particular, como uma instância de hub de eventos ou um tópico. Um cliente ou uma aplicação que tenha este acesso granular é chamado de editor Event Hubs. Para configurar esta autenticação, siga estes passos:

  1. Cria uma chave SAS na entidade para a qual queres publicar e atribui-lhe o escopo de envio . Para obter mais informações, consulte Políticas de autorização de acesso compartilhado.

  2. Gera um token SAS com tempo de expiração para um editor específico usando a chave que criaste no passo 1. Para o código de exemplo, veja Gerar uma assinatura (token) a partir de uma política.

  3. Forneça o token ao cliente publicador, que só pode enviar para a entidade e o publicador aos quais o token concede acesso.

    Quando o token expira, o cliente perde o acesso para enviar ou publicar para a entidade.

Note

Embora não o recomendemos, pode equipar os dispositivos com tokens que concedam acesso a um hub de eventos ou a um namespace. Qualquer dispositivo que contenha esse token pode enviar mensagens diretamente para esse hub de eventos. Não podes colocar o dispositivo na lista de bloqueio para o impedir de enviar para esse hub de eventos.

Recomendamos que você forneça escopos específicos e granulares.

Important

Quando crias os tokens, cada cliente recebe o seu próprio token único.

Quando o cliente envia dados para um hub de eventos, marca o seu pedido com o token. Para impedir que um invasor espione e roube o token, a comunicação entre o cliente e o hub de eventos deve ocorrer por um canal criptografado.

Se um atacante roubar um token, pode fazer-se passar pelo cliente cujo token foi roubado. Se proibires um editor, esse cliente torna-se inutilizável até receber um novo token que utilize outro editor.

Autenticar os consumidores dos Centros de Eventos com SAS

Para autenticar aplicativos back-end que consomem dados gerados por produtores de Hubs de Eventos, a autenticação de token de Hubs de Eventos exige que seus clientes tenham os direitos de gerenciamento ou os privilégios de escuta atribuídos ao namespace dos Hubs de Eventos ou à instância ou tópico do hub de eventos. Os dados são consumidos de Hubs de Eventos usando grupos de consumidores. Embora a política SAS ofereça um escopo granular, esse escopo é definido apenas no nível da entidade e não no nível do consumidor. Isso significa que os privilégios definidos no nível do namespace ou no hub de eventos ou no nível do tópico são aplicados aos grupos de consumidores dessa entidade.

Desativar a autenticação local ou por chave SAS

Para determinados requisitos de segurança organizacional, você deseja desabilitar completamente a autenticação de chave local/SAS e confiar na autenticação baseada em ID do Microsoft Entra, que é a maneira recomendada de se conectar aos Hubs de Eventos do Azure. Você pode desabilitar a autenticação de chave local/SAS no nível de namespace dos Hubs de Eventos usando o portal do Azure ou o modelo do Azure Resource Manager.

Desative a autenticação por chave local ou SAS usando o portal

Você pode desabilitar a autenticação de chave local/SAS para um determinado namespace de Hubs de Eventos usando o portal do Azure.

  1. Navegue até ao seu namespace de Hubs de Eventos no portal do Azure.

  2. Na página Visão geral, selecione Habilitado para autenticação local, conforme mostrado na imagem a seguir.

    Captura de tela que mostra a Autenticação Local selecionada.

  3. No pop-up Autenticação Local, selecione Desativado e selecione OK.

    Captura de ecrã que mostra o pop-up Autenticação Local com a opção Desativado selecionada.

Desative a autenticação por chave local ou SAS usando um modelo

Você pode desativar a autenticação local para um determinado namespace de Hubs de Eventos, definindo a propriedade disableLocalAuth como true, conforme mostrado no seguinte modelo do Azure Resource Manager (Modelo ARM).

{
  "apiVersion": "2024-01-01",
  "name": "[parameters('eventHubNamespaceName')]",
  "type": "Microsoft.EventHub/Namespaces",
  "location": "[resourceGroup().location]",
  "sku": {
    "name": "Standard",
    "tier": "Standard"
  },
  "properties": {
    "isAutoInflateEnabled": true,
    "maximumThroughputUnits": 7,
    "disableLocalAuth": true
  },
  "resources": [
    {
      "apiVersion": "2024-01-01",
      "name": "[parameters('eventHubName')]",
      "type": "EventHubs",
      "dependsOn": [
        "[concat('Microsoft.EventHub/namespaces/', parameters('eventHubNamespaceName'))]"
      ],
      "properties": {
        "messageRetentionInDays": "[parameters('messageRetentionInDays')]",
        "partitionCount": "[parameters('partitionCount')]"
      }
    }
  ]
}

Samples

  • Consulte o exemplo .NET #6 neste local do GitHub para saber como publicar eventos em um hub de eventos usando credenciais de acesso compartilhado ou a identidade de credenciais padrão do Azure.
  • Consulte o exemplo .NET #5 neste local do GitHub para saber como consumir ou processar eventos usando credenciais de acesso compartilhado ou a identidade de credenciais padrão do Azure.

Agora que compreende a autenticação SAS, explore estes artigos relacionados: