教程:使用 Linux VM 和 .NET 应用在 Azure Key Vault 中存储机密Tutorial: Use a Linux VM and a .NET app to store secrets in Azure Key Vault

Azure Key Vault 用于保护机密,例如访问应用程序、服务和 IT 资源所需的 API 密钥和数据库连接字符串。Azure Key Vault helps you to protect secrets such as API Keys and database connection strings that are needed to access your applications, services, and IT resources.

在本教程中,请设置 .NET 控制台应用程序以使用 Azure 资源的托管标识从 Azure Key Vault 读取信息。In this tutorial, you set up a .NET console application to read information from Azure Key Vault by using managed identities for Azure resources. 你将学习如何执行以下操作:You learn how to:

  • 创建密钥保管库Create a key vault
  • 在 Key Vault 中存储机密Store a secret in Key Vault
  • 创建一个 Azure Linux 虚拟机Create an Azure Linux virtual machine
  • 为虚拟机启用托管标识Enable a managed identity for the virtual machine
  • 授予所需的权限,让控制台应用程序从 Key Vault 读取数据Grant the required permissions for the console application to read data from Key Vault
  • 从 Key Vault 检索机密Retrieve a secret from Key Vault

在我们进一步讨论之前,请阅读有关密钥保管库基本概念的内容。Before we go any further, read about key vault basic concepts.

先决条件Prerequisites

了解托管服务标识Understand Managed Service Identity

Azure Key Vault 可以安全地存储凭据,因此不需将凭据置于代码中,但若要检索这些凭据,需向 Azure Key Vault 进行身份验证。Azure Key Vault can store credentials securely so they aren't in your code, but to retrieve them you need to authenticate to Azure Key Vault. 但是,若要向 Key Vault 进行身份验证,需提供凭据。However, to authenticate to Key Vault, you need a credential. 这是经典的启动问题。It's a classic bootstrap problem. 有了 Azure 和 Azure Active Directory (Azure AD),托管服务标识 (MSI) 就可以提供一个“启动标识”来大大简化启动过程。With Azure and Azure Active Directory (Azure AD), Managed Service Identity (MSI) can provide a bootstrap identity that makes it much simpler to get things started.

为 Azure 服务(例如虚拟机、应用服务或 Functions)启用 MSI 时,Azure 会为 Azure Active Directory 中的服务实例创建一个服务主体。When you enable MSI for an Azure service like Virtual Machines, App Service, or Functions, Azure creates a service principal for the instance of the service in Azure Active Directory. 它会将服务主体的凭据注入服务的实例。It injects the credentials for the service principal into the instance of the service.

MSI

接下来,代码会调用 Azure 资源上提供的本地元数据服务,以获取访问令牌。Next, your code calls a local metadata service available on the Azure resource to get an access token. 代码使用从本地 MSI_ENDPOINT 获取的访问令牌,以便向 Azure Key Vault 服务进行身份验证。Your code uses the access token it gets from the local MSI_ENDPOINT to authenticate to an Azure Key Vault service.

登录 AzureSign in to Azure

若要使用 Azure CLI 登录到 Azure,请输入:To sign in to Azure by using the Azure CLI, enter:

az  cloud  set –n  AzureChinaCloud 
az login

创建资源组Create a resource group

使用 az group create 命令创建资源组。Create a resource group by using the az group create command. Azure 资源组是在其中部署和管理 Azure 资源的逻辑容器。An Azure resource group is a logical container into which Azure resources are deployed and managed.

在“中国北部”位置创建一个资源组。Create a resource group in the China North location. 在以下示例中,为资源组选取一个名称并用其替换 YourResourceGroupNamePick a name for your resource group and replace YourResourceGroupName in the following example:

# To list locations: az account list-locations --output table
az group create --name "<YourResourceGroupName>" --location "China North"

本教程通篇使用此资源组。You use this resource group throughout the tutorial.

创建密钥保管库Create a key vault

接下来,在资源组中创建密钥保管库。Next, create a key vault in your resource group. 提供以下信息:Provide the following information:

  • 密钥保管库名称:由 3 到 24 个字符构成的字符串,只能包含数字、字母和连字符(0-9、a-z、A-Z 和 -)。Key vault name: a string of 3 to 24 characters that can contain only numbers, letters, and hyphens ( 0-9, a-z, A-Z, and - ).
  • 资源组名称Resource group name
  • 位置:中国北部Location: China North
az keyvault create --name "<YourKeyVaultName>" --resource-group "<YourResourceGroupName>" --location "China North"

