Skip to content

Commit 2f07db0

Browse files
authored
Data Protection: Managed Identity with Blob/AKV (#35589)
1 parent 5e87350 commit 2f07db0

File tree

25 files changed

+790
-246
lines changed

25 files changed

+790
-246
lines changed

aspnetcore/blazor/call-web-api.md

Lines changed: 29 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ description: Learn how to call a web API from Blazor apps.
55
monikerRange: '>= aspnetcore-3.1'
66
ms.author: wpickett
77
ms.custom: mvc
8-
ms.date: 06/03/2025
8+
ms.date: 06/11/2025
99
uid: blazor/call-web-api
1010
---
1111
# Call a web API from ASP.NET Core Blazor
@@ -124,7 +124,7 @@ To configure a production distributed cache provider, see <xref:performance/cach
124124
For more information, see [Token cache serialization: Distributed caches](/entra/msal/dotnet/how-to/token-cache-serialization?tabs=msal#distributed-caches). However, the code examples shown don't apply to ASP.NET Core apps, which configure distributed caches via <xref:Microsoft.Extensions.DependencyInjection.MemoryCacheServiceCollectionExtensions.AddDistributedMemoryCache%2A>, not <xref:Microsoft.Identity.Web.TokenCacheExtensions.AddDistributedTokenCache%2A>.
125125
126126
<!-- DOC AUTHOR NOTE: The next part on using a shared DP key ring is also
127-
covered in the *BWA+Entra* security article. Mirror
127+
covered in the *BWA + Entra* security article. Mirror
128128
changes when updating this portion of content. -->
129129
130130
Use a shared Data Protection key ring in production so that instances of the app across servers in a web farm can decrypt tokens when <xref:Microsoft.Identity.Web.TokenCacheProviders.Distributed.MsalDistributedTokenCacheAdapterOptions.Encrypt%2A?displayProperty=nameWithType> is set to `true`.
@@ -138,7 +138,7 @@ Use a shared Data Protection key ring in production so that instances of the app
138138
>
139139
> Later in the development and testing period, enable token encryption and adopt a shared Data Protection key ring.
140140
141-
The following example shows how to use [Azure Blob Storage and Azure Key Vault (`PersistKeysToAzureBlobStorage`/`ProtectKeysWithAzureKeyVault`)](xref:security/data-protection/configuration/overview#protectkeyswithazurekeyvault) for the shared key ring. The service configurations are base case scenarios for demonstration purposes. Before deploying production apps, familiarize yourself with the Azure services and adopt best practices using their dedicated documentation sets, which are listed at the end of this section.
141+
The following example shows how to use [Azure Blob Storage and Azure Key Vault (`PersistKeysToAzureBlobStorage`/`ProtectKeysWithAzureKeyVault`)](xref:security/data-protection/configuration/overview#protect-keys-with-azure-key-vault-protectkeyswithazurekeyvault) for the shared key ring. The service configurations are base case scenarios for demonstration purposes. Before deploying production apps, familiarize yourself with the Azure services and adopt best practices using the Azure services' dedicated documentation sets, which are linked at the end of this section.
142142
143143
Add the following packages to the server project of the Blazor Web App:
144144
@@ -150,65 +150,41 @@ Add the following packages to the server project of the Blazor Web App:
150150
> [!NOTE]
151151
> Before proceeding with the following steps, confirm that the app is registered with Microsoft Entra.
152152
153-
Configure Azure Blob Storage to maintain Data Protection keys and encrypt them at rest with Azure Key Vault:
153+
Configure Azure Blob Storage to maintain data protection keys. Follow the guidance in <xref:security/data-protection/implementation/key-storage-providers#azure-storage>.
154154
155-
* Create an Azure storage account. The account name in the following example is `contoso`.
156-
157-
* Create a container to hold the Data Protection keys. The container name in the following example is `data-protection`.
158-
159-
* Create the key file on your local machine. In the following example, the key file is named `keys.xml`. You can use a text editor to create the file.
160-
161-
`keys.xml`:
162-
163-
```xml
164-
<?xml version="1.0" encoding="utf-8"?>
165-
<repository>
166-
</repository>
167-
```
168-
169-
* Upload the key file (`keys.xml`) to the container of the storage account. Use the context menu's **View/edit** command at the end of the key row in the portal to confirm that the blob contains the preceding content.
170-
171-
* Use the context menu's **Generate SAS** command to obtain the blob's URI with a shared access signature (SAS). When you create the SAS, use the following permissions: `Read`, `Add`, `Create`, `Write`, `Delete`. The URI is used later where the `{BLOB URI WITH SAS}` placeholder appears.
172-
173-
When establishing the key vault in the Entra or Azure portal:
174-
175-
* Configure the key vault to use a **Vault access policy**. Confirm that public access on the **Networking** step is **enabled** (checked).
176-
177-
* In the **Access policies** pane, create a new access policy with `Get`, `Unwrap Key`, and `Wrap Key` Key permissions. Select the registered application as the service principal.
178-
179-
* When key encryption is active, keys in the key file include the comment, ":::no-loc text="This key is encrypted with Azure Key Vault.":::" After starting the app, select the **View/edit** command from the context menu at the end of the key row to confirm that a key is present with key vault security applied.
180-
181-
The <xref:Microsoft.Extensions.Azure.AzureEventSourceLogForwarder> service in the following example forwards log messages from Azure SDK for logging and requires the [`Microsoft.Extensions.Azure` NuGet package](https://www.nuget.org/packages/Microsoft.Extensions.Azure).
182-
183-
[!INCLUDE[](~/includes/package-reference.md)]
184-
185-
At the top of the `Program` file, provide access to the API in the <xref:Microsoft.Extensions.Azure?displayProperty=fullName> namespace:
186-
187-
```csharp
188-
using Microsoft.Extensions.Azure;
189-
```
155+
Configure Azure Key Vault to encrypt the data protection keys at rest. Follow the guidance in <xref:security/data-protection/configuration/overview#protect-keys-with-azure-key-vault-protectkeyswithazurekeyvault>.
190156
191157
Use the following code in the `Program` file where services are registered:
192158
193159
```csharp
194-
builder.Services.TryAddSingleton<AzureEventSourceLogForwarder>();
160+
TokenCredential? credential;
161+
162+
if (builder.Environment.IsProduction())
163+
{
164+
credential = new ManagedIdentityCredential("{MANAGED IDENTITY CLIENT ID}");
165+
}
166+
else
167+
{
168+
// Local development and testing only
169+
credential = new DefaultAzureCredential();
170+
}
195171
196172
builder.Services.AddDataProtection()
197-
.PersistKeysToAzureBlobStorage(new Uri("{BLOB URI WITH SAS}"))
198-
.ProtectKeysWithAzureKeyVault(new Uri("{KEY IDENTIFIER}"), new DefaultAzureCredential());
173+
.SetApplicationName("{APPLICATION NAME}")
174+
.PersistKeysToAzureBlobStorage(new Uri("{BLOB URI}"), credential)
175+
.ProtectKeysWithAzureKeyVault(new Uri("{KEY IDENTIFIER}"), credential);
199176
```
200177
201-
`{BLOB URI WITH SAS}`: The full URI where the key file should be stored with the SAS token as a query string parameter. The URI is generated by Azure Storage when you request a SAS for the uploaded key file. The container name in the following example is `data-protection`, and the storage account name is `contoso`. The key file is named `keys.xml`.
178+
`{MANAGED IDENTITY CLIENT ID}`: The Azure Managed Identity Client ID (GUID).
202179
203-
Example:
180+
`{APPLICATION NAME}`: <xref:Microsoft.AspNetCore.DataProtection.DataProtectionBuilderExtensions.SetApplicationName%2A> sets the unique name of this app within the data protection system. The value should match across deployments of the app.
204181
205-
> :::no-loc text="https://contoso.blob.core.windows.net/data-protection/keys.xml?sp={PERMISSIONS}&st={START DATETIME}&se={EXPIRATION DATETIME}&spr=https&sv={STORAGE VERSION DATE}&sr=c&sig={TOKEN}":::
182+
`{BLOB URI}`: Full URI to the key file. The URI is generated by Azure Storage when you create the key file. Do not use a SAS.
206183
207-
`{KEY IDENTIFIER}`: Azure Key Vault key identifier used for key encryption. The key vault name is `contoso` in the following example, and an access policy allows the application to access the key vault with `Get`, `Unwrap Key`, and `Wrap Key` permissions. The example key name is `data-protection`. The version of the key (`{KEY VERSION}` placeholder) is obtained from the key in the Entra or Azure portal after it's created.
184+
`{KEY IDENTIFIER}`: Azure Key Vault key identifier used for key encryption. An access policy allows the application to access the key vault with `Get`, `Unwrap Key`, and `Wrap Key` permissions. The key identifier is obtained from the key in the Entra or Azure portal after it's created. If you enable autorotation of the key vault key, make sure that you use a versionless key identifier in the app's key vault configuration, where no key GUID is placed at the end of the identifier (example: `https://contoso.vault.azure.net/keys/data-protection`).
208185
209-
Example:
210-
211-
> :::no-loc text="https://contoso.vault.azure.net/keys/data-protection/{KEY VERSION}":::
186+
> [!NOTE]
187+
> In non-Production environments, the preceding example uses <xref:Azure.Identity.DefaultAzureCredential> to simplify authentication while developing apps that deploy to Azure by combining credentials used in Azure hosting environments with credentials used in local development. When moving to production, an alternative is a better choice, such as the <xref:Azure.Identity.ManagedIdentityCredential> shown in the preceding example. For more information, see [Authenticate Azure-hosted .NET apps to Azure resources using a system-assigned managed identity](/dotnet/azure/sdk/authentication/system-assigned-managed-identity).
212188
213189
Inject <xref:Microsoft.Identity.Abstractions.IDownstreamApi> and call <xref:Microsoft.Identity.Abstractions.IDownstreamApi.CallApiForUserAsync%2A> when calling on behalf of a user:
214190
@@ -233,17 +209,19 @@ This approach is used by the `BlazorWebAppEntra` and `BlazorWebAppEntraBff` samp
233209
234210
For more information, see the following resources:
235211
212+
* <xref:security/data-protection/implementation/key-storage-providers#azure-storage>
213+
* <xref:security/data-protection/configuration/overview#protect-keys-with-azure-key-vault-protectkeyswithazurekeyvault>
214+
* [Use the Azure SDK for .NET in ASP.NET Core apps](/dotnet/azure/sdk/aspnetcore-guidance?tabs=api)
236215
* [Web API documentation | Microsoft identity platform](/entra/identity-platform/index-web-api)
237216
* [A web API that calls web APIs: Call an API: Option 2: Call a downstream web API with the helper class](/entra/identity-platform/scenario-web-api-call-api-call-api?tabs=aspnetcore#option-2-call-a-downstream-web-api-with-the-helper-class)
238217
* <xref:Microsoft.Identity.Abstractions.IDownstreamApi>
239218
* *Secure an ASP.NET Core Blazor Web App with Microsoft Entra ID*
240219
* [Non-BFF pattern (Interactive Auto)](xref:blazor/security/blazor-web-app-entra?pivots=non-bff-pattern)
241220
* [BFF pattern (Interactive Auto)](xref:blazor/security/blazor-web-app-entra?pivots=non-bff-pattern-server)
242221
* [Host ASP.NET Core in a web farm: Data Protection](xref:host-and-deploy/web-farm#data-protection)
243-
* <xref:security/data-protection/configuration/overview>
244-
* <xref:security/data-protection/implementation/key-storage-providers>
245222
* [Azure Key Vault documentation](/azure/key-vault/general/)
246223
* [Azure Storage documentation](/azure/storage/)
224+
* [Provide access to Key Vault keys, certificates, and secrets with Azure role-based access control](/azure/key-vault/general/rbac-guide?tabs=azure-cli)
247225
248226
## Sample apps
249227

aspnetcore/blazor/file-uploads.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1256,7 +1256,7 @@ Consider an approach that uses [Azure Files](https://azure.microsoft.com/service
12561256
* [Azure Files REST API](/rest/api/storageservices/file-service-rest-api)
12571257
* [Azure Storage Blob client library for JavaScript](/javascript/api/overview/azure/storage-blob-readme)
12581258
* [Blob service REST API](/rest/api/storageservices/blob-service-rest-api)
1259-
* Authorize user uploads with a user-delegated shared-access signature (SAS) token generated by the app (server-side) for each client file upload. For example, Azure offers the following SAS features:
1259+
* Authorize user uploads with a user-delegated shared access signature (SAS) token generated by the app (server-side) for each client file upload. For example, Azure offers the following SAS features:
12601260
* [Azure Storage File Share client library for JavaScript: with SAS Token](/javascript/api/overview/azure/storage-file-share-readme#with-sas-token)
12611261
* [Azure Storage Blob client library for JavaScript: with SAS Token](/javascript/api/overview/azure/storage-blob-readme#with-sas-token)
12621262
* Provide automatic redundancy and file share backup.

aspnetcore/blazor/host-and-deploy/server/index.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -151,6 +151,9 @@ For a deeper exploration of scaling server-side Blazor apps on the Azure Contain
151151

152152
:::moniker-end
153153

154+
> [!NOTE]
155+
> The preceding example uses <xref:Azure.Identity.DefaultAzureCredential> to simplify authentication while developing apps that deploy to Azure by combining credentials used in Azure hosting environments with credentials used in local development. When moving to production, an alternative is a better choice, such as <xref:Azure.Identity.ManagedIdentityCredential>. For more information, see [Authenticate Azure-hosted .NET apps to Azure resources using a system-assigned managed identity](/dotnet/azure/sdk/authentication/system-assigned-managed-identity).
156+
154157
## IIS
155158

156159
When using IIS, enable:

aspnetcore/blazor/security/account-confirmation-and-password-recovery.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,9 @@ public static class AzureHelper
119119
}
120120
```
121121

122+
> [!NOTE]
123+
> The preceding example uses <xref:Azure.Identity.DefaultAzureCredential> to simplify authentication while developing apps that deploy to Azure by combining credentials used in Azure hosting environments with credentials used in local development. When moving to production, an alternative is a better choice, such as <xref:Azure.Identity.ManagedIdentityCredential>. For more information, see [Authenticate Azure-hosted .NET apps to Azure resources using a system-assigned managed identity](/dotnet/azure/sdk/authentication/system-assigned-managed-identity).
124+
122125
Where services are registered in the server project's `Program` file, obtain and bind the secret with [Options configuration](xref:fundamentals/configuration/options):
123126

124127
```csharp

0 commit comments

Comments
 (0)