2015 年 9 月

第 30 卷,第 9 期

本文章是由機器翻譯。

Microsoft Azure-保護機密資訊與 Azure 的金鑰保存庫

Rahul Nath | 2015 年 9 月

許多應用程式建置今日處理中的機密資訊某種形式或另一個通常至外部系統例如資料庫的連接字串。這些金鑰通常會部署為應用程式的組態檔的一部分,可用以純文字給任何人可以存取部署伺服器。很明顯地,這會造成龐大的安全性威脅。

Microsoft Azure 金鑰保存庫是雲端託管硬體安全性模組 (HSM)-備份服務來管理密碼編譯金鑰和其他機密資訊 — 秘密金鑰保存庫術語中的 — 在集中位置,而且可以藉由指定的機碼或密碼的適當 URI 存取透過 REST API。金鑰保存庫也可讓您建立軟體的索引鍵,而不是 HSM 備份。在這兩種情況下之金鑰的私密部分不會保留金鑰保存庫界限和可以永遠不會被看見或共用。

在本文中我將逐步引導您在其中大型公司 Contoso 外包給不同廠商的開發與建置特定業務 (LOB) 應用程式的案例。應用程式與多個協力廠商服務互動並處理機密資訊,包括客戶個人識別資訊 (PII)。我將討論在現有的實作第一個和安全性公司會發出此造成則會顯示公司如何使用 Azure 金鑰保存庫來解決這些問題。

現有的應用程式

Contoso 是大型的汽車製造公司目前正在建立 LOB 應用程式提供媒介和其他有興趣的合作對象的單一平台上的客戶連線的汽車經驗。Contoso 有小型 IT 小組內部,因為它承接委外工作的不同廠商的應用程式建置的應用程式的不同部分的每個開發。應用程式是雲端裝載並公開不同應用程式開發介面各種實體與它互動。它也可以使用協力廠商應用程式的 Api 來取用外部服務和呼叫透過 Web 服務公開的內部 Contoso 應用程式的資料。

應用程式處理 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 指令程式,您可以藉由指定保存庫名稱 (這是全域唯一的)、 資源群組和位置建立新的保存庫:

Switch-AzureMode AzureResourceManager
New-AzureResourceGroup –Name 'ContosoResourceGroup' –Location 'East Asia'
New-AzureKeyVault -VaultName 'ContosoKeyVault' -ResourceGroupName
  'ContosoResourceGroup' -Location 'East Asia'

在命令成功執行,新建立的金鑰保存庫的詳細資料則會輸出到 Azure PowerShell 主控台,其中包含保存庫名稱以及唯一識別保存庫的 URI。

設定金鑰保存庫: 建立和儲存的密碼編譯金鑰和也是有沒有特定的語意 (semantics) 的限制大小八位元物件的秘密的儲存體可讓 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'

在成功執行這會是新的軟體 RSA 金鑰建立 ContosoKeyVault,可以識別其唯一識別碼 (例如 https://ContosoKeyVault.vault.azure.net/keys/ContosoPIIKey/ bfacf5f768ae42ffb0a0bca448aead87) 工程師會共用與應用程式廠商。

在 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 的金鑰保存庫的存取都被安全使用 Azure Active Directory (Azure AD) 的應用程式權杖。若要這樣做,Contoso 工程師必須先在 Azure AD 中建立的應用程式和保護其安全的驗證金鑰 (共用密碼) 或憑證。建立使用驗證金鑰存取保護 Azure AD 應用程式可以透過 Azure 管理入口網站中,在應用程式] 索引標籤中的 Active Directory 選項。但是其索引鍵的保存庫保護與驗證索引鍵為沒有什麼 Contoso 慣用這一次表示將機密資訊放在用戶端應用程式組態檔是他們想要在第一時間避免。此外,因為金鑰保存庫是其所有的機密資料的單一存放區,允許存取的認證是應該極力避免的項目。因此,Contoso 會決定使用憑證式驗證,並且讓它可以將憑證部署到應用程式需要它直接可以進一步保護憑證使用的密碼。

建立使用憑證驗證的 Azure AD 應用程式可以透過 Windows PowerShell 命令列來完成。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 應用程式的應用程式權杖可以用來針對金鑰保存庫進行驗證。這可以使用 Set 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) 來連接到索引鍵的保存庫。

驗證用戶端應用程式與 Azure AD 應用程式輕易完成使用 Azure AD 驗證程式庫 (ADAL),這也以 NuGet 套件的形式提供。所有應用程式需要向 Azure AD 應用程式是用戶端識別碼和可以放在組態檔中的憑證識別碼 (例如指紋)。這些可以安全地部署在組態檔中因為本身不是機密資訊。

C# SDK 提供所示的 KeyVaultClient 類別 [圖 1。其建構函式接受回呼方法以提供有效的語彙基元從 Azure AD 應用程式。每當執行密碼編譯的動作時使用的用戶端呼叫的回呼方法。有效的憑證是使用自訂函式 GetCertificateByThumbprint 使用指紋資訊從應用程式的組態檔,用來驗證對 Azure AD 應用程式中提取。ADAL 程式庫會從 Azure AD 應用程式第一次收到的權杖快取和權杖到期前做為每個後續的呼叫快取的 token。

[圖 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。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 的應用程式識別碼,用來識別要使用 Azure AD 應用程式與各種金鑰和密碼的識別項進行驗證的憑證的憑證指紋。針對不同的應用程式部署,可以使用不同的金鑰保存庫。開發人員部署每個應用程式廠商可以建立使用下列程序之前討論過; 其 Azure 訂用帳戶的金鑰保存庫設定保存庫並填入的金鑰和秘密應用程式預期。然後更新組態檔。當 Contoso 小組需要部署應用程式進行測試時,他們可以更新組態檔的部署其訂用帳戶底下的保存庫的詳細資料。

總結

Contoso 一定很滿意參數對 Azure 金鑰保存庫中,幫助公司就可以輕鬆處理大部分的已遭其應用程式有安全性風險。它可以完成它處理應用程式程式碼很少的調整設定的所有項目且也變得更加容易管理各種類型的機密資訊。與 contoso 能夠將這個參數的簡易鼓勵公司重新瀏覽其他 LOB 應用程式同時也使它們更安全。Azure 金鑰保存庫是大部分的應用程式可使用的權限離開並使儲存和管理密碼編譯金鑰與其他簡單又安全的機密資訊。


Rahul Nath 是開發人員、 顧問和部落客範圍從建置豐富的 windows Azure 平台上的大型應用程式的用戶端應用程式的體驗。您可以依照他在 Twitter 上 twitter.com/rahulpnath 或閱讀他的部落格 rahulpnath.com

感謝以下的微軟技術專家對本文的審閱: Amit Bapat
Amit Bapat 目前專案經理,Microsoft Azure 金鑰保存庫。Microsoft 之前, Amit 曾在 Intel 在各種角色包括產品行銷 Intel Xeon 處理器和技術的各種軟體專案以及設計 Intel Cpu 的 CAD 工程師的角色。