目前,只有你的 Azure 帐户才有权对这个新保管库执行任何操作。At this point, only your Azure account is authorized to perform any operations on this new vault.

向密钥保管库添加机密Add a secret to the key vault

现在,请添加机密。Now, you add a secret. 在实际方案中,在存储 SQL 连接字符串或任何其他信息时,可能既需要确保其安全,但同时也要确保其可供应用程序使用。In a real-world scenario, you might be storing a SQL connection string or any other information that you need to keep securely, but make available to your application.

在本教程中,请键入以下命令,在密钥保管库中创建机密。For this tutorial, type the following commands to create a secret in the key vault. 该机密名为 AppSecret,其值为 MySecretThe secret is called AppSecret and its value is MySecret.

az keyvault secret set --vault-name "<YourKeyVaultName>" --name "AppSecret" --value "MySecret"

创建 Linux 虚拟机Create a Linux virtual machine

使用 az vm create 命令创建 VM。Create a VM with the az vm create command.

以下示例创建一个名为 myVM 的 VM 并添加一个名为 azureuser 的用户帐户。The following example creates a VM named myVM and adds a user account named azureuser. --generate-ssh-keys 参数用来自动生成一个 SSH 密钥,并将其放置在默认密钥位置 ( ~/.ssh) 中。The --generate-ssh-keys parameter us used to automatically generate an SSH key and put it in the default key location (~/.ssh). 若要改为使用一组特定的密钥,请使用 --ssh-key-value 选项。To use a specific set of keys instead, use the --ssh-key-value option.

az vm create \
  --resource-group myResourceGroup \
  --name myVM \
  --image UbuntuLTS \
  --admin-username azureuser \
  --generate-ssh-keys

创建 VM 和支持资源需要几分钟时间。It takes a few minutes to create the VM and supporting resources. 以下示例输出表明 VM 创建操作已成功。The following example output shows that the VM create operation was successful.

{
  "fqdns": "",
  "id": "/subscriptions/<guid>/resourceGroups/myResourceGroup/providers/Microsoft.Compute/virtualMachines/myVM",
  "location": "chinanorth",
  "macAddress": "00-00-00-00-00-00",
  "powerState": "VM running",
  "privateIpAddress": "XX.XX.XX.XX",
  "publicIpAddress": "XX.XX.XXX.XXX",
  "resourceGroup": "myResourceGroup"
}

记下 VM 输出中的 publicIpAddressMake a note of your publicIpAddress in the output from your VM. 在后续步骤中,将使用此地址访问 VM。You'll use this address to access the VM in later steps.

为 VM 分配标识Assign an identity to the VM

为虚拟机创建一个系统分配标识,方法是运行以下命令:Create a system-assigned identity to the virtual machine by running the following command:

az vm identity assign --name <NameOfYourVirtualMachine> --resource-group <YourResourceGroupName>

此命令的输出应该是:The output of the command should be:

{
  "systemAssignedIdentity": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
  "userAssignedIdentities": {}
}

记下 systemAssignedIdentityMake a note of the systemAssignedIdentity. 在下一步使用它。You use it in the next step.

为 VM 标识提供 Key Vault 访问权限Give the VM identity permission to Key Vault

现在可以向所创建的标识提供 Key Vault 权限。Now you can give Key Vault permission to the identity you created. 运行以下命令:Run the following command:

az keyvault set-policy --name '<YourKeyVaultName>' --object-id <VMSystemAssignedIdentity> --secret-permissions get list

登录 VMLog in to the VM

使用终端登录虚拟机。Log in to the virtual machine by using a terminal.

ssh azureuser@<PublicIpAddress>

在 Linux 上安装 .NET CoreInstall .NET Core on Linux

在 Linux VM 上:On your Linux VM:

运行以下命令,将 Microsoft 产品密钥注册为受信任的密钥:Register the Microsoft product key as trusted by running the following commands:

curl https://packages.microsoft.com/keys/microsoft.asc | gpg --dearmor > microsoft.gpg
sudo mv microsoft.gpg /etc/apt/trusted.gpg.d/microsoft.gpg

