# Microsoft Azure-保护与关键的 Azure 保管库的敏感信息
通过 [Rahul Nath](https://msdn.microsoft.com/zh-cn/magazine/mt149362?author=Rahul+Nath) | 2015 年 9 月
许多应用程序构建今天处理中的敏感信息某种形式或另一个,通常到外部系统 (如数据库连接字符串。这些注册表项通常会将其部署为应用程序的配置文件的一部分并可作为纯文本的任何用户可以访问部署服务器。很明显,这会带来巨大的安全威胁。
Microsoft Azure 密钥保管库是云托管硬件安全模块 (HSM)-备份服务用于管理加密密钥和其他敏感信息 — 在保管库密钥术语中的机密信息 — 在一个中央位置,并且可以通过指定的键或机密的相应 URI 访问通过 REST API。保管库密钥还允许您创建的软件注册表,而不是 HSM 备份一个;在这两种情况下该密钥的私钥部分不保留键保管库边界和可以永远不会被看到或共享。
在本文中,我将向您介绍一家大型公司,Contoso,与外包给不同供应商开发业务线 (LOB) 应用程序构建在其中一个方案。该应用程序与多个第三方服务交互及讲述了敏感信息,包括客户个人身份信息 (PII)。我将介绍如何在现有的实施第一个和安全性会为公司,发出此姿势然后显示该公司如何使用 Azure 密钥保管库来解决这些问题。
## 现有的应用程序
Contoso 是当前构建 LOB 应用程序对于客户而言,车辆和其他相关的方到单个平台上提供连接的汽车体验对大型的汽车制造公司。由于 Contoso 具有仅小型 IT 团队内部,它会外包给各种供应商构建的应用程序的不同部分的每个应用程序的开发。该应用程序是云托管,并公开为各种实体的不同 Api 可以与其进行交互。它还使用第三方应用程序 Api 来使用来自外部服务,并调用到内部 Contoso 应用程序通过 Web 服务公开的数据。
应用程序处理 PII,而是保密应安全地存储。最初,不是真正考虑如何应处理敏感信息,并不同供应商有其自己的方法。连接字符串的大多数都是应用程序配置文件的一部分,使其无法更改每个部署 ;某些密钥用于加密 PII 信息已硬编码到应用程序。而某些证书的详细信息以连接与 Contoso Web 服务是在应用程序的数据库中。这会变得难以管理对于 Contoso,且公司最后并不建议这样做与应用程序开发的供应商,共享的敏感信息。Contoso 还认识到任何具有为其部署服务器的访问权的人都能够非常轻松地篡改 PII 数据,这样会严重的威胁。该公司强制统一用于维护和访问敏感信息的方法。
## 应用程序 Refit
Contoso 深入了解了用于管理敏感信息和统一的体验以便它可以成为一致的跨不同的应用程序的各种备选方法。该公司希望为其安全团队,可以轻松管理其密钥的中央存储,而且它想要为不同应用程序提供不同的访问策略的信息。此外,Contoso 不希望任何一个过程需要的日常监视具有很大的维护开销。
于是便选择了 Azure 密钥保管库中,允许使用的软件和 HSM 备份密钥,以及从 PFX 文件导入现有密钥。保管库密钥允许您在云中安全地存储小少量信息 (安全的密码) 并根据需要访问它们。因为完全管理此服务并将其保留在 Azure 平台上,您是从维护它的所有开销释放出来。
无法查看或由任何人,使其非常安全的平台中提取键的方式生成保管库密钥。它提供一个丰富 API 用于访问和与保管库中,以及用于在 Microsoft.NET Framework 运行的应用程序的 C# API 库进行交互。能够控制如何不同应用程序和供应商可以与交互如该公司想要限制不同应用程序供应商可以与安全信息进行交互的方式是为 Contoso,一个不错的选择使密钥保管库的重要因素。另外,Contoso 工程师已经很大程度使用 Windows PowerShell 脚本来管理其各种其他服务器、 和密钥存储库是完全可以通过 Windows PowerShell 进行管理。
创建密钥的保管库: Contoso IT 团队的安全管理员负责设置密钥保管库和管理密钥和机密内容。Azure 密钥保管库可以创建和使用 Windows PowerShell cmdlet 管理且可使用最新的 Azure PowerShell (0.9.2 或更高版本)。一旦连接到 Azure 订阅的 Azure PowerShell 提示符下,您需要切换到 AzureResourceManager 模式,密钥保管库 cmdlet 需要。然后,您可以使用新建 AzureKeyVault cmdlet,通过指定保管库名称 (这是全局唯一的)、 资源组和位置中创建新的存储库:
~~~
Switch-AzureMode AzureResourceManager
New-AzureResourceGroup –Name 'ContosoResourceGroup' –Location 'East Asia'
New-AzureKeyVault -VaultName 'ContosoKeyVault' -ResourceGroupName
'ContosoResourceGroup' -Location 'East Asia'
~~~
在成功执行的命令时,新创建的密钥保管库的详细信息被输出到 Azure PowerShell 控制台中,其中包括该保管库名称和用于唯一标识此保管库的 URI。
设置键保管库: Azure 密钥保管库使创建和存储加密密钥,并且还秘密,是具有任何特定语义的有限大小八位位组对象存储。
支持当前仅 RSA 密钥和加密密钥在保管库中表示为 JSON Web 键对象。一旦在保管库中创建一个键后,只有该密钥的公共部分是在保管库边界外可用。
密钥的保管库可以包含密钥和机密,并且可以单独控制对这些外部访问。密钥和机密内容是在保管库中的受版本控制对象,由保管库 URL 和对象名称和其版本号唯一标识一个新。时与现有名称创建一个对象,创建了一个新对象具有相同的名称和新的版本号,这将成为最新版本。尝试访问没有版本号的对象返回的当前版本。对象标识符,用于唯一地标识一个保管库中的某个对象采用以下格式,并使用与密钥和机密内容使用 API 进行交互:
~~~
https://{keyvault-name}.vault.azure.net/{object-type}/{object-name}/{object-version}
~~~
其中:
~~~
keyvault-name : Globally unique key vault name
object-type : Either "keys" or "secrets," indicating the type of object
object-name : Unique name within a key vault
object-version : System generated string, optionally used to
identify a specific version of object
~~~
Azure 密钥保管库中的键与扩展以启用对 Azure 密钥保管库实现是唯一的密钥类型的基 JWK 规范表示为 JSON Web 键 (JWK) 对象。当前 Azure 密钥保管库支持仅 RSA 算法,非对称算法。Azure 保管库密钥支持创建、 导入、 更新、 删除、 列表、 获取、 备份和还原操作对键,并这些操作可使用 REST API 和 Windows PowerShell cmdlet。因为 Contoso 应用程序使用密钥进行加密和解密特定 PII 的信息,一个密钥需要在保管库中创建。Contoso 工程师使用以下脚本将新密钥添加到保管库中,与在其保管库中是唯一的名称:
~~~
Add-AzureKeyVaultKey -VaultName 'ContosoKeyVault' -Name 'ContosoPIIKey'
-Destination 'Software'
~~~
在成功执行这将在 ContosoKeyVault,可以使用工程师将共享与应用程序供应商的唯一标识符 (例如,https://ContosoKeyVault.vault.azure.net/keys/ContosoPIIKey/ bfacf5f768ae42ffb0a0bca448aead87) 来标识创建新的软件 RSA 密钥。
Azure 密钥保管库中的秘密) 是八位字节序列的每个; 25 K 的最大大小接受任何类型的数据并将其安全地存储。密钥保管库支持创建、 获取、 列表、 删除和更新的秘密,对操作和这些操作可以使用 REST API 和 Windows PowerShell cmdlet。由于 Contoso 应用程序将连接字符串保存在应用程序配置文件中时,Contoso 工程师可以决定要移到密钥保管库,它可以安全地存储并仍然可以访问使用唯一标识符。下面的脚本用于将其 SQL 数据库连接字符串添加到保管库:
~~~
$ContosoSQLConnectionString = ConvertTo-SecureString -String
"ContosoSQLConnectionString"
-AsPlainText -Force
Set-AzureKeyVaultSecret -VaultName "ContosoKeyVault" -Name
"ContosoSQLConnectionString"
-SecretValue $ContosoSQLConnectionString
~~~
在成功执行这机密值会在创建 ContosoKeyVault,可以使用的唯一标识符 (如 https://ContosoKeyVault.vault.azure.net/secrets/ContosoSQLConnectionString/ 90018dbb96a84117a0d2847ef8e7189d),其中工程师与应用程序供应商的共享再次进行标识。
进行身份验证应用程序以使用密钥保管库: 新创建的存储库是只能从创建它的 Azure 帐户并不被任何其他用户目前可以访问的。Contoso 需求为各种客户端应用程序访问到保管库。使用 Azure Active Directory (Azure AD) 应用程序令牌来保护到 Azure 的关键保管库的访问。若要执行此操作,Contoso 工程师首先需要在 Azure AD 中创建应用程序使用的身份验证密钥 (共享密钥) 或证书来保护它。可以使用 Azure 管理门户中,在 Active Directory 选项应用程序选项卡下完成创建 Azure AD 应用程序使用身份验证密钥访问保护。但与身份验证密钥保护其密钥的保管库不什么 Contoso 倾向于,如下这同样意味着将敏感信息放在客户端应用程序配置文件,正是他们想要在第一时间避免。此外,因为键保管库是所有敏感信息的单个存储区,允许访问到它的凭据是应极力避免的内容。因此,Contoso 决定使用基于证书的身份验证,以便它可以将证书部署到需要它的应用程序直接并可以进一步保护使用密码的证书。
可以通过 Windows PowerShell 命令行创建的 Azure AD 应用程序使用证书身份验证。Contoso 已有一种机制来生成用于保护其其他内部应用程序,因此该公司使用同一个服务来生成用于 Azure AD 应用程序的证书的证书。一旦该公司拥有该证书,可以使用以下脚本创建 Azure AD 应用程序:
~~~
$certificateFilePath = "C:\certificates\ContosoADApplication.cer"
$x509Certificate2 = New-Object System.Security.Cryptography.X509Certificates.X509Certificate2
$x509Certificate2.Import($certificateFilePath)
$rawCertData = $x509Certificate2.GetRawCertData()
$credentialValue = [System.Convert]::ToBase64String($rawCertData)
$startDate= [System.DateTime]::Now
$endDate = $startDate.AddYears(1)
$newADApplication = New-AzureADApplication -DisplayName
"ContosoKeyVaultADApplication"
-HomePage "http://www.contoso.com" -IdentifierUris "http://www.contoso.com"
-KeyValue $credentialValue -KeyType "AsymmetricX509Cert" -KeyUsage "Verify"
-StartDate $startDate -EndDate $endDate
~~~
使用密钥的保管库和创建的 Azure AD 应用程序,Contoso 现在已将这些连接在一起以便从 Azure AD 应用程序收到的应用程序令牌可用于对密钥的保管库进行身份验证。这可以通过使用组 AzureKeyVaultAccessPolicy cmdlet。您还设置 Azure AD 应用程序在这一次,对密钥的保管库的权限使用 PermissionToKeys 和 PermissionToSecrets 参数。
PermissionToKeys 参数指定要向其授予向应用程序的关键操作权限的数组和有一个可接受的值的列表 (解密、 加密、 UnwrapKey、 WrapKey、 验证、 签名、 获取、 列表、 更新、 创建、 导入、 删除、 备份、 还原所有)。PermissionToSecrets 参数指定要向其授予向应用程序的机密操作权限的数组和也有一个可接受的值的列表 (获取、 列表、 设置、 删除、 所有)。权限是适用于所有密钥和密钥在保管库中 ;不允许使用的某些项或保管库中的机密数据赋予选择性的权限。如果选择性访问密钥或机密信息的权限是必需的您需要创建与所选的键和密钥来管理的权限的单独的保管库。没有为密钥保管库本身,没有设置费用,但这可能会更改并且想要检查创建单独的保管库之前定价键保管库。若要向不同的访问级别提供针对相同的密钥和机密内容,您可以创建多个 Azure AD 应用程序和注册不同的权限级别。
Contoso 工程师使用以下脚本以将 Azure AD 应用程序和关键保管库中,关联并指定该应用程序具有在保管库的权限:
~~~
$ServicePrincipal = New-AzureADServicePrincipal -ApplicationId $newADApplication.ApplicationId
Set-AzureKeyVaultAccessPolicy -VaultName 'ContosoKeyVaultRahul' -ObjectId $ServicePrincipal.Id
-PermissionsToKeys encrypt,decrypt,get -PermissionsToSecrets get
$ServicePrincipal.ApplicationId
~~~
从客户端应用程序连接到保管库密钥: 一旦创建 Azure AD 应用程序并将其与键的保管库关联,您可以使用它从客户端应用程序进行身份验证密钥保管库。由于 Contoso 应用程序在.NET 平台上开发的应用程序供应商将使用 Microsoft.Azure.KeyVault NuGet 程序包 ([bit.ly/1Ji6xcS](http://bit.ly/1Ji6xcS)) 连接到关键的保管库。
对与 Azure AD 应用程序的客户端应用程序进行身份验证很容易实现使用 Azure AD 身份验证库 (ADAL),这也可作为 NuGet 程序包。所有应用程序需要使用 Azure AD 应用程序进行身份验证是客户端 ID 和可以放置在配置文件中的证书标识符 (如指纹)。这些可以安全地部署在配置文件中因为本身,它们不是敏感信息。
C# SDK 提供了 KeyVaultClient 类,该类中所示 图 1。其构造函数采用一个回调方法以提供有效的令牌从 Azure AD 应用程序。每当使用客户端执行加密操作时调用回调方法。有效的证书是使用自定义的函数 GetCertificateByThumbprint,从应用程序的配置文件中使用的指纹信息和用于对 Azure AD 应用程序进行身份验证获取的。ADAL 库缓存从 Azure AD 应用程序第一次收到的令牌和令牌过期之前提供从为每个后续调用缓存的令牌。
图 1 连接到关键的保管库
~~~
var keyVaultClient = new KeyVaultClient(async (authority, resource, scope) =>
{
string azureAdApplicationId =
ConfigurationManager.AppSettings["AzureAdApplicationId"];
string certificateThumbprint =
ConfigurationManager.AppSettings["CertificateThumbprint"];
X509Certificate2 certificate =
GetCertificateByThumbprint(certificateThumbprint);
var clientAssertionCertificate =
new ClientAssertionCertificate(azureAdApplicationId, certificate);
var authenticationContext = new AuthenticationContext(authority);
var result =
await authenticationContext.AcquireTokenAsync(resource,
clientAssertionCertificate);
return result.AccessToken;
});
~~~
配置客户端应用程序以使用密钥和机密内容: 客户端应用程序供应商现在需要更新现有的应用程序以使用的键和 Contoso 工程师由共享机密标识符从保管库中获取所需的连接字符串和密钥信息。由于本身的密钥标识符不是敏感信息,可以安全地将它们放在应用程序的配置文件中。
在连接字符串或已保存为一个秘密密钥的保管库中的类似敏感信息是必需的被替换现有代码从保管库使用 KeyVaultClient 读取:
~~~
var connectionStringIdentifier =
ConfigurationManager.AppSettings["ConnectionStringIdentifier"];
var contosoSQLConnectionString =
await keyVaultClient.GetSecretAsync(connectionStringIdentifier);
~~~
首先,此代码查找的连接字符串机密标识符存储在配置文件并使用此 SDK 客户端检索密钥值,在这种情况下是一个连接字符串。连接字符串然后可根据需要连接到应用程序数据库。
该应用程序须加密或解密 PII 信息的现有代码替换为代码以执行该操作使用 SDK 客户端并指定要使用的密钥标识符。下面的代码演示如何加密并随后会解密回原始文本一些文本:
~~~
// Within the actual application, encryption and decryption
// would happen at different parts.
var contosoPIIKeyIdentifier =
ConfigurationManager.AppSettings["ContosoPIIKeyIdentifier"];
Byte[] textToEncrypt = Encoding.Unicode.GetBytes("Consumer PII Information");
var encryptedResult =
await keyVaultClient.EncryptAsync(contosoPIIKeyIdentifier, "RSA_OAEP", textToEncrypt);
var decryptedResult =
await keyVaultClient.DecryptAsync(contosoPIIKeyIdentifier,
"RSA_OAEP", encryptedResult.Result);
var text = Encoding.Unicode.GetString(decryptedResult.Result);
~~~
维护关键保管库: Contoso 工程师负责维护的生存期内,其中包括更改与密钥标识符中 ; 相关联的密钥值的键的保管库更新为机密的标识符 ; 相关联的密钥值创建新的密钥或密钥的值 ;正在更新等用于 Azure AD 应用程序身份验证的证书。
若要创建或更新密钥和机密内容的保管库中,使用如前面的脚本。在为一个秘密或密钥指定的对象标识符不存在的保管库中,都会创建一个新的对象。有关现有标识符,保管库会自动创建的新版本并成为最新版本。较旧的值将保留在保管库并可供引用的标识符名称和在 URI 中的版本号。客户端应用程序可以决定是否在根据其需求的标识符中包含的版本号。对于不同的应用程序版本,你可以任选一个来在同一个保管库中,具有不同保管库或具有不同名称的标识符或标识符具有相同名称但具有在标识符 URI 中显式指定版本号。Contoso 安全策略要求密钥,如连接字符串和为其工程师请按照下面的工作流的证书的密钥值的频繁的更改 (滚动):
* 当保管库中存储的密钥都更新到较新版本时,将使用这些密钥加密的数据存储的客户端应用程序将需要确保加密的数据都将迁移为使用新密钥。
* Contoso 客户端应用程序维护所使用的数据进行加密的密钥版本并始终使用的解密相同的数据时。
* 加密数据时,应用程序始终将使用新密钥的信息。这允许应用程序逐渐将迁移到新的密钥值,以及它们创建时。
对于更新密钥值,该过程取决于密钥表示的值的种类。对于提供信息,如连接字符串的值,您首先切换到备用服务的密钥的值,然后前滚主服务的凭据信息和更新密钥与主服务已更新的凭据。对于某些服务如 Azure 存储,这是更简单,因为有一些主要和辅助密钥可互换使用时或者正在更新。对于其值仅与该应用程序的机密内容,机密是直接更新以便反映的任何新值。
证书用于保护 Azure AD 应用程序需要进行更改,Contoso 工程师使用 Windows PowerShell 脚本以执行更新。若要更新 Azure AD 应用程序的证书,需要安装 Azure AD 模块。您会发现模块在[bit.ly/1OdZTIS](http://bit.ly/1OdZTIS)。Contoso 工程师然后使用在该脚本 图 2 以上载新证书来保护 Azure AD 应用程序。
图 2 用于上载新证书的 Azure PowerShell 脚本
~~~
$certificateFilePath = "C:\certificates\ContosoADApplicationNew.cer"
$x509Certificate2 =
New-Object System.Security.Cryptography.X509Certificates.X509Certificate2
$x509Certificate2.Import($certificateFilePath)
$rawCertData = $x509Certificate2.GetRawCertData()
$credentialValue = [System.Convert]::ToBase64String($rawCertData)
$startDate= [System.DateTime]::Now
$endDate = $startDate.AddYears(1)
$msolCredentials = get-credential
connect-msolservice -credential $msolCredentials
New-MsolServicePrincipalCredential -ServicePrincipalName $ServicePrincipal.ApplicationId
-Type Asymmetric -Value $credentialValue -StartDate $startDate -EndDate $endDate
~~~
当任何应用程序不再使用的证书凭据时,Contoso 工程师将运行以下脚本以从使用 Get-msolserviceprincipalcredential cmdlet 来获取需要删除的凭据的标识符的服务主体中删除凭据密钥:
~~~
$servicePrincipalCredential = Get-MsolServicePrincipalCredential
-ServicePrincipalName $ServicePrincipal.ApplicationId -ReturnKeyValues 0
Remove-MsolServicePrincipalCredential
-ServicePrincipalName $ServicePrincipal.ApplicationId
-KeyIds $servicePrincipalCredential[0].KeyId
~~~
此脚本只需通过只从列表中删除第一个凭据显示 cmdlet 的用法。在实际的应用程序可能显式声明要删除的证书凭据的标识符。
处理多个部署: 该应用程序当前只依赖于 Azure AD 应用程序 ID,用于标识要使用 Azure AD 应用程序,以及各种密钥和机密标识符进行身份验证的证书的证书指纹。对于应用程序的不同部署,可以使用不同的密钥保管库。对于开发人员部署每个应用程序供应商可以创建密钥的保管库使用的操作的步骤,我讨论了 ; 其 Azure 订阅设置保管库并填充的密钥和机密该应用程序需要;然后更新配置文件。当 Contoso 团队需要部署用于测试应用程序时,它们可以使用从保管库在其订阅下部署的详细信息更新配置文件。
## 总结
Contoso 是高兴有实现这一转换到 Azure 密钥保管库,这可以帮助公司能够轻松地处理其应用程序必须向其应用这些安全风险的大多数。它已能够完成所有内容都将其设置出处理很少调整到应用程序代码中,并且这也使得很轻松地管理各种类型的敏感信息。Contoso 是能够进行此开关的易用性鼓励公司还使它们更加安全地重新访问其其他 LOB 应用程序。Azure 密钥保管库是大部分应用程序可能会使利用右离开,并使存储和管理加密密钥和其他敏感信息轻松、 安全。
* * *
Rahul Nath *是开发人员、 顾问和博主具有从构建丰富的 windows Azure 平台上的大型应用程序的客户端应用程序的体验。您可以关注他的 Twitter (网址 [twitter.com/rahulpnath](http://twitter.com/rahulpnath) 或阅读他的博客[rahulpnath.com](http://rahulpnath.com/)。*
- 介绍
- 云连接移动应用 - 借助身份验证和离线支持构建 Xamarin 应用
- 崛起 - 自由 Internet 广播
- Microsoft Azure - 云中的容错问题和解决方法
- 最前沿 - 适合常见应用程序的事件源
- Azure 深入了解 - 跨云平台创建统一的 Heroku 式工作流
- 借助 C++ 进行 Windows 开发 - Windows 运行时中的高级类型
- 编译器优化 - 借助按本机配置优化来简化代码
- 数据点 - 再探 JavaScript 数据绑定(现在包含 Aurelia)
- 云安全 - 借助 Azure 密钥保管库保护敏感信息的安全
- 测试运行 - 借助人工尖峰神经元进行计算
- 开发运营 - 在 Microsoft 堆栈上启用开发运营
- 孜孜不倦的程序员 - 如何成为 MEAN: Node.js
- 新型应用 - 提升新型应用的易用性的做法
- 别让我打开话匣子 - Darwin 的照相机
- 编辑寄语 - 汽车 Internet 发生故障