教學課程:使用 Azure 金鑰保存庫加密及解密 Blob

在本教學課程中,您將了解如何使用用戶端加密,以利用 Azure Key Vault 儲存的金鑰來加密和解密 Blob。

Azure Blob 儲存體同時支援服務端和用戶端加密。 在大部分情況下,Microsoft 建議使用服務端加密功能,以方便用來保護資料。 若要深入了解服務端加密,請參閱待用資料的 Azure 儲存體加密

適用於 .NET 的 Azure Blob 儲存體用戶端程式庫支援在上傳至 Azure 儲存體之前於應用程式內進行用戶端資料加密,並在下載至用戶端時解密資料。 此程式庫也支援與 Azure Key Vault 整合,以進行金鑰管理。

本教學課程會示範如何:

  • 設定 Azure Key Vault 資源的權限
  • 使用 .NET 用戶端程式庫建立要與資源互動的主控台應用程式
  • 將金鑰新增至金鑰保存庫
  • 使用金鑰保存庫中儲存的金鑰來設定用戶端加密選項
  • 建立已啟用用戶端加密的 Blob 服務用戶端物件
  • 上傳加密的 Blob,然後下載並解密該 Blob

必要條件

將角色指派給 Microsoft Entra 使用者

在本機開發時,請確定存取金鑰保存庫的使用者帳戶具有正確的權限。 您將需要金鑰保存庫密碼編譯人員角色來建立金鑰,並對金鑰保存庫中的金鑰執行動作。 您可以使用 Azure 入口網站、Azure CLI 或 Azure PowerShell,將 Azure RBAC 角色指派給使用者。 您可以在範圍概觀頁面上深入了解角色指派的可用範圍。

在此案例中,您會將權限指派給使用者帳戶 (範圍限定在金鑰保存庫),以遵循最低權限原則。 此做法只為使用者提供所需的最低權限,並建立更安全的實際執行環境。

下列範例說明如何將金鑰保存庫密碼編譯人員角色指派給您的使用者帳戶,以提供完成本教學課程所需的存取權。

重要

在大部分情況下,角色指派在 Azure 中傳播只需要一兩分鐘,但在罕見情況下,可能需要長達八分鐘。 如果您第一次執行程式碼時收到驗證錯誤,請稍候片刻再試一次。

  1. 在 Azure 入口網站中,使用主要搜尋列或左側導覽找出您的金鑰保存庫。

  2. 在金鑰保存庫概觀頁面上,從左側功能表中選取 [存取控制 (IAM)]

  3. 在 [存取控制 (IAM)] 頁面上,選取 [角色指派] 索引標籤。

  4. 從頂端功能表選取 [+ 新增],然後從產生的下拉功能表中選取 [新增角色指派]

    A screenshot showing how to assign a role in Azure portal.

  5. 使用搜尋方塊,從結果篩選出所需的角色。 針對此範例,搜尋「金鑰保存庫密碼編譯人員」,並選取相符的結果,然後選擇 [下一步]

  6. 在 [存取權指派對象為] 下,選取 [使用者、群組或服務主體],然後選擇 [+ 選取成員]

  7. 在對話方塊中,搜尋 Microsoft Entra 使用者名稱 (通常是您的 user@domain 電子郵件地址),然後在對話方塊底部選擇 [選取]

  8. 選取 [檢閱 + 指派] 以移至最終頁面,然後再次選取 [檢閱 + 指派] 以完成此程序。

設定您的專案

  1. 在主控台視窗中 (例如 PowerShell 或 Bash),使用 dotnet new 命令建立名為 BlobEncryptionKeyVault 的新主控台應用程式。 此命令會建立簡單的 "Hello World" C# 專案,內含單一原始程式檔:Program.cs

    dotnet new console -n BlobEncryptionKeyVault
    
  2. 切換至新建立的 BlobEncryptionKeyVault 目錄。

    cd BlobEncryptionKeyVault
    
  3. 在您想要的程式碼編輯器中開啟專案。 若要開啟專案:

    • 在 Visual Studio 中,找出並按兩下 BlobEncryptionKeyVault.csproj 檔案。
    • 在 Visual Studio Code 中,執行下列命令︰
    code .
    

若要在此範例中與 Azure 服務互動,請使用 dotnet add package 安裝下列用戶端程式庫。

dotnet add package Azure.Identity
dotnet add package Azure.Security.KeyVault.Keys
dotnet add package Azure.Storage.Blobs

新增下列 using 指示詞,並確定將 System.Configuration 的參考新增至專案。

using Azure;
using Azure.Core;
using Azure.Identity;
using Azure.Security.KeyVault.Keys;
using Azure.Security.KeyVault.Keys.Cryptography;
using Azure.Storage;
using Azure.Storage.Blobs;
using Azure.Storage.Blobs.Models;
using Azure.Storage.Blobs.Specialized;

設定環境變數

此應用程式會尋找稱為 KEY_VAULT_NAME 的環境變數,以擷取金鑰保存庫的名稱。 若要設定環境變數,請開啟主控台視窗,並遵循您作業系統所適用的指示。 將 <your-key-vault-name> 取代為金鑰保存庫的名稱。

Windows:

您可以從命令列為 Windows 設定環境變數。 不過這麼做的話,該作業系統上執行的所有應用程式就都能使用該值,因此可能在您疏忽時造成衝突。 環境變數可在使用者或系統層級設定:

setx KEY_VAULT_NAME "<your-key-vault-name>"

在 Windows 中新增環境變數之後,您必須啟動新的命令視窗執行個體。 如果您在 Windows 上使用 Visual Studio,則在建立環境變數之後,您可能需要重新啟動 Visual Studio,才能偵測到變更。

Linux:

export KEY_VAULT_NAME=<your-key-vault-name>

在 Azure Key Vault 中新增金鑰

在此範例中,我們會使用 Azure Key Vault 用戶端程式庫,建立金鑰並將其新增至金鑰保存庫。 您也可以使用 Azure CLIAzure 入口網站PowerShell,建立金鑰並將其新增至金鑰保存庫。

在下列範例中,我們會為指定的保存庫建立 KeyClient 物件。 接著使用 KeyClient 物件,在指定的保存庫中建立新的 RSA 金鑰。

var keyName = "testRSAKey";
var keyVaultName = Environment.GetEnvironmentVariable("KEY_VAULT_NAME");

// URI for the key vault resource
var keyVaultUri = $"https://{keyVaultName}.vault.azure.net";

TokenCredential tokenCredential = new DefaultAzureCredential();

// Create a KeyClient object
var keyClient = new KeyClient(new Uri(keyVaultUri), tokenCredential);

// Add a key to the key vault
var key = await keyClient.CreateKeyAsync(keyName, KeyType.Rsa);

建立金鑰和金鑰解析器執行個體

接下來,我們將使用剛新增至保存庫的金鑰,來建立密碼編譯用戶端和金鑰解析器執行個體。 CryptographyClient 會實作 IKeyEncryptionKey,並用來搭配 Azure Key Vault 中儲存的金鑰執行密碼編譯作業。 KeyResolver 會實作 IKeyEncryptionResolver,然後從金鑰識別碼擷取金鑰加密金鑰並解析金鑰。

// Cryptography client and key resolver instances using Azure Key Vault client library
CryptographyClient cryptoClient = keyClient.GetCryptographyClient(key.Value.Name, key.Value.Properties.Version);
KeyResolver keyResolver = new (tokenCredential);

如果您在保存庫中具有想要加密的現有金鑰,則可以傳入 URI,來建立金鑰和金鑰解析器執行個體:

var keyVaultKeyUri = $"https://{keyVaultName}.vault.azure.net/keys/{keyName}";
CryptographyClient cryptoClient = new CryptographyClient(new Uri(keyVaultKeyUri), tokenCredential);

設定加密選項

現在,我們需要設定要用於 Blob 上傳和下載的加密選項。 若要使用用戶端加密,我們首先會建立 ClientSideEncryptionOptions 物件,並使用 SpecializedBlobClientOptions 在用戶端建立時加以設定。

ClientSideEncryptionOptions 類別會提供用戶端設定選項,用於使用用戶端加密連線到 Blob 儲存體。 KeyEncryptionKey 對於上傳作業是必要的,且用來包裝產生的內容加密金鑰。 KeyResolver 對於下載作業是必要的,並會擷取正確的金鑰加密金鑰,來解除包裝下載的內容加密金鑰。 KeyWrapAlgorithm 對於上傳是必要的,並會指定包裝內容加密金鑰時要使用的演算法識別碼。

重要

由於第 1 版的安全性弱點,建議使用 ClientSideEncryptionVersion.V2_0 作為版本參數來建構 ClientSideEncryptionOptions 物件。 若要深入了解如何緩解應用程式中的弱點,請參閱緩解應用程式中的安全性弱點。 如需此安全性弱點的詳細資訊,請參閱Azure 儲存體更新 SDK 中的用戶端加密以解決安全性弱點

// Configure the encryption options to be used for upload and download
ClientSideEncryptionOptions encryptionOptions = new (ClientSideEncryptionVersion.V2_0)
{
    KeyEncryptionKey = cryptoClient,
    KeyResolver = keyResolver,
    // String value that the client library will use when calling IKeyEncryptionKey.WrapKey()
    KeyWrapAlgorithm = "RSA-OAEP"
};

// Set the encryption options on the client options.
BlobClientOptions options = new SpecializedBlobClientOptions() { ClientSideEncryption = encryptionOptions };

將用戶端物件設定為使用用戶端加密

在此範例中,我們會將用戶端加密設定選項套用至 BlobServiceClient 物件。 在服務用戶端層級套用時,這些加密選項會從服務用戶端傳遞至容器用戶端,然後從容器用戶端傳遞至 Blob 用戶端。 當 BlobClient 執行上傳或下載作業時,Azure Blob 儲存體用戶端程式庫會使用信封加密來加密和解密用戶端上的 Blob。 信封加密會使用一或多個額外的金鑰來加密金鑰。

// Create a blob client with client-side encryption enabled.
// Attempting to construct a BlockBlobClient, PageBlobClient, or AppendBlobClient from a BlobContainerClient
// with client-side encryption options present will throw, as this functionality is only supported with BlobClient.
Uri blobUri = new (string.Format($"https://{accountName}.blob.core.windows.net"));
BlobClient blob = new BlobServiceClient(blobUri, tokenCredential, options).GetBlobContainerClient("test-container").GetBlobClient("testBlob");

加密 blob 和上傳

BlobClient 物件呼叫上傳方法時,出現數個步驟來執行用戶端加密:

  1. Azure 儲存體用戶端程式庫會產生 16 位元組的隨機初始化向量 (IV),以及 32 位元組的隨機內容加密金鑰 (CEK),並使用這項資訊執行 Blob 資料的信封加密。
  2. Blob 資料會使用 CEK 進行加密。
  3. CEK 接著會使用我們在 ClientSideEncryptionOptions 中指定的金鑰加密金鑰 (KEK) 進行包裝 (加密)。 在此範例中,KEK 是儲存在所指定 Azure Key Vault 資源中的非對稱金鑰組。 Blob 用戶端本身永遠無法存取 KEK,只會叫用 Key Vault 所提供的金鑰包裝演算法。
  4. 加密的 Blob 資料接著會上傳至儲存體帳戶。

新增下列程式碼來加密 Blob 並將其上傳至 Azure 儲存體帳戶:

// Upload the encrypted contents to the blob
Stream blobContent = BinaryData.FromString("Ready for encryption, Captain.").ToStream();
await blob.UploadAsync(blobContent);

一旦上傳了 Blob,您就可以檢視儲存體帳戶中的 Blob,以查看加密的內容,以及加密中繼資料。

解密 blob 和下傳

Azure 儲存體用戶端程式庫假設使用者在本機或金鑰保存庫中管理 KEK。 使用者不必知道用於加密的特定金鑰。 在下載和解密 Blob 資料時,ClientSideEncryptionOptions 中指定的金鑰解析器將用來解析金鑰識別碼。

BlobClient 物件呼叫下載方法時,出現數個步驟來解密加密的 Blob 資料:

  1. 用戶端程式庫會從儲存體帳戶下載加密的 Blob 資料,包括加密中繼資料。
  2. 包裝的 CEK 接著會使用 KEK 解除包裝 (解密)。 用戶端程式庫在此過程中無法存取 KEK,而是只會叫用 ClientSideEncryptionOptions 中指定的金鑰解除包裝演算法。 RSA 金鑰組的私密金鑰會保留在保存庫金鑰中,因此來自 Blob 中繼資料包含 CEK 的加密金鑰會傳送至金鑰保存庫進行解密。
  3. 用戶端程式庫會使用 CEK 來解密加密的 Blob 資料。

新增下列程序代碼,以下載並解密您先前上傳的 Blob。

// Download and decrypt the encrypted contents from the blob
Response<BlobDownloadInfo>  response = await blob.DownloadAsync();
BlobDownloadInfo downloadInfo = response.Value;
Console.WriteLine((await BinaryData.FromStreamAsync(downloadInfo.Content)).ToString());

下一步

在本教學課程中,您已了解如何使用 .NET 用戶端程式庫,為 Blob 上傳和下載作業執行用戶端加密。

如需對 Blob 進行用戶端加密的廣泛概觀,包括將加密資料移轉至第 2 版的指示,請參閱 Blob 的用戶端加密

如需 Azure Key Vault 的詳細資訊,請參閱 Azure Key Vault 概觀頁面