You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Azure VM中无需存储账户访问密钥生成Blob SAS令牌的替代方案

问题描述

我的Web应用由ReactJS SPA前端和部署在Azure VM中的Web API后端构成。用户上传文件时,后端会生成带SAS令牌的URL,前端通过该URL直接从浏览器上传文件到Azure存储Blob容器,无需经过后端VM中转。

目前后端用以下代码生成带SAS令牌的URL:

function generate_signed_url(BLOB_NAME, AZURE_PRIMARY_KEY) {
    
    const ACCOUNT_NAME = process.env.AZURE_BLOB_STORAGE_ACCOUNT_NAME;
    const CONTAINER_NAME = process.env.AZURE_BLOB_STORAGE_CONTAINER_NAME;
    const ACCESS_KEY = process.env.AZURE_BLOB_STORAGE_ACCESS_KEY;

    const sharedKeyCredential = new StorageSharedKeyCredential(accountName=ACCOUNT_NAME, accountKey=ACCESS_KEY)
      
    //This URL will be valid for 1 hour
    const expDate = new Date(new Date().valueOf() + 3600 * 1000);

    // Generate service level SAS for a blob
    const blobSAS = generateBlobSASQueryParameters({
      containerName: CONTAINER_NAME, // Required
      blobName: BLOB_NAME, // Required
      permissions: BlobSASPermissions.parse("racwd"), // Required
      startsOn: new Date(), // Optional
      expiresOn: expDate, // Required. Date type
      cacheControl: "cache-control-override", // Optional
      contentDisposition: "content-disposition-override", // Optional
      contentEncoding: "content-encoding-override", // Optional
      contentLanguage: "content-language-override", // Optional
      contentType: "content-type-override", // Optional
      ipRange: { start: "0.0.0.0", end: "255.255.255.255" }, // Optional
      protocol: SASProtocol.HttpsAndHttp, // Optional
      version: "2016-05-31" // Optional
    },
    sharedKeyCredential 
    ).toString();

    SaSURL = `https://${ACCOUNT_NAME}.blob.core.windows.net/${AZURE_CONTAINER}/${AZURE_BLOB}?${containerSAS}`;
    
    console.log(`SAS URL for blob is: ${SaSURL}`);
    return SaSURL;
}

但这种方式需要把Azure存储账户访问密钥存在VM的环境变量里,属于不安全的实践:

const ACCESS_KEY = process.env.AZURE_BLOB_STORAGE_ACCESS_KEY

请问有没有更专业的替代方案?

替代方案

以下是几种更安全合规的替代方案,避免直接存储访问密钥:

1. 使用Azure托管标识(Managed Identity)

这是Azure推荐的首选方案,完全不需要存储任何密钥:

  • 给Azure VM启用系统分配或用户分配的托管标识
  • 给该托管标识授予Azure存储账户的Storage Blob Data Contributor(或更细粒度的权限,比如仅允许生成SAS的权限)角色
  • 后端代码中使用Azure Identity SDK获取令牌,替代共享密钥生成SAS:
    const { DefaultAzureCredential } = require("@azure/identity");
    const { BlobServiceClient, BlobSASPermissions } = require("@azure/storage-blob");
    
    async function generate_signed_url(BLOB_NAME) {
      const ACCOUNT_NAME = process.env.AZURE_BLOB_STORAGE_ACCOUNT_NAME;
      const CONTAINER_NAME = process.env.AZURE_BLOB_STORAGE_CONTAINER_NAME;
      
      // 使用托管标识获取凭证
      const credential = new DefaultAzureCredential();
      const blobServiceClient = new BlobServiceClient(
        `https://${ACCOUNT_NAME}.blob.core.windows.net`,
        credential
      );
    
      const expDate = new Date(Date.now() + 3600 * 1000);
      const containerClient = blobServiceClient.getContainerClient(CONTAINER_NAME);
      const blobClient = containerClient.getBlobClient(BLOB_NAME);
    
      // 生成SAS令牌
      const sasToken = await blobClient.generateSasUrl({
        permissions: BlobSASPermissions.parse("racwd"),
        expiresOn: expDate,
        // 其他可选参数按需设置
      });
    
      console.log(`SAS URL for blob is: ${sasToken}`);
      return sasToken;
    }
    
  • 优势:无需管理密钥,Azure自动处理身份验证,权限可通过IAM精细控制,泄露风险为零。

2. 使用Azure Key Vault存储访问密钥

如果暂时无法使用托管标识,可将存储账户访问密钥存入Azure Key Vault:

  • 创建Azure Key Vault实例,将存储账户的访问密钥作为机密存入Vault
  • 给VM的托管标识(或服务主体)授予Key Vault的Secret User权限,允许读取该机密
  • 后端代码从Key Vault中获取访问密钥,而非从环境变量读取:
    const { SecretClient } = require("@azure/keyvault-secrets");
    const { DefaultAzureCredential } = require("@azure/identity");
    const { StorageSharedKeyCredential, generateBlobSASQueryParameters, BlobSASPermissions } = require("@azure/storage-blob");
    
    async function generate_signed_url(BLOB_NAME) {
      const ACCOUNT_NAME = process.env.AZURE_BLOB_STORAGE_ACCOUNT_NAME;
      const CONTAINER_NAME = process.env.AZURE_BLOB_STORAGE_CONTAINER_NAME;
      const KEY_VAULT_URL = process.env.AZURE_KEY_VAULT_URL;
      const SECRET_NAME = "AzureBlobStorageAccessKey"; // Key Vault中存储密钥的机密名称
    
      // 从Key Vault获取访问密钥
      const credential = new DefaultAzureCredential();
      const secretClient = new SecretClient(KEY_VAULT_URL, credential);
      const secret = await secretClient.getSecret(SECRET_NAME);
      const ACCESS_KEY = secret.value;
    
      // 生成SAS逻辑
      const sharedKeyCredential = new StorageSharedKeyCredential(ACCOUNT_NAME, ACCESS_KEY);
      const expDate = new Date(Date.now() + 3600 * 1000);
    
      const blobSAS = generateBlobSASQueryParameters({
        containerName: CONTAINER_NAME,
        blobName: BLOB_NAME,
        permissions: BlobSASPermissions.parse("racwd"),
        expiresOn: expDate,
        // 其他参数按需设置
      }, sharedKeyCredential).toString();
    
      const sasUrl = `https://${ACCOUNT_NAME}.blob.core.windows.net/${CONTAINER_NAME}/${BLOB_NAME}?${blobSAS}`;
      console.log(`SAS URL for blob is: ${sasUrl}`);
      return sasUrl;
    }
    
  • 优势:密钥集中存储在安全的Vault中,可设置自动轮换,权限受控,比直接存在VM环境变量安全得多。

3. 使用存储账户的用户委派SAS(User Delegation SAS)

如果需要更高的安全性和审计能力,可使用用户委派SAS:

  • 基于Azure AD身份生成SAS,而非存储账户密钥
  • 给身份授予Storage Blob Data Contributor或Storage Blob Data Owner角色
  • 代码中通过Azure AD令牌获取用户委派密钥,再生成SAS:
    const { DefaultAzureCredential } = require("@azure/identity");
    const { BlobServiceClient, generateBlobSASQueryParameters, BlobSASPermissions } = require("@azure/storage-blob");
    
    async function generate_signed_url(BLOB_NAME) {
      const ACCOUNT_NAME = process.env.AZURE_BLOB_STORAGE_ACCOUNT_NAME;
      const CONTAINER_NAME = process.env.AZURE_BLOB_STORAGE_CONTAINER_NAME;
      
      const credential = new DefaultAzureCredential();
      const blobServiceClient = new BlobServiceClient(
        `https://${ACCOUNT_NAME}.blob.core.windows.net`,
        credential
      );
    
      // 获取用户委派密钥
      const userDelegationKey = await blobServiceClient.getUserDelegationKey(
        new Date(),
        new Date(Date.now() + 3600 * 1000)
      );
    
      const expDate = new Date(Date.now() + 3600 * 1000);
      const blobSAS = generateBlobSASQueryParameters({
        containerName: CONTAINER_NAME,
        blobName: BLOB_NAME,
        permissions: BlobSASPermissions.parse("racwd"),
        expiresOn: expDate,
        // 其他参数按需设置
      }, userDelegationKey, ACCOUNT_NAME).toString();
    
      const sasUrl = `https://${ACCOUNT_NAME}.blob.core.windows.net/${CONTAINER_NAME}/${BLOB_NAME}?${blobSAS}`;
      console.log(`SAS URL for blob is: ${sasUrl}`);
      return sasUrl;
    }
    
  • 优势:SAS的权限与Azure AD身份绑定,可通过Azure AD审计日志追踪操作,比服务SAS更安全,适合敏感数据场景。

内容的提问来源于stack exchange,提问作者Kid_Learning_C

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.16 09:24:55