Авторизация доступа к ресурсам концентраторов событий с помощью подписанных URL-адресов

Подписанный URL-адрес (SAS) обеспечивает детальный контроль над типом доступа, предоставляемым клиентам. Вот некоторые элементы управления, которые можно настроить в SAS.

  • Интервал, в течение которого sas действителен, который включает время начала и истечение срока действия.
  • Разрешения, предоставляемые с помощью SAS. Например, SAS для пространства имен концентраторов событий может предоставлять разрешение на прослушивание, но не на отправку.
  • Только клиенты, предоставляющие действительные учетные данные, могут передать данные в концентратор событий.
  • Клиент не может действовать от имени другого клиента.
  • Постороннему клиенту можно запретить отправку данных в концентратор событий.

В этой статье рассматривается проверка подлинности доступа к ресурсам концентраторов событий с помощью SAS. Дополнительные сведения о предоставлении доступа к ресурсам концентраторов событий с помощью SAS см. в этой статье.

Примечание.

Корпорация Майкрософт рекомендует использовать учетные данные Microsoft Entra, если это возможно для обеспечения безопасности, а не использовать подписанные URL-адреса, что может быть проще скомпрометировано. Хотя вы можете продолжать использовать подписанные URL-адреса (SAS) для предоставления детального доступа к ресурсам Центров событий, идентификатор Microsoft Entra ID предлагает аналогичные возможности без необходимости управлять маркерами SAS или беспокоиться о отмене скомпрометированного SAS.

Дополнительные сведения об интеграции Microsoft Entra в Центры событий Azure см. в разделе "Авторизация доступа к центрам событий" с помощью идентификатора Microsoft Entra.

Настройка проверки подлинности SAS

Правило SAS можно настроить в пространстве имен Центров событий или сущности (экземпляр концентратора событий или раздел Kafka в концентраторе событий). Настройка правила SAS в группе потребителей в настоящее время не поддерживается, но вы можете использовать правила, настроенные в пространстве имен или сущности для защиты доступа к группе потребителей.

На следующем рисунке показано, как правила авторизации применяются к примерам сущностей.

Настройка правила авторизации

В этом примере в примере пространства имен Центров событий (ExampleNamespace) есть две сущности: eh1 и Kafka topic1. Правила авторизации определяются как на уровне сущности, так и на уровне пространства имен.

Правила авторизации manageRuleNS, sendRuleNS и listenRuleNS применяются как к eh1, так и t1. Правила авторизации listenRule-eh и sendRule-eh применяются только к правилу авторизации eh1, а правило авторизации sendRuleT применяется только к разделу1.

При использовании правила авторизации sendRuleNS клиентские приложения могут отправляться как в eh1, так и в раздел1. При использовании правила авторизации sendRuleT применяется детальный доступ только к разделу1, поэтому клиентские приложения, использующие это правило для доступа, теперь не могут отправляться в eh1, а только в раздел1.

Создание маркера подписанного URL-адреса

Каждый клиент, который имеет доступ к имени правила авторизации и одному из его ключей подписи, может создать маркер SAS. Маркер создается путем составления строки в следующем формате:

  • se — срок действия маркера. Количество секунд с начала эпохи UNIX (00:00:00 UTC 1 января 1970 г.) до истечения срока действия маркера.
  • skn — имя правила авторизации, которое является именем ключа SAS.
  • sr — URI ресурса, к которому осуществляется доступ.
  • sig — подпись.

Строка подписи — это хэш SHA-256, вычисляемый на основе URI ресурса (в значении области, описанном в предыдущем разделе), и строковое представление срока действия маркера, разделенные символом CRLF. Вычисление хэша напоминает следующий псевдокод и возвращает 256-битное (32-байтное) значение хэша.

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

Маркер содержит нехэшируемые значения, что позволяет получателю повторно вычислить хэш с теми же параметрами и проверить, что издатель использует допустимый ключ подписи.

URI ресурса — это полный URI ресурса служебной шины, к которому запрашивается доступ. Например, http://<namespace>.servicebus.windows.net/<entityPath> или sb://<namespace>.servicebus.windows.net/<entityPath>. Вся строка будет выглядеть так: http://contoso.servicebus.windows.net/eh1.

URI должен быть закодирован с помощью знака процента.

Правило SAS, используемое для подписывания, должно быть настроено для сущности, указанной этим универсальным кодом ресурса (URI) или одним из его иерархических родителей. Например, в предыдущем примере это — http://contoso.servicebus.windows.net/eh1 или http://contoso.servicebus.windows.net.

Маркер SAS действителен для всех ресурсов с префиксом <resourceURI>, используемым в строке подписи.

Примечание

Маркер доступа создается для концентраторов событий с помощью политики общего доступа. Дополнительные сведения см. в разделе Политика авторизации общего доступа.

Создание (маркера) подписи на основе политики

В следующем разделе показано, как создать маркер SAS с помощью политик подписанного URL-доступа.

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

Чтобы использовать имя политики и значение ключа для подключения к концентратору событий, используйте конструктор EventHubProducerClient, принимающий параметр AzureNamedKeyCredential.

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

Необходимо добавить ссылку на AzureNamedKeyCredential.

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

Чтобы использовать маркер SAS, созданный с помощью кода, используйте EventHubProducerClient конструктор, принимающий AzureSASCredential параметр.

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

Необходимо добавить ссылку на 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"
}

Проверка подлинности издателей концентраторов событий с помощью SAS

Издатель событий определяет виртуальную конечную точку для концентратора событий. Издатель можно использовать только для отправки сообщений в концентратор событий, но не для их получения.

Как правило, концентратор событий использует один издатель на клиент. Все сообщения, отправленные любому из издателей концентратора событий, добавляются в очередь этого концентратора событий. Издатели обеспечивают точно детализированный контроль доступа.

Каждому клиенту Центров событий назначается уникальный маркер, который передается в клиент. Маркеры созданы таким образом, что каждый уникальный маркер предоставляет доступ к одному уникальному издателю. Клиент, имеющий маркер, может отправлять данные только одному издателю и никаким больше. Если несколько клиентов совместно используют один маркер, они также совместно используют издатель.

Всем маркерам назначаются ключи SAS. Как правило, все маркеры должны быть подписаны тем же ключом. Клиенты не знают о ключе, что не дает клиентам создавать маркеры. Клиенты используют одни и те же маркеры до истечения срока их действия.

Например, чтобы определить правила авторизации, разрешающие только отправку данных в концентраторы событий и публикацию данных в концентраторах, необходимо определить правило авторизации отправки. Это можно сделать на уровне пространства имен или предоставить более детализированные область определенной сущности (экземпляр концентраторов событий или раздел). Клиент или приложение, область действия которого имеет такой детализированный доступ, называется издателем концентраторов событий. Для этого выполните следующие действия.

  1. Создайте ключ SAS для сущности, которую необходимо опубликовать, чтобы назначить ей область отправки. Дополнительные сведения см. в разделе Политики авторизации общего доступа.

  2. Создайте маркер SAS с временем окончания срока действия для определенного издателя с помощью ключа, созданного в шаге 1. Пример кода см. в разделе Создание (маркера) подписи на основе политики.

  3. Предоставьте маркер клиенту издателя, который может отправлять данные только сущности и издателю, к которым маркер предоставляет доступ.

    После истечения срока действия маркера клиент теряет доступ к отправке данных в сущность или их публикации в сущности.

Примечание

Хотя это не рекомендуется, можно предоставить устройствам маркеры, которые обеспечивают прямой доступ к концентратору событий или пространству имен. Любое устройство с этим маркером может отправлять сообщения непосредственно в концентратор событий. Кроме того, устройство нельзя внести в список блокировок, чтобы запретить отправку данных в концентратор событий.

Рекомендуется всегда предоставлять определенные и детальные области.

Важно!

После создания маркеров каждому клиенту присваивается собственный уникальный маркер.

Когда клиент отправляет данные в концентратор событий, к запросу прикрепляется специальный маркер. Во избежание перехвата и кражи маркера злоумышленником связь между клиентом и концентратором событий должна выполняться по зашифрованному каналу.

Если маркер украден злоумышленником, злоумышленник может действовать от имени клиента, маркер которого был украден. Добавление издателя в список блокировок означает, что этот клиент не сможет работать, пока не получит новый маркер, использующий другой издатель.

Проверка подлинности потребителей концентраторов событий с помощью SAS

Для проверки подлинности серверных приложений, которые используют данные, формируемые производителями концентраторов событий, проверка подлинности маркеров концентраторов событий требует, чтобы клиенты имели права управления или прослушивания, назначенные пространству имен концентраторов событий либо экземпляру или разделу концентратора событий. Данные поступают из концентраторов событий с помощью групп потребителей. Хотя политика SAS обеспечивает детальную область, эта область определяется только на уровне сущности, а не потребителя. Это означает, что привилегии, определенные на уровне пространства имен или на уровне экземпляра или раздела концентратора событий, будут применяться к группам потребителей этой сущности.

Отключение проверки подлинности локального ключа/ключа SAS

Для определенных требований к безопасности организации необходимо полностью отключить проверку подлинности локального или SAS-ключа и использовать проверку подлинности на основе идентификатора Microsoft Entra, которая является рекомендуемым способом подключения к Центры событий Azure. Вы можете отключить проверку подлинности локального ключа/ключа SAS на уровне пространства имен Центров событий с помощью портала Azure или шаблона Azure Resource Manager.

Отключение проверки подлинности ключа/ключа SAS на портале

На портале Azure можно отключить проверку подлинности локального ключа/ключа SAS для данного пространства имен Центров событий.

Как показано на следующем рисунке, в разделе обзора пространства имен выберите "Локальная проверка подлинности".

Обзор пространства имен для отключения локальной проверки подлинности

А затем нажмите кнопку "Отключено " и нажмите кнопку "ОК ", как показано на следующем рисунке. Отключение локальной проверки подлинности

Отключение проверки подлинности локального ключа/ключа SAS с помощью шаблона

Локальную проверку подлинности для заданного пространства имен Центров событий можно отключить, задав для свойства disableLocalAuth значение true, как показано в следующем шаблоне Azure Resource Manager (шаблон ARM).

"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": false
      },
      "resources": [
        {
          "apiVersion": "2017-04-01",
          "name": "[parameters('eventHubName')]",
          "type": "EventHubs",
          "dependsOn": [
            "[concat('Microsoft.EventHub/namespaces/', parameters('eventHubNamespaceName'))]"
          ],
          "properties": {
            "messageRetentionInDays": "[parameters('messageRetentionInDays')]",
            "partitionCount": "[parameters('partitionCount')]"
          }

        }
      ]
    }
  ]

Примеры

  • См. пример .NET #6 в этом расположении GitHub, чтобы узнать, как публиковать события в концентраторе событий с использованием учетных данных общего доступа или удостоверения учетных данных Azure по умолчанию.
  • См. пример .NET #5 в этом расположении GitHub, чтобы узнать, как использовать или обрабатывать события с использованием учетных данных общего доступа или удостоверения учетных данных Azure по умолчанию.

Дальнейшие действия

См. следующие статьи:

См. следующие статьи по этой теме: