Skip to content

Commit 33cd86f

Browse files
authored
Merge pull request #216340 from pauljewellmsft/pauljewell-encryption-kv
Add article for client-side encryption using Azure Key Vault
2 parents ba2e2ea + 2f992a5 commit 33cd86f

File tree

4 files changed

+297
-5
lines changed

4 files changed

+297
-5
lines changed

.openpublishing.redirection.json

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6423,11 +6423,6 @@
64236423
"redirect_url": "/azure/storage/blobs/storage-encrypt-decrypt-blobs-key-vault",
64246424
"redirect_document_id": false
64256425
},
6426-
{
6427-
"source_path_from_root": "/articles/storage/blobs/storage-encrypt-decrypt-blobs-key-vault.md",
6428-
"redirect_url": "/azure/storage/blobs/client-side-encryption",
6429-
"redirect_document_id": false
6430-
},
64316426
{
64326427
"source_path_from_root": "/articles/storage/blobs/Storage-blob-performance-tiers.md",
64336428
"redirect_url": "/azure/storage/common/storage-account-overview",

articles/storage/blobs/TOC.yml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,8 @@ items:
8888
href: storage-auth-abac-powershell.md
8989
- name: CLI
9090
href: storage-auth-abac-cli.md
91+
- name: Encrypt and decrypt blobs using Azure Key Vault
92+
href: storage-encrypt-decrypt-blobs-key-vault.md
9193
- name: Samples
9294
items:
9395
- name: .NET
47.4 KB
Loading
Lines changed: 295 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,295 @@
1+
---
2+
title: Encrypt and decrypt blobs using Azure Key Vault
3+
titleSuffix: Azure Storage
4+
description: Learn how to encrypt and decrypt a blob using client-side encryption with Azure Key Vault.
5+
author: pauljewellmsft
6+
ms.service: storage
7+
ms.topic: tutorial
8+
ms.date: 11/2/2022
9+
ms.author: pauljewell
10+
ms.reviewer: ozgun
11+
ms.subservice: blobs
12+
ms.devlang: csharp
13+
ms.custom: devx-track-csharp
14+
---
15+
16+
# Tutorial: Encrypt and decrypt blobs using Azure Key Vault
17+
18+
In this tutorial, you learn how to use client-side encryption to encrypt and decrypt blobs using a key stored with Azure Key Vault.
19+
20+
Azure Blob Storage supports both service-side and client-side encryption. For most scenarios, Microsoft recommends using service-side encryption features for ease of use in protecting your data. To learn more about service-side encryption, see [Azure Storage encryption for data at rest](../common/storage-service-encryption.md).
21+
22+
The [Azure Blob Storage client library for .NET](/dotnet/api/overview/azure/storage) supports client-side data encryption within applications before uploading to Azure Storage, and decrypting data while downloading to the client. The library also supports integration with [Azure Key Vault](https://azure.microsoft.com/services/key-vault/) for key management.
23+
24+
This tutorial shows you how to:
25+
26+
> [!div class="checklist"]
27+
> * Configure permissions for an Azure Key Vault resource
28+
> * Create a console application to interact with resources using .NET client libraries
29+
> * Add a key to a key vault
30+
> * Configure client-side encryption options using a key stored in a key vault
31+
> * Create a blob service client object with client-side encryption enabled
32+
> * Upload an encrypted blob, then download and decrypt the blob
33+
34+
## Prerequisites
35+
36+
- Azure subscription - [create an account for free](https://azure.microsoft.com/free/?WT.mc_id=A261C142F)
37+
- Azure storage account - [create a storage account](../common/storage-account-create.md)
38+
- Key vault - create one using [Azure portal](/azure/key-vault/general/quick-create-portal), [Azure CLI](/azure/key-vault/general/quick-create-cli), or [PowerShell](/azure/key-vault/general/quick-create-powershell)
39+
- [Visual Studio 2022](https://visualstudio.microsoft.com) installed
40+
41+
## Assign a role to your Azure AD user
42+
43+
When developing locally, make sure that the user account that is accessing the key vault has the correct permissions. You'll need the [Key Vault Crypto Officer role](/azure/role-based-access-control/built-in-roles#key-vault-crypto-officer) to create a key and perform actions on keys in a key vault. You can assign Azure RBAC roles to a user using the Azure portal, Azure CLI, or Azure PowerShell. You can learn more about the available scopes for role assignments on the [scope overview](../../../articles/role-based-access-control/scope-overview.md) page.
44+
45+
In this scenario, you'll assign permissions to your user account, scoped to the key vault, to follow the [Principle of Least Privilege](../../../articles/active-directory/develop/secure-least-privileged-access.md). This practice gives users only the minimum permissions needed and creates more secure production environments.
46+
47+
The following example shows how to assign the **Key Vault Crypto Officer** role to your user account, which provides the access you'll need to complete this tutorial.
48+
49+
> [!IMPORTANT]
50+
> In most cases it will take a minute or two for the role assignment to propagate in Azure, but in rare cases it may take up to eight minutes. If you receive authentication errors when you first run your code, wait a few moments and try again.
51+
52+
### [Azure portal](#tab/roles-azure-portal)
53+
54+
1. In the Azure portal, locate your key vault using the main search bar or left navigation.
55+
56+
2. On the storage account overview page, select **Access control (IAM)** from the left-hand menu.
57+
58+
3. On the **Access control (IAM)** page, select the **Role assignments** tab.
59+
60+
4. Select **+ Add** from the top menu and then **Add role assignment** from the resulting drop-down menu.
61+
62+
:::image type="content" source="./media/storage-blob-encryption-keyvault/assign-role-kv.png" lightbox="./media/storage-blob-encryption-keyvault/assign-role-kv.png" alt-text="A screenshot showing how to assign a role in Azure portal.":::
63+
64+
5. Use the search box to filter the results to the desired role. For this example, search for *Key Vault Crypto Officer* and select the matching result and then choose **Next**.
65+
66+
6. Under **Assign access to**, select **User, group, or service principal**, and then choose **+ Select members**.
67+
68+
7. In the dialog, search for your Azure AD username (usually your *user@domain* email address) and then choose **Select** at the bottom of the dialog.
69+
70+
8. Select **Review + assign** to go to the final page, and then **Review + assign** again to complete the process.
71+
72+
### [Azure CLI](#tab/roles-azure-cli)
73+
74+
To assign a role at the resource level using the Azure CLI, you first must retrieve the resource ID using the `az storage account show` command. You can filter the output properties using the `--query` parameter.
75+
76+
```azurecli
77+
az keyvault show --resource-group '<your-resource-group-name>' --name '<your-unique-keyvault-name>' --query id
78+
```
79+
80+
Copy the output `Id` from the preceding command. You can then assign roles using the [az role](/cli/azure/role) command of the Azure CLI.
81+
82+
```azurecli
83+
az role assignment create --assignee "<user@domain>" \
84+
--role "Key Vault Crypto Officer" \
85+
--scope "<your-resource-id>"
86+
```
87+
88+
### [PowerShell](#tab/roles-powershell)
89+
90+
To assign a role at the resource level using Azure PowerShell, you first must retrieve the resource ID using the `Get-AzResource` command.
91+
92+
```azurepowershell
93+
Get-AzResource -ResourceGroupName "<yourResourceGroupname>" -Name "<yourKeyVaultName>"
94+
```
95+
96+
Copy the `Id` value from the preceding command output. You can then assign roles using the [New-AzRoleAssignment](/powershell/module/az.resources/new-azroleassignment) command in PowerShell.
97+
98+
```azurepowershell
99+
New-AzRoleAssignment -SignInName <user@domain> `
100+
-RoleDefinitionName "Key Vault Crypto Officer" `
101+
-Scope <yourKeyVaultId>
102+
```
103+
104+
---
105+
106+
## Set up your project
107+
108+
1. In a console window (such as PowerShell or Bash), use the `dotnet new` command to create a new console app with the name *BlobEncryptionKeyVault*. This command creates a simple "Hello World" C# project with a single source file: *Program.cs*.
109+
110+
```dotnetcli
111+
dotnet new console -n BlobEncryptionKeyVault
112+
```
113+
114+
1. Switch to the newly created *BlobEncryptionKeyVault* directory.
115+
116+
```console
117+
cd BlobEncryptionKeyVault
118+
```
119+
120+
1. Open the project in your desired code editor. To open the project in:
121+
* Visual Studio, locate and double-click the `BlobEncryptionKeyVault.csproj` file.
122+
* Visual Studio Code, run the following command:
123+
124+
```bash
125+
code .
126+
```
127+
---
128+
129+
To interact with Azure services in this example, install the following client libraries using `dotnet add package`.
130+
131+
### [.NET CLI](#tab/packages-dotnetcli)
132+
133+
```dotnetcli
134+
dotnet add package Azure.Identity
135+
dotnet add package Azure.Security.KeyVault.Keys
136+
dotnet add package Azure.Storage.Blobs
137+
```
138+
139+
### [PowerShell](#tab/packages-powershell)
140+
141+
```powershell
142+
Install-Package Azure.Identity
143+
Install-Package Azure.Security.KeyVault.Keys
144+
Install-Package Azure.Storage.Blobs
145+
```
146+
---
147+
148+
Add the following `using` directives and make sure to add a reference to `System.Configuration` to the project.
149+
150+
```csharp
151+
using Azure;
152+
using Azure.Core;
153+
using Azure.Identity;
154+
using Azure.Security.KeyVault.Keys;
155+
using Azure.Security.KeyVault.Keys.Cryptography;
156+
using Azure.Storage;
157+
using Azure.Storage.Blobs;
158+
using Azure.Storage.Blobs.Models;
159+
using Azure.Storage.Blobs.Specialized;
160+
```
161+
162+
## Set environment variable
163+
164+
This application looks for an environment variable called `KEY_VAULT_NAME` to retrieve the name of your key vault. To set the environment variable, open a console window and follow the instructions for your operating system. Replace `<your-key-vault-name>` with the name of your key vault.
165+
166+
**Windows:**
167+
168+
You can set environment variables for Windows from the command line. However, when using this approach the values are accessible to all applications running on that operating system and may cause conflicts if you aren't careful. Environment variables can be set at either user or system level:
169+
170+
```cmd
171+
setx KEY_VAULT_NAME "<your-key-vault-name>"
172+
````
173+
After you add the environment variable in Windows, you must start a new instance of the command window. If you're using Visual Studio on Windows, you may need to relaunch Visual Studio after creating the environment variable for the change to be detected.
174+
175+
**Linux:**
176+
177+
```bash
178+
export KEY_VAULT_NAME=<your-key-vault-name>
179+
```
180+
181+
## Add a key in Azure Key Vault
182+
183+
In this example, we create a key and add it to the key vault using the Azure Key Vault client library. You can also create and add a key to a key vault using [Azure CLI](/azure/key-vault/keys/quick-create-cli#add-a-key-to-key-vault), [Azure portal](/azure/key-vault/keys/quick-create-portal#add-a-key-to-key-vault), or [PowerShell](/azure/key-vault/keys/quick-create-powershell#add-a-key-to-key-vault).
184+
185+
In the sample below, we create a [KeyClient](/dotnet/api/azure.security.keyvault.keys.keyclient) object for the specified vault. The `KeyClient` object is then used to create a new RSA key in the specified vault.
186+
187+
```csharp
188+
var keyName = "testRSAKey";
189+
var keyVaultName = Environment.GetEnvironmentVariable("KEY_VAULT_NAME");
190+
191+
// URI for the key vault resource
192+
var keyVaultUri = $"https://{keyVaultName}.vault.azure.net";
193+
194+
TokenCredential tokenCredential = new DefaultAzureCredential();
195+
196+
// Create a KeyClient object
197+
var keyClient = new KeyClient(new Uri(keyVaultUri), tokenCredential);
198+
199+
// Add a key to the key vault
200+
var key = await keyClient.CreateKeyAsync(keyName, KeyType.Rsa);
201+
```
202+
203+
## Create key and key resolver instances
204+
205+
Next, we'll use the key we just added to the vault to create the cryptography client and key resolver instances. [CryptographyClient](/dotnet/api/azure.security.keyvault.keys.cryptography.cryptographyclient) implements [IKeyEncryptionKey](/dotnet/api/azure.core.cryptography.ikeyencryptionkey) and is used to perform cryptographic operations with keys stored in Azure Key Vault. [KeyResolver](/dotnet/api/azure.security.keyvault.keys.cryptography.keyresolver) implements [IKeyEncryptionResolver](/dotnet/api/azure.core.cryptography.ikeyencryptionkeyresolver) and retrieves key encryption keys from the key identifier and resolves the key.
206+
```csharp
207+
// Cryptography client and key resolver instances using Azure Key Vault client library
208+
CryptographyClient cryptoClient = keyClient.GetCryptographyClient(key.Value.Name, key.Value.Properties.Version);
209+
KeyResolver keyResolver = new (tokenCredential);
210+
```
211+
212+
If you have an existing key in the vault that you'd like to encrypt with, you can create the key and key resolver instances by passing in the URI:
213+
```csharp
214+
var keyVaultKeyUri = $"https://{keyVaultName}.vault.azure.net/keys/{keyName}";
215+
CryptographyClient cryptoClient = new CryptographyClient(new Uri(keyVaultKeyUri), tokenCredential);
216+
```
217+
218+
## Configure encryption options
219+
220+
Now we need to configure the encryption options to be used for blob upload and download. To use client-side encryption, we first create a `ClientSideEncryptionOptions` object and set it on client creation with `SpecializedBlobClientOptions`.
221+
222+
The [ClientSideEncryptionOptions](/dotnet/api/azure.storage.clientsideencryptionoptions) class provides the client configuration options for connecting to Blob Storage using client-side encryption. [KeyEncryptionKey](/dotnet/api/azure.storage.clientsideencryptionoptions.keyencryptionkey) is required for upload operations and is used to wrap the generated content encryption key. [KeyResolver](/dotnet/api/azure.storage.clientsideencryptionoptions.keyresolver) is required for download operations and fetches the correct key encryption key to unwrap the downloaded content encryption key. [KeyWrapAlgorithm]() is required for uploads and specifies the algorithm identifier to use when wrapping the content encryption key.
223+
224+
> [!IMPORTANT]
225+
>Due to a security vulnerability in version 1, it's recommended to construct the `ClientSideEncryptionOptions` object using `ClientSideEncryptionVersion.V2_0` for the version parameter. To learn more about mitigating the vulnerability in your apps, see [Mitigate the security vulnerability in your applications](client-side-encryption.md#mitigate-the-security-vulnerability-in-your-applications). For more information about this security vulnerability, see [Azure Storage updating client-side encryption in SDK to address security vulnerability](https://aka.ms/azstorageclientencryptionblog).
226+
227+
```csharp
228+
// Configure the encryption options to be used for upload and download
229+
ClientSideEncryptionOptions encryptionOptions = new (ClientSideEncryptionVersion.V2_0)
230+
{
231+
KeyEncryptionKey = cryptoClient,
232+
KeyResolver = keyResolver,
233+
// String value that the client library will use when calling IKeyEncryptionKey.WrapKey()
234+
KeyWrapAlgorithm = "RSA-OAEP"
235+
};
236+
237+
// Set the encryption options on the client options.
238+
BlobClientOptions options = new SpecializedBlobClientOptions() { ClientSideEncryption = encryptionOptions };
239+
```
240+
241+
## Configure client object to use client-side encryption
242+
243+
In this example, we apply the client-side encryption configuration options to a `BlobServiceClient` object. When applied at the service client level, these encryption options are passed from the service client to container clients, and from container clients to blob clients. When the `BlobClient` object performs an upload or download operation, the Azure Blob Storage client libraries use envelope encryption to encrypt and decrypt blobs on the client side. Envelope encryption encrypts a key with one or more additional keys.
244+
245+
```csharp
246+
// Create a blob client with client-side encryption enabled.
247+
// Attempting to construct a BlockBlobClient, PageBlobClient, or AppendBlobClient from a BlobContainerClient
248+
// with client-side encryption options present will throw, as this functionality is only supported with BlobClient.
249+
Uri blobUri = new (string.Format($"https://{accountName}.blob.core.windows.net"));
250+
BlobClient blob = new BlobServiceClient(blobUri, tokenCredential, options).GetBlobContainerClient("test-container").GetBlobClient("testBlob");
251+
```
252+
253+
## Encrypt blob and upload
254+
When the `BlobClient` object calls an upload method, several steps occur to perform the client-side encryption:
255+
1. The Azure Storage client library generates a random initialization vector (IV) of 16 bytes and a random content encryption key (CEK) of 32 bytes, and performs envelope encryption of the blob data using this information.
256+
1. Blob data is encrypted using the CEK.
257+
1. The CEK is then wrapped (encrypted) using the key encryption key (KEK) we specified in `ClientSideEncryptionOptions`. In this example, the KEK is an asymmetric key pair stored in the specified Azure Key Vault resource. The blob client itself never has access to the KEK, it just invokes the key wrapping algorithm that is provided by Key Vault.
258+
1. The encrypted blob data is then uploaded to the storage account.
259+
260+
Add the following code to encrypt a blob and upload it to your Azure storage account:
261+
262+
```csharp
263+
// Upload the encrypted contents to the blob
264+
Stream blobContent = BinaryData.FromString("Ready for encryption, Captain.").ToStream();
265+
await blob.UploadAsync(blobContent);
266+
```
267+
268+
Once the blob is uploaded, you can view the blob in your storage account to see the encrypted contents along with the encryption metadata.
269+
270+
## Decrypt blob and download
271+
272+
The Azure Storage client library assumes that the user is managing the KEK either locally or in a key vault. The user doesn't need to know the specific key that was used for encryption. The key resolver specified in `ClientSideEncryptionOptions` will be used to resolve key identifiers when blob data is downloaded and decrypted.
273+
274+
When the `BlobClient` object calls a download method, several steps occur to decrypt the encrypted blob data:
275+
276+
1. The client library downloads the encrypted blob data, including encryption metadata, from the storage account.
277+
1. The wrapped CEK is then unwrapped (decrypted) using the KEK. The client library doesn't have access to the KEK during this process, but only invokes the key unwrapping algorithm specified in `ClientSideEncryptionOptions`. The private key of they RSA key pair remains in the key vault, so the encrypted key from the blob metadata that contains the CEK is sent to the key vault for decryption.
278+
1. The client library uses the CEK to decrypt the encrypted blob data.
279+
280+
Add the following code to download and decrypt the blob that you previously uploaded.
281+
282+
```csharp
283+
// Download and decrypt the encrypted contents from the blob
284+
Response<BlobDownloadInfo> response = await blob.DownloadAsync();
285+
BlobDownloadInfo downloadInfo = response.Value;
286+
Console.WriteLine((await BinaryData.FromStreamAsync(downloadInfo.Content)).ToString());
287+
```
288+
289+
## Next steps
290+
291+
In this tutorial, you learned how to use .NET client libraries to perform client-side encryption for blob upload and download operations.
292+
293+
For a broad overview of client-side encryption for blobs, including instructions for migrating encrypted data to version 2, see [Client-side encryption for blobs](client-side-encryption.md).
294+
295+
For more information about Azure Key Vault, see the [Azure Key Vault overview page](../../key-vault/general/overview.md)

0 commit comments

Comments
 (0)