Eseguire l'autenticazione dell'accesso alle risorse di Hub eventi tramite firme di accesso condiviso

La firma di accesso condiviso offre un controllo granulare sul tipo di accesso concesso ai client. Ecco alcuni dei controlli che è possibile impostare in una firma di accesso condiviso:

  • Intervallo in cui la firma di accesso condiviso è valida, che include l'ora di inizio e l'ora di scadenza.
  • Le autorizzazioni concesse dalla firma di accesso condiviso. Ad esempio, una firma di accesso condiviso per uno spazio dei nomi di Hub eventi potrebbe concedere l'autorizzazione di ascolto, ma non l'autorizzazione di invio.
  • Solo i client che presentano le credenziali valide possono inviare dati a un hub eventi.
  • Un client non può rappresentare un altro client.
  • A un client non autorizzato può essere impedito l'invio di dati a un hub eventi.

Questo articolo tratta dell'autenticazione dell'accesso alle risorse di Hub eventi tramite firme di accesso condiviso. Per informazioni sull'autorizzazione dell'accesso alle risorse di Hub eventi tramite firma di accesso condiviso, vedere questo articolo.

Nota

È consigliabile usare le credenziali di Microsoft Entra quando possibile come procedura consigliata per la sicurezza, anziché usare le firme di accesso condiviso, che possono essere compromesse più facilmente. Anche se è possibile continuare a usare firme di accesso condiviso (SAS) per concedere l'accesso granulare alle risorse di Hub eventi, Microsoft Entra ID offre funzionalità simili senza dover gestire i token di firma di accesso condiviso o preoccuparsi di revocare una firma di accesso condiviso compromessa.

Per altre informazioni sull'integrazione di Microsoft Entra in Hub eventi di Azure, vedere Autorizzare l'accesso a Hub eventi usando Microsoft Entra ID.

Configurazione dell'autenticazione SAS

È possibile configurare una regola di firma di accesso condiviso in uno spazio dei nomi di Hub eventi o in un'entità (hub eventi o argomento Kafka). La configurazione di una regola di firma di accesso condiviso in un gruppo di consumer non è attualmente supportata, ma è possibile usare regole configurate in uno spazio dei nomi o un'entità per proteggere l'accesso al gruppo di consumer. L'immagine seguente mostra come le regole di autorizzazione si applicano alle entità di esempio.

Diagramma che mostra gli hub eventi con regole di ascolto, invio e gestione.

In questo esempio lo spazio dei nomi di Hub eventi di esempio (ExampleNamespace) ha due entità: eh1 e Kafka topic1. Le regole di autorizzazione vengono definite sia a livello di entità che a livello di spazio dei nomi.

Le regole di autorizzazione manageRuleNS, sendRuleNS e listenRuleNS si applicano sia a eh1 che a topic1. Le regole di autorizzazione listenRule-eh e sendRule-eh si applicano solo a eh1 e la regola di autorizzazione sendRuleT si applica solo a topic1.

Quando si usa la regola di autorizzazione sendRuleNS, le applicazioni client possono essere inviate sia a eh1 che a topic1. Quando si usa la regola di autorizzazione sendRuleT, applica solo l'accesso granulare a topic1 e quindi le applicazioni client che usano questa regola per l'accesso non possono effettuare invii a eh1, ma solo a topic1.

Generare un token della firma di accesso condiviso

Qualsiasi client che abbia accesso al nome di una regola di autorizzazione e a una delle relative chiavi di firma può generare un token di firma di accesso condiviso. Il token viene generato creando una stringa nel formato seguente:

  • se - Istante di scadenza del token. Valore intero che riflette i secondi trascorsi dalle 00:00:00 UTC del 1° gennaio 1970 (epoca UNIX) quando il token scade
  • skn: nome della regola di autorizzazione, ovvero il nome della chiave di firma di accesso condiviso.
  • sr: URI della risorsa a cui si ha accesso.
  • sig: firma.

Signature-string è il codice hash SHA-256 calcolato in base all'URI della risorsa (l'ambito descritto nella sezione precedente) e la rappresentazione di stringa dell'istante di scadenza del token, separati da un ritorno a capo e dall'avanzamento riga (CRLF). Il calcolo del codice hash è simile allo pseudo codice seguente e restituisce un valore hash a 256 bit o 32 byte.

SHA-256('https://<yournamespace>.servicebus.windows.net/'+'\n'+ 1438205742)

Il token contiene i valori non hash in modo che il destinatario possa ricalcolare il codice hash con gli stessi parametri, verificando che l'autorità di certificazione sia in possesso di una chiave di firma valida.

L'URI di risorsa è l'URI completo della risorsa del bus di servizio a cui si richiede l'accesso. Ad esempio http://<namespace>.servicebus.windows.net/<entityPath> o sb://<namespace>.servicebus.windows.net/<entityPath>, ovvero http://contoso.servicebus.windows.net/eh1.

L'URI deve essere codificato in percentuale.

La regola di autorizzazione di accesso condiviso usata per la firma deve essere configurata nell'entità specificata da questo URI o in un elemento padre nella gerarchia. Ad esempio http://contoso.servicebus.windows.net/eh1 o http://contoso.servicebus.windows.net nell'esempio precedente.

Un token di firma di accesso condiviso è valido per tutte le risorse il cui prefisso è <resourceURI> usato nella stringa della firma.

Nota

Si genera un token di accesso per Hub eventi usando i criteri di accesso condiviso. Per altre informazioni, vedere Criteri di autorizzazione di accesso condiviso.

Generazione di una firma (token) da un criterio

La sezione seguente illustra la generazione di un token di firma di accesso condiviso con i relativi criteri.

NodeJS

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

Per usare un nome di criterio e un valore di chiave per connettersi a un hub eventi, usare il costruttore EventHubProducerClient che accetta il parametro AzureNamedKeyCredential.

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

È necessario aggiungere un riferimento a AzureNamedKeyCredential.

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

Per usare un token di firma di accesso condiviso generato usando il codice, usare il costruttore EventHubProducerClient che accetta il parametro AzureSASCredential.

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

È necessario aggiungere un riferimento 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"
}

Autenticazione dei publisher di Hub eventi con firma di accesso condiviso

Un publisher di eventi definisce un endpoint virtuale per un hub eventi. Il publisher può essere usato solo per inviare messaggi a un hub eventi e non per ricevere messaggi.

In genere, un hub eventi usa un solo publisher per ogni client. Tutti i messaggi inviati a uno dei publisher di un hub eventi vengono accodati all'interno di tale hub eventi. Publishers consentono il controllo di accesso con granularità fine.

A ogni client di Hub eventi viene assegnato un token univoco, che viene caricato nel client. I token vengono prodotti in modo tale che ogni token univoco conceda l'accesso a un diverso autore univoco. Un client in possesso di un token può inviare a un solo publisher e a nessun altro. Se più client condividono lo stesso token, ognuno condivide il publisher.

A tutti i token vengono assegnate chiavi SAS. Tutti i token vengono in genere firmati con la stessa chiave. I client non conoscono la chiave, quindi non possono creare token. I client operano sugli stessi token fino alla scadenza.

Ad esempio, per definire regole di autorizzazione con ambito limitato all'invio/pubblicazione a Hub eventi, è necessario definire una regola di autorizzazione di invio. L'operazione può essere eseguita a livello di spazio dei nomi o fornendo un ambito più granulare a una determinata entità (istanza di hub eventi o un argomento). Un client o un'applicazione con ambito con tale accesso granulare viene chiamato Server di pubblicazione di Hub eventi. A tale scopo, effettuare i passaggi seguenti:

  1. Creare una chiave di firma di accesso condiviso nell'entità da pubblicare e a cui assegnare l'ambito invio. Per altre informazioni, vedere Criteri di autorizzazione di accesso condiviso.

  2. Generare un token di firma di accesso condiviso con una scadenza per un server di pubblicazione specifico usando la chiave generata nel passaggio 1. Per il codice di esempio, vedere Generazione di una firma (token) da un criterio.

  3. Fornire il token al client di pubblicazione, che può effettuare invii solo all'entità e al server di pubblicazione a cui il token concede l'accesso.

    Una volta scaduto il token, il client perde l'accesso all'entità di invio/pubblicazione.

Nota

Anche se non è consigliabile, è possibile dotare i dispositivi di token che concedono l'accesso a un hub eventi o a uno spazio dei nomi. Qualsiasi dispositivo che contiene un token di questo tipo può inviare messaggi direttamente a tale hub eventi. Non è possibile disattivare l'invio a tale Hub eventi per il dispositivo.

È consigliabile assegnare ambiti specifici e granulari.

Importante

Dopo avere creato i token, viene eseguito il provisioning di ogni client con il proprio token univoco.

Quando il client invia dati a un hub eventi, contrassegna la richiesta con il token. Per evitare che un utente malintenzionato intercetti e rubi il token, la comunicazione tra il client e l'Hub eventi deve verificarsi su un canale crittografato.

In caso di furto di un token da parte di un utente malintenzionato, l'autore dell'attacco può rappresentare il client il cui token è stato rubato. La disattivazione di un publisher rende il rendering di tale client inutilizzabile fino a che non riceve un nuovo token che usa un autore diverso.

Autenticazione dei consumer di Hub eventi con firma di accesso condiviso

Per autenticare le applicazioni back-end che utilizzano i dati generati dai producer di Hub eventi, l'autenticazione dei token di Hub eventi richiede ai client di avere diritti di gestione o privilegi di ascolto assegnati al relativo spazio dei nomi di Hub eventi oppure all'istanza o all'argomento dell'hub eventi. I dati vengono utilizzati da Hub eventi tramite gruppi di consumer. Anche se i criteri di firma di accesso condiviso offrono un ambito granulare, questo ambito viene definito solo a livello di entità e non a livello di consumer. Ciò significa che i privilegi definiti a livello di spazio dei nomi o dell'hub eventi o dell'argomento vengono applicati ai gruppi di consumer di tale entità.

Disabilitare l'autenticazione della chiave locale o SAS

Per determinati requisiti di sicurezza dell'organizzazione, si vuole disabilitare completamente l'autenticazione con chiave locale/firma di accesso condiviso e ci si vuole basare sull'autenticazione con Microsoft Entra ID, che è il modo consigliato per connettersi a Hub eventi di Azure. È possibile disabilitare l'autenticazione della chiave locale/SAS a livello di spazio dei nomi di Hub eventi usando il portale di Azure o il modello di Azure Resource Manager.

Disabilitare l'autenticazione della chiave locale o SAS tramite il portale

È possibile disabilitare l'autenticazione della chiave locale/SAS per uno spazio dei nomi di Hub eventi specifico usando il portale di Azure.

  1. Passare allo spazio dei nomi di Hub eventi nel portale di Azure.

  2. Nella pagina Panoramica selezionare Abilitato per Autenticazione locale, come illustrato nell'immagine seguente.

    Screenshot che mostra l'opzione Autenticazione locale selezionata.

  3. Nella finestra popup Autenticazione locale selezionare Disabilitato e selezionare OK.

    Screenshot che mostra il popup Autenticazione locale con l'opzione Disabilitata selezionata.

Disabilitare l'autenticazione della chiave locale o SAS tramite un modello

È possibile disabilitare l'autenticazione locale per uno spazio dei nomi di Hub eventi specifico impostando la proprietà disableLocalAuth su true, come illustrato nel modello di Azure Resource Manager seguente.

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

        }
      ]
    }
  ]

Esempi

  • Vedere l'esempio .NET n. 6 in questa posizione di GitHub per informazioni su come pubblicare eventi in un hub eventi usando credenziali di accesso condiviso o l'identità predefinita delle credenziali di Azure.
  • Vedere l'esempio .NET n. 5 in questa posizione di GitHub per informazioni su come utilizzare o elaborare eventi usando credenziali di accesso condiviso o l'identità predefinita delle credenziali di Azure.

Passaggi successivi

Fai riferimento ai seguenti articoli:

Vedere gli articoli correlati seguenti: