Создание маркера SAS для делегирования пользователей с помощью Хранилища BLOB-объектов Azure и JavaScript

В этой статье показано, как создать маркер SAS для делегирования пользователей с помощью клиентской библиотеки Хранилища BLOB-объектов Azure версии 12 для JavaScript. SAS делегирования пользователей, представленный с версией 2018-11-09, защищен учетными данными Microsoft Entra и поддерживается только для службы BLOB-объектов:

  • предоставление доступа к существующему контейнеру;
  • предоставление доступа для создания, использования и удаления BLOB-объектов.

Чтобы создать SAS для делегирования пользователей, клиент должен иметь разрешения на вызов операции blobServiceClient.getUserDelegationKey. Эта операция возвращает ключ, который используется для подписывания SAS для делегирования пользователей. Субъект безопасности, который вызывает эту операцию, должен иметь роль Azure RBAC с разрешением на выполнение действия Microsoft.Storage/storageAccounts/blobServices/generateUserDelegationKey.

Клиенту, у которого есть SAS, предоставляются разрешения, определяемые пересечением набора разрешений, предоставленных субъекту безопасности, который запрашивал ключ для делегирования пользователей, и набора разрешений, предоставленных ресурсу в маркере SAS (в поле sp). Если разрешение, предоставленное субъекту безопасности в системе RBAC, не указано в маркере SAS, то это разрешение не будет предоставлено клиенту, который использует этот SAS для доступа к ресурсу.

Примеры фрагментов кода доступны на GitHub в виде исполняемых файлов Node.js.

Пакет (npm) | Примеры | Справочная документация по API | Исходный код библиотеки | Оставить отзыв

Рекомендации по маркерам SAS для делегирования пользователей

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

Рекомендации по использованию SAS

Использование DefaultAzureCredential в облаке Azure

Чтобы выполнять проверку подлинности в Azure без секретов, настройте управляемое удостоверение. Это позволяет использовать в коде объект DefaultAzureCredential.

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

  • Создание управляемого удостоверения
  • Настройка соответствующих ролей хранилища для удостоверения
  • Настройка среды Azure для работы с управляемым удостоверением

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

Использование DefaultAzureCredential при разработке в локальной среде

В локальной среде разработки удостоверение Azure (личная учетная запись для разработки, которая используется для входа на портал Azure) должно выполнять проверку подлинности в Azure, чтобы вы могли использовать одинаковый код в локальных и облачных средах выполнения.

Контейнер: добавление обязательных зависимостей в приложение

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

const {
    DefaultAzureCredential
} = require('@azure/identity');
const {
    ContainerClient,
    BlobServiceClient,
    ContainerSASPermissions,
    generateBlobSASQueryParameters,
    SASProtocol
} = require('@azure/storage-blob');

// used for local environment variables
require('dotenv').config();

Контейнер: получение переменных среды

Имя учетной записи хранения BLOB-объектов и имя контейнера — это минимально необходимый набор значений для создания маркера SAS для контейнера:

// Get environment variables for DefaultAzureCredential
const accountName = process.env.AZURE_STORAGE_ACCOUNT_NAME;
const containerName = process.env.AZURE_STORAGE_BLOB_CONTAINER_NAME;

Создание SAS с помощью DefaultAzureCredential

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

  • Настройка DefaultAzureCredential
    • В локальной среде разработки — примените личные удостоверения и настройте роли для хранилища
    • В облаке Azure — создайте управляемое удостоверение
  • Получите ключ делегирования пользователей из DefaultAzureCredential с помощью UserDelegationKey
  • Примените ключ делегирования пользователей для создания маркера SAS с нужными полями с помощью generateBlobSASQueryParameters

Контейнер: создание маркера SAS с помощью DefaultAzureCredential

Настроив удостоверение, используйте следующий код для создания маркера SAS для делегирования пользователей в области существующей учетной записи и существующего контейнера:

// Server creates User Delegation SAS Token for container
async function createContainerSas() {

    // Get environment variables
    const accountName = process.env.AZURE_STORAGE_ACCOUNT_NAME;
    const containerName = process.env.AZURE_STORAGE_BLOB_CONTAINER_NAME;

    // Best practice: create time limits
    const TEN_MINUTES = 10 * 60 * 1000;
    const NOW = new Date();

    // Best practice: set start time a little before current time to 
    // make sure any clock issues are avoided
    const TEN_MINUTES_BEFORE_NOW = new Date(NOW.valueOf() - TEN_MINUTES);
    const TEN_MINUTES_AFTER_NOW = new Date(NOW.valueOf() + TEN_MINUTES);

    // Best practice: use managed identity - DefaultAzureCredential
    const blobServiceClient = new BlobServiceClient(
        `https://${accountName}.blob.core.windows.net`,
        new DefaultAzureCredential()
      );

    // Best practice: delegation key is time-limited  
    // When using a user delegation key, container must already exist 
    const userDelegationKey = await blobServiceClient.getUserDelegationKey(
        TEN_MINUTES_BEFORE_NOW, 
        TEN_MINUTES_AFTER_NOW
    );

    // Need only list permission to list blobs 
    const containerPermissionsForAnonymousUser = "l";

    // Best practice: SAS options are time-limited
    const sasOptions = {
        containerName,                                           
        permissions: ContainerSASPermissions.parse(containerPermissionsForAnonymousUser), 
        protocol: SASProtocol.HttpsAndHttp,
        startsOn: TEN_MINUTES_BEFORE_NOW,
        expiresOn: TEN_MINUTES_AFTER_NOW
    };
 
    const sasToken = generateBlobSASQueryParameters(
        sasOptions,
        userDelegationKey,
        accountName 
    ).toString();

    return sasToken;
}

Приведенный выше код сервера создает поток значений, необходимых для создания маркера SAS для контейнера:

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

Контейнер: использование маркера SAS

Завершив создание маркера SAS для контейнера, примените его. Вот один из примеров использования маркера SAS:

  • создайте полный URL-адрес, включая имя контейнера и строку запроса. Строкой запроса здесь является маркер SAS;
  • создайте ContainerClient, используя URL-адрес контейнера;
  • используйте этот клиент: например получите список больших двоичных объектов в контейнере с помощью listBlobsFlat.
// Client or another process uses SAS token to use container
async function listBlobs(sasToken){

    // Get environment variables
    const accountName = process.env.AZURE_STORAGE_ACCOUNT_NAME;
    const containerName = process.env.AZURE_STORAGE_BLOB_CONTAINER_NAME;
    
    // Create Url
    // SAS token is the query string with typical `?` delimiter
    const sasUrl = `https://${accountName}.blob.core.windows.net/${containerName}?${sasToken}`;
    console.log(`\nContainerUrl = ${sasUrl}\n`);

    // Create container client from SAS token url
    const containerClient = new ContainerClient(sasUrl);

    let i = 1;

    // List blobs in container
    for await (const blob of containerClient.listBlobsFlat()) {
        console.log(`Blob ${i++}: ${blob.name}`);
    }    
}

BLOB-объект: добавление обязательных зависимостей в приложение

Включите необходимые зависимости для создания маркера SAS для BLOB-объекта.

const {
    DefaultAzureCredential
} = require('@azure/identity');
const {
    BlockBlobClient,
    BlobServiceClient,
    BlobSASPermissions,
    generateBlobSASQueryParameters,
    SASProtocol
} = require('@azure/storage-blob');

// used for local environment variables
require('dotenv').config();

BLOB-объект: получение переменных среды

Имя учетной записи хранения BLOB-объектов и имя контейнера — это минимально необходимый набор значений для создания маркера SAS для BLOB-объекта:

const accountName = process.env.AZURE_STORAGE_ACCOUNT_NAME;
const containerName = process.env.AZURE_STORAGE_BLOB_CONTAINER_NAME;

Если вы хотите создать маркер SAS для BLOB-объекта, вам потребуется имя большого двоичного объекта. Имя BLOB-объекта создается заранее на основе случайной строки, предоставляется пользователем или создается приложением.

// Create random blob name for text file
const blobName = `${(0|Math.random()*9e6).toString(36)}.txt`;

BLOB-объект: создание маркера SAS с помощью DefaultAzureCredential

Настроив удостоверение, используйте следующий код для создания маркера SAS для делегирования пользователей в области существующей учетной записи и существующего контейнера:

// Server creates User Delegation SAS Token for blob
async function createBlobSas(blobName) {

    // Get environment variables
    const accountName = process.env.AZURE_STORAGE_ACCOUNT_NAME;
    const containerName = process.env.AZURE_STORAGE_BLOB_CONTAINER_NAME;

    // Best practice: create time limits
    const TEN_MINUTES = 10 * 60 * 1000;
    const NOW = new Date();

    // Best practice: set start time a little before current time to 
    // make sure any clock issues are avoided
    const TEN_MINUTES_BEFORE_NOW = new Date(NOW.valueOf() - TEN_MINUTES);
    const TEN_MINUTES_AFTER_NOW = new Date(NOW.valueOf() + TEN_MINUTES);

    // Best practice: use managed identity - DefaultAzureCredential
    const blobServiceClient = new BlobServiceClient(
        `https://${accountName}.blob.core.windows.net`,
        new DefaultAzureCredential()
      );

    // Best practice: delegation key is time-limited  
    // When using a user delegation key, container must already exist 
    const userDelegationKey = await blobServiceClient.getUserDelegationKey(
        TEN_MINUTES_BEFORE_NOW, 
        TEN_MINUTES_AFTER_NOW
    );

    // Need only create/write permission to upload file
    const blobPermissionsForAnonymousUser = "cw"

    // Best practice: SAS options are time-limited
    const sasOptions = {
        blobName,
        containerName,                                           
        permissions: BlobSASPermissions.parse(blobPermissionsForAnonymousUser), 
        protocol: SASProtocol.HttpsAndHttp,
        startsOn: TEN_MINUTES_BEFORE_NOW,
        expiresOn: TEN_MINUTES_AFTER_NOW
    };
 
    const sasToken = generateBlobSASQueryParameters(
        sasOptions,
        userDelegationKey,
        accountName 
    ).toString();

    return sasToken;
}

Приведенный выше код создает поток значений, необходимых для создания маркера SAS для контейнера:

Завершив создание маркера SAS для BLOB-объекта, вы можете предоставить его клиенту, который будет использовать маркер. Затем клиент может использовать его для отправки BLOB-объекта. В примере клиентского кода показано, как проверить работу SAS от имени потребителя.

BLOB-объект: использование маркера SAS

Завершив создание маркера SAS для BLOB-объекта, примените его. Вот один из примеров использования маркера SAS:

  • создайте полный URL-адрес, включая имя контейнера, имя BLOB-объекта и строку запроса. Строкой запроса здесь является маркер SAS;
  • создайте BlockBlobClient с URL-адресом контейнера;
  • примените его в клиенте, например отправьте большой двоичный объект с помощью upload.
// Client or another process uses SAS token to upload content to blob
async function uploadStringToBlob(blobName, sasToken, textAsString){

    // Get environment variables
    const accountName = process.env.AZURE_STORAGE_ACCOUNT_NAME;
    const containerName = process.env.AZURE_STORAGE_BLOB_CONTAINER_NAME;

    // Create Url SAS token as query string with typical `?` delimiter
    const sasUrl = `https://${accountName}.blob.core.windows.net/${containerName}/${blobName}?${sasToken}`;
    console.log(`\nBlobUrl = ${sasUrl}\n`);

    // Create blob client from SAS token url
    const blockBlobClient = new BlockBlobClient(sasUrl);

    // Upload string
    await blockBlobClient.upload(textAsString, textAsString.length, undefined);    
}

См. также