在开发应用程序时,经常需要处理各种敏感信息,如API密钥、数据库连接字符串等。这些信息如果直接硬编码在代码中,不仅不安全,而且难以管理。本文将介绍如何使用Azure Key Vault来安全地存储和管理这些敏感信息。
在代码中直接硬编码敏感信息,虽然看似简单快捷,但存在以下问题:
Azure Key Vault是一个安全的云服务,用于存储和管理敏感信息。它可以存储以下类型的数据:
这些数据被安全地存储在Key Vault中,只有具有相应访问权限的用户或进程才能检索它们。访问情况会被监控,因此可以知道谁访问了什么,以及Key Vault的性能如何。
要在Azure门户中创建Key Vault,请按照以下步骤操作:
在Azure门户中找到新Key Vault并点击它。如果订阅包含很多对象,可能需要先选择包含Key Vault的资源组。
现在可以看到概览页面,其中包含一些有用的信息。这里最重要的信息是DNS名称(右上角)。将需要这个名称来从代码中连接到Key Vault。
在左侧菜单中点击“机密”。将看到所有当前存储的机密。如果刚刚创建了Key Vault,这里可能是空的。
点击“生成/导入”来创建一个新的机密:
如果愿意,还可以为这个机密设置激活日期和过期日期。在示例中,将留空。
确保“启用”设置为“是”,然后点击“创建”。
当再次点击左侧的“机密”按钮时,将看到这个密钥的条目。
使用脚本创建Azure对象可以使其可重复。如果有多个租户,可以编写一个脚本,为每个租户创建必要的对象。这将节省时间,因为:
打开Cloud Shell:
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,请按照以下步骤操作:
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));
}
public async Task 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);
}
}
}
}
这个类的目的是从Key Vault中读取机密,因此只实现了这一个方法。可以根据需要在类中添加其他与Key Vault相关的方法。
使用这个类很简单。可以通过设置文件获取Key Vault名称,而不是作为字符串传递。这也将允许在开发环境中轻松切换。
请注意,从未创建过名为“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门户中,返回到Cloud Shell。删除“CodeProject”资源组:
RESOURCE_GROUP='CodeProject'
az group delete --name $RESOURCE_GROUP --yes
这将删除“CodeProject”资源组及其所有内容。如果不执行这一步,不用担心,Key Vault的费用非常低,每10000次操作只需3美分。可以在这里计算费用:
也可以通过Azure门户删除资源组。
检索第一个密钥可能需要几秒钟。如果不确定是否总是需要从Key Vault中检索机密,可以考虑使用Lazy<T>类。