根据操作系统设置所需版本主机包源:Set up desired version host package feed based on operating system:

   # Ubuntu 17.10
   sudo sh -c 'echo "deb [arch=amd64] https://packages.microsoft.com/repos/microsoft-ubuntu-artful-prod artful main" > /etc/apt/sources.list.d/dotnetdev.list'
   sudo apt-get update
   
   # Ubuntu 17.04
   sudo sh -c 'echo "deb [arch=amd64] https://packages.microsoft.com/repos/microsoft-ubuntu-zesty-prod zesty main" > /etc/apt/sources.list.d/dotnetdev.list'
   sudo apt-get update
   
   # Ubuntu 16.04 / Linux Mint 18
   sudo sh -c 'echo "deb [arch=amd64] https://packages.microsoft.com/repos/microsoft-ubuntu-xenial-prod xenial main" > /etc/apt/sources.list.d/dotnetdev.list'
   sudo apt-get update
   
   # Ubuntu 14.04 / Linux Mint 17
   sudo sh -c 'echo "deb [arch=amd64] https://packages.microsoft.com/repos/microsoft-ubuntu-trusty-prod trusty main" > /etc/apt/sources.list.d/dotnetdev.list'
   sudo apt-get update

安装 .NET 并检查版本:Install .NET and check the version:

sudo apt-get install dotnet-sdk-2.1.4
dotnet --version

创建并运行示例 .NET 应用Create and run a sample .NET app

运行以下命令。Run the following commands. 此时会看到“Hello World”输出到控制台。You should see "Hello World" printed to the console.

dotnet new console -o helloworldapp
cd helloworldapp
dotnet run

编辑用于提取机密的控制台应用Edit the console app to fetch your secret

打开 Program.cs 文件,添加以下包:Open Program.cs file and add these packages:

using System;
using System.IO;
using System.Net;
using System.Text;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;

需要通过一个两步过程更改类文件,使应用能够访问密钥保管库中的机密。It's a two-step process to change the class file to enable the app to access the secret in the key vault.

  1. 从 VM 上的本地 MSI 终结点提取一个令牌,该终结点会转而从 Azure Active Directory 提取令牌。Fetch a token from the local MSI endpoint on the VM that in turn fetches a token from Azure Active Directory.

  2. 将令牌传递到 Key Vault,提取机密。Pass the token to Key Vault and fetch your secret.

    编辑类文件,使之包含以下代码:Edit the class file to contain the following code:

     class Program
        {
            static void Main(string[] args)
            {
                // Step 1: Get a token from local (URI) Managed Service Identity endpoint which in turn fetches it from Azure Active Directory
                var token = GetToken();
    
                // Step 2: Fetch the secret value from Key Vault
                System.Console.WriteLine(FetchSecretValueFromKeyVault(token));
            }
    
            static string GetToken()
            {
                WebRequest request = WebRequest.Create("http://169.254.169.254/metadata/identity/oauth2/token?api-version=2018-02-01&resource=https%3A%2F%2Fvault.azure.cn");
                request.Headers.Add("Metadata", "true");
                WebResponse response = request.GetResponse();
                return ParseWebResponse(response, "access_token");
            }
    
            static string FetchSecretValueFromKeyVault(string token)
            {
                WebRequest kvRequest = WebRequest.Create("https://prashanthwinvmvault.vault.azure.cn/secrets/RandomSecret?api-version=2016-10-01");
                kvRequest.Headers.Add("Authorization", "Bearer "+  token);
                WebResponse kvResponse = kvRequest.GetResponse();
                return ParseWebResponse(kvResponse, "value");
            }
    
            private static string ParseWebResponse(WebResponse response, string tokenName)
            {
                string token = String.Empty;
                using (Stream stream = response.GetResponseStream())
                {
                    StreamReader reader = new StreamReader(stream, Encoding.UTF8);
                    String responseString = reader.ReadToEnd();
    
                    JObject joResponse = JObject.Parse(responseString);
                    JValue ojObject = (JValue)joResponse[tokenName];
                    token = ojObject.Value.ToString();
                }
                return token;
            }
        }
    

现在,我们已学习了如何在 Azure Linux 虚拟机运行的 .NET 应用程序中通过 Azure Key Vault 执行操作。Now you've learned how to perform operations with Azure Key Vault in a .NET application running on an Azure Linux virtual machine.

清理资源Clean up resources

不再需要资源组、虚拟机和所有相关的资源时,可将其删除。Delete the resource group, virtual machine, and all related resources when you no longer need them. 为此,请选择适用于 VM 的资源组,然后选择“删除”。 To do so, select the resource group for the VM and select Delete.

使用 az keyvault delete 命令删除密钥保管库:Delete the key vault by using the az keyvault delete command:

az keyvault delete --name
                   [--resource group]
                   [--subscription]

后续步骤Next steps