教程:使用 Windows VM 系统分配的托管标识访问 Azure 存储

Azure 资源的托管标识是 Microsoft Entra ID 的一项功能。 支持 Azure 资源的托管标识的每个 Azure 服务都受其自己的时间线限制。 在开始之前,请务必查看资源的托管标识的可用性状态以及已知问题

本教程介绍了如何使用 Windows 虚拟机 (VM) 的系统分配的托管标识来访问 Azure 存储。 您将学习如何:

  • 在存储帐户中创建 Blob 容器
  • 向 Windows VM 的系统分配的托管标识授予对存储帐户的访问权限
  • 获取访问令牌并使用它来调用 Azure 存储

注意

适用于 Azure 存储的 Microsoft Entra 身份验证当前处于公共预览版。

先决条件

启用

启用系统分配的托管标识只需单击一次即可。 可以在创建 VM 的过程中或在现有 VM 的属性中启用它。

屏幕截图显示虚拟机的“系统分配”选项卡,可以在其中打开“系统分配”状态。

若要在新 VM 上启用系统分配的托管标识,请执行以下操作:

  1. 登录到 Azure 门户

  2. 创建启用了系统分配标识的虚拟机

授予访问权限

创建存储帐户

在本部分中,创建一个存储帐户。

  1. 选择 Azure 门户左上角的“+ 创建资源”按钮。

  2. 单击“存储”,然后单击“存储帐户 - Blob、文件、表、队列”。

  3. 在“名称”下,输入存储帐户的名称。

  4. “部署模型”和“帐户类型”应分别设置为“资源管理器”和“存储(常规用途 v1)”。

  5. 确保“订阅”和“资源组”与上一步中创建 VM 时指定的名称匹配。

  6. 选择创建

    屏幕截图显示如何新建存储帐户。

创建 blob 容器,并将文件上传到存储帐户

文件需要 blob 存储,因此你需要创建用于存储文件的 blob 容器。 然后将文件上传到新存储帐户中的 blob 容器。

  1. 导航回新创建的存储帐户。

  2. 在“Blob 服务”下,选择“容器”。

  3. 选择页面顶部的“+ 容器”。

  4. 在“新建容器”下,输入容器的名称,并保留“公共访问级别”下的默认值。

    屏幕截图显示如何创建存储容器。

  5. 使用你选择的编辑器,在本地计算机上创建一个标题为 hello world.txt 的文件。 打开该文件并添加文本“Hello world! :)”(不包括引号),然后保存该文件。

  6. 通过单击容器名称并单击“上传”,将该文件上传到新创建的容器。

  7. 在“上传 Blob”窗格中的“文件”下,选择文件夹图标并浏览到本地计算机上的文件 hello_world.txt,然后选择该文件并单击“上传”。 屏幕截图显示文本文件上传屏幕。

授予访问权限

本部分介绍如何授予 VM 访问 Azure 存储容器的权限。 可以使用 VM 的系统分配的托管标识检索 Azure 存储 blob 中的数据。

  1. 导航回新创建的存储帐户。

  2. 选择“访问控制 (IAM)”。

  3. 选择“添加”>“添加角色分配”,打开“添加角色分配”页面 。

  4. 分配以下角色。 有关详细步骤,请参阅使用 Azure 门户分配 Azure 角色

    设置
    角色 存储 Blob 数据读取者
    将访问权限分配到 托管标识
    系统分配 虚拟机
    Select <你的虚拟机>

    用于添加角色分配的页面的屏幕截图。

访问数据

Azure 存储原生支持 Microsoft Entra 身份验证,因此可以直接接受使用托管标识获取的访问令牌。 此方法将 Azure 存储与 Microsoft Entra ID 集成结合使用,不同于在连接字符串中提供凭据。

以下 .NET 代码的示例是关于打开与 Azure 存储的连接。 该示例使用访问令牌,然后读取前面创建的文件的内容。 此代码必须在 VM 上运行才能访问 VM 的托管标识终结点。 使用访问令牌方法需要 .NET Framework 4.6 或更高版本。 相应地替换 <URI to blob file> 的值。 可以通过以下方式获取此值:在“概述”页上的“属性”下,导航到你创建并上传到 blob 存储的文件,然后复制 URL

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.IO;
using System.Net;
using System.Web.Script.Serialization;
using Microsoft.WindowsAzure.Storage.Auth;
using Microsoft.WindowsAzure.Storage.Blob;

namespace StorageOAuthToken
{
    class Program
    {
        static void Main(string[] args)
        {
            //get token
            string accessToken = GetMSIToken("https://storage.azure.com/");

            //create token credential
            TokenCredential tokenCredential = new TokenCredential(accessToken);

            //create storage credentials
            StorageCredentials storageCredentials = new StorageCredentials(tokenCredential);

            Uri blobAddress = new Uri("<URI to blob file>");

            //create block blob using storage credentials
            CloudBlockBlob blob = new CloudBlockBlob(blobAddress, storageCredentials);

            //retrieve blob contents
            Console.WriteLine(blob.DownloadText());
            Console.ReadLine();
        }

        static string GetMSIToken(string resourceID)
        {
            string accessToken = string.Empty;
            // Build request to acquire MSI token
            HttpWebRequest request = (HttpWebRequest)WebRequest.Create("http://169.254.169.254/metadata/identity/oauth2/token?api-version=2018-02-01&resource=" + resourceID);
            request.Headers["Metadata"] = "true";
            request.Method = "GET";

            try
            {
                // Call /token endpoint
                HttpWebResponse response = (HttpWebResponse)request.GetResponse();

                // Pipe response Stream to a StreamReader, and extract access token
                StreamReader streamResponse = new StreamReader(response.GetResponseStream());
                string stringResponse = streamResponse.ReadToEnd();
                JavaScriptSerializer j = new JavaScriptSerializer();
                Dictionary<string, string> list = (Dictionary<string, string>)j.Deserialize(stringResponse, typeof(Dictionary<string, string>));
                accessToken = list["access_token"];
                return accessToken;
            }
            catch (Exception e)
            {
                string errorText = String.Format("{0} \n\n{1}", e.Message, e.InnerException != null ? e.InnerException.Message : "Acquire token failed");
                return accessToken;
            }
        }
    }
}

响应包含文件内容:

Hello world! :)

禁用

若要在 VM 上禁用系统分配的标识,请将系统分配的标识的状态设为“关” 。

屏幕截图显示虚拟机的“系统分配”选项卡,可以在其中关闭“系统分配”状态。

后续步骤

在本教程中,你已学习了如何启用 Windows VM 的系统分配的标识以访问 Azure 存储。 要详细了解 Azure 存储,请参阅: