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

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

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

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

注意

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

先决条件

启用

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

Screenshot shows the System assigned tab for a virtual machine where you can turn on the System assigned status.

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

  1. 登录到 Azure 门户

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

授予访问权限

创建存储帐户

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

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

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

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

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

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

  6. 选择创建

    Create new storage account

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

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

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

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

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

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

    Create storage container

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

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

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

授予访问权限

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

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

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

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

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

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

    Screenshot that shows the page for adding a role assignment.

访问数据

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 上禁用系统分配的标识,请将系统分配的标识的状态设为“关” 。

Screenshot shows the System assigned tab for a virtual machine where you can turn off the System assigned status.

后续步骤

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