如何使用 Microsoft Azure Key Vault





5.00/5 (2投票s)
如何设置和使用 Azure 密钥保管库来存储您的秘密值。
引言
在本文中,我将介绍如何设置和使用 Azure Key Vault 来存储你的秘密值。
有时,我们会看到像存储密钥和连接字符串这样的秘密值作为字面量写在项目代码中,例如
public static class Secrets
{
public const string ApiKey = "MyAppKey";
// ...
}
这似乎不是什么大问题,因为
- 这是获取密钥的最快方法
- 密钥可能不会经常更改
但这种工作方式也存在一些严重的缺点
- 如果密钥发生更改,代码需要进行修改和重新部署。
- 密钥在代码中一览无余。
- 密钥将“永久”保存在源代码系统中,甚至可能保存在公共存储库中。
- 当你更改环境(从 DEV 到 ACC 再到 PROD)时,密钥很可能也会随之更改。这对于硬编码的密钥来说是一个问题。
将密钥存储在其他地方会更好,但有哪些选择呢?
- 密钥可以存储在配置文件中。这已经有所改善,但该文件仍然可以被开发人员读取(并在公共存储库中可见)。
- 密钥可以存储在 Azure 中。这就是我们在本文中要讨论的内容。
本文的前提条件
如果你想跟随示例进行操作,你需要一个 Azure 订阅。在 Azure 主页 上,你可以找到创建免费订阅的步骤,该订阅将有效 3 个月。
Azure Key Vault 简介
我们可以在 Key Vault 中存储以下项目,以供以后使用
- 秘密 - 可以在此处存储许多类型的数据,例如令牌、密码、密钥等。
- 密钥 - 加密密钥可以放在这里,以后可以引用它们来加密/解密你的数据。
- 证书
这些项目被安全地存储在保管库中,只有具有正确访问权限的用户(或进程)才能检索它们。此访问受到监控,因此你可以知道谁访问了什么,以及 Key Vault 的性能如何。
创建 Azure Key Vault
在 Microsoft Azure 门户中
- 点击左上角的“创建资源”按钮。
- 在出现的刀片式服务中,在搜索框中输入“Key Vault”,然后从下面的列表中选择“Key Vault”。
点击“创建”并填写必要的参数
- 名称:密钥保管库的唯一名称
- 订阅:将包含你的密钥保管库的订阅
- 资源组:在这里,你可以选择一个现有的资源组或创建一个新的资源组。对于本示例,你可能希望创建一个新的资源组,以便在完成后可以轻松清理所有内容。
- Location
- 定价层:标准,除非你需要 HSM 备份的密钥。
- 访问策略:默认情况下,当前用户将是密钥保管库的所有者。你可以在此处添加或删除权限。
- 点击“创建”,密钥保管库将被创建。这可能需要一些时间。
将值插入 Key Vault
- 在 Azure 中找到你的新密钥保管库并点击它。如果你的订阅包含许多对象,你可能需要先选择密钥保管库所在的资源组。
- 现在你将看到概述页面,其中包含一些有用的信息。
- 这里最重要的一条信息是 DNS 名称(右上角)。你需要它才能从你的代码连接到密钥保管库。
- 你还可以看到请求数量、平均延迟和成功率。
- 专业技巧:记录平均延迟,作为未来请求的基线值。
- 在左侧,点击“Secrets”。你将看到所有当前存储的秘密。如果你刚刚创建了密钥保管库,这里将是空的。
- 点击“Generate/Import”以创建新的秘密
- 上传选项:手动
- 名称:Password(以供我们举例)
- 值:My Secret
- 内容类型:留空
- 如果需要,你还可以为该秘密设置激活日期和过期日期。在本示例中,我们将留空。
- 确保“enabled”设置为 yes,然后点击“Create”。
当你再次点击左侧的“Secrets”按钮时,你将看到这个密钥的条目。
如果你更喜欢通过脚本来完成,下一部分就是为你准备的。
使用 Azure Cloud Shell 设置 Key Vault
使用脚本创建 Azure 对象使其可重复。如果你有多个租户,你可以编写一个脚本,为每个租户创建必要的对象。这会为你节省时间,因为
- 显然,执行脚本比手动创建每个对象更快
- 一致性。如果一切都已脚本化,你可以确保所有对象在每个租户中都创建得相同。这可以为你节省数小时的时间来查找配置错误。
- 你可以将脚本保存在源代码管理中,这样你就可以对它们进行版本控制。
打开 Cloud Shell
顶部,点击“Cloud Shell”图标。如果你是第一次打开云 shell,将显示一个设置 shell 的向导。你可以选择要使用的脚本语言(PowerShell 或 Linux Bash),然后 Azure 将为你创建一些存储。还有一个明确的警告,即存储会花费你一些钱。
在本示例中,我将使用 Linux Bash。
RESOURCE_GROUP='CodeProject'
LOCATION='WestEurope'
KEY_VAULT='CPKeyVault666'
az group create --name $RESOURCE_GROUP --location $LOCATION
az keyvault create --resource-group $RESOURCE_GROUP --name $KEY_VAULT
az keyvault list
az keyvault secret set --vault-name $KEY_VAULT --name Password --value 'My Secret'
az keyvault secret list --vault-name $KEY_VAULT
az keyvault secret show --vault-name $KEY_VAULT --name Password --query value --output tsv
在你的 .NET 项目中使用 Azure Key Vault
项目设置
使用 Visual Studio 2019,创建一个新的 .NET Core 控制台应用程序,命名为‘KeyVault
’。
NuGet 包
要使用 Azure Key Vault,你首先需要向你的项目添加 2 个 NuGet 包
Microsoft.Azure.KeyVault
Microsoft.Azure.Services.AppAuthentication
打开“Package Manager Console”(Tools > NuGet Package Manager > Package Manager Console…)并输入以下语句
install-package Microsoft.Azure.KeyVault
install-package Microsoft.Azure.Services.AppAuthentication
在你的源文件中,你需要以下 using
语句
using Microsoft.Azure.KeyVault;
using Microsoft.Azure.Services.AppAuthentication;
从 Key Vault 读取字符串
为了在应用程序中分离关注点,最好为此创建一个单独的类,例如
using System.Collections.Generic;
using System.Threading.Tasks;
using Microsoft.Azure.KeyVault;
using Microsoft.Azure.KeyVault.Models;
using Microsoft.Azure.Services.AppAuthentication;
namespace KeyVault
{
public class KeyvaultUtilities : IKeyvaultUtilities
{
private readonly IKeyVaultClient _keyVaultClient;
private readonly string _vaultBaseUrl;
public KeyvaultUtilities(string keyvaultName)
{
_vaultBaseUrl = $"https://{keyvaultName}.vault.azure.net";
AzureServiceTokenProvider azureServiceTokenProvider =
new AzureServiceTokenProvider();
_keyVaultClient = new KeyVaultClient(
new KeyVaultClient.AuthenticationCallback
(azureServiceTokenProvider.KeyVaultTokenCallback));
}
/// <summary>
/// Get the value for a secret from the key vault.
/// </summary>
/// <param name="keyname"></param>
/// <returns></returns>
/// <exception cref="KeyVaultErrorException">
/// When the key is not found, this exception is thrown.</exception>
public async Task<string> GetSecretAsync(string keyname)
{
try
{
var secret = await _keyVaultClient.GetSecretAsync(_vaultBaseUrl, keyname)
.ConfigureAwait(false);
return secret.Value;
}
catch (KeyVaultErrorException kvex)
{
throw new KeyNotFoundException
($"Keyname '{keyname}' does not seem to exist in this key vault", kvex);
}
}
}
}
目的是从密钥保管库读取一个秘密,所以我只实现了一个方法。如果需要,你可以在类中添加其他与密钥保管库相关的方法。
使用这个类很简单。而不是将密钥保管库名称作为 string
传递,你可以从设置文件中获取它。这也将使你在开发环境中轻松切换。
请注意,我们从未创建过名为“xyz
”的秘密。尝试检索此值将引发 KeyNotFoundException
。
using System;
using System.Threading.Tasks;
namespace KeyVault
{
class Program
{
static async Task Main(string[] args)
{
Console.WriteLine("Hello World!");
IKeyvaultUtilities util = new KeyvaultUtilities("cpkeyvault666");
string pwd = await util.GetSecretAsync("Password");
Console.WriteLine("Password: " + pwd);
string xyz = await util.GetSecretAsync("xyz");
Console.WriteLine("xyz: " + pwd);
}
}
}
Azure 中的清理
在 Azure 门户中,返回到 Cloud Shell。删除‘CodeProject
’资源组
RESOURCE_GROUP='CodeProject'
az group delete --name $RESOURCE_GROUP --yes
这将删除‘Codeproject
’资源组及其所有内容。如果你不执行此步骤,请不要担心,密钥保管库的成本仅为每 10000 次操作约 3 美分。你可以在这里计算你的成本:https://azure.microsoft.com/en-us/pricing/calculator/。
你也可以通过 Azure 门户删除资源组。
首次检索秘密可能(非常)缓慢
首次检索密钥可能需要几秒钟。如果你不确定是否始终需要密钥保管库中的秘密,可以考虑使用 Lazy<T> 类。
后续的检索速度很快。
因此,你可以考虑将 KeyVaultUtilities
注册为单例并注入它,而不是每次都重新创建它。如何做到这一点将取决于你正在创建的应用程序类型。