Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

DataProtection and scaling /8 #33104

Open
wants to merge 27 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 15 commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
f524f55
DataProtection and scaling
Rick-Anderson Jul 16, 2024
7e7f446
DataProtection and scaling
Rick-Anderson Jul 16, 2024
09a8106
DataProtection and scaling
Rick-Anderson Jul 16, 2024
ba71c7b
DataProtection and scaling
Rick-Anderson Jul 16, 2024
36f9423
Apply suggestions from code review
Rick-Anderson Jul 17, 2024
1973c82
DataProtection and scaling
Rick-Anderson Jul 17, 2024
73d70c1
DataProtection and scaling
Rick-Anderson Jul 17, 2024
907cfc6
react to feedback
Rick-Anderson Jul 17, 2024
6ea6eec
react to feedback
Rick-Anderson Jul 17, 2024
8c27b91
react to feedback
Rick-Anderson Jul 17, 2024
5dea93a
react to feedback
Rick-Anderson Jul 17, 2024
ba6186b
react to feedback
Rick-Anderson Jul 17, 2024
0d6f57d
Apply suggestions from code review
Rick-Anderson Jul 17, 2024
33d328c
react to feedback
Rick-Anderson Jul 17, 2024
fff74ab
react to feedback
Rick-Anderson Jul 17, 2024
4963274
react to feedback
Rick-Anderson Jul 19, 2024
065ba19
Draft a section on how to use a separate key manager to eliminate races
amcasey Oct 4, 2024
2201cd3
react to feedback
Rick-Anderson Dec 5, 2024
ec06d56
Update aspnetcore/host-and-deploy/web-farm.md
Rick-Anderson Dec 5, 2024
e058df8
react to feedback
Rick-Anderson Dec 5, 2024
6a7ebb0
react to feedback
Rick-Anderson Dec 5, 2024
96a80b3
react to feedback
Rick-Anderson Dec 5, 2024
50e65a4
react to feedback
Rick-Anderson Dec 5, 2024
807f8f6
react to feedback
Rick-Anderson Dec 6, 2024
6e07927
react to feedback
Rick-Anderson Dec 6, 2024
8537b5f
react to feedback
Rick-Anderson Dec 6, 2024
5e53be9
react to feedback
Rick-Anderson Dec 6, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 9 additions & 3 deletions aspnetcore/host-and-deploy/web-farm.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,11 +38,17 @@ When an app is scaled to multiple instances, there might be app state that requi

## Required configuration

Data Protection and Caching require configuration for apps deployed to a web farm.
Data Protection and Caching may require configuration for apps deployed to a web farm.

### Data Protection
### Data Protection in distributed environments

The [ASP.NET Core Data Protection system](xref:security/data-protection/introduction) is used by apps to protect data. Data Protection relies upon a set of cryptographic keys stored in a *key ring*. When the Data Protection system is initialized, it applies [default settings](xref:security/data-protection/configuration/default-settings) that store the key ring locally. Under the default configuration, a unique key ring is stored on each node of the web farm. Consequently, each web farm node can't decrypt data that's encrypted by an app on any other node. The default configuration isn't generally appropriate for hosting apps in a web farm. An alternative to implementing a shared key ring is to always route user requests to the same node. For more information on Data Protection system configuration for web farm deployments, see <xref:security/data-protection/configuration/overview>.
amcasey marked this conversation as resolved.
Show resolved Hide resolved
The [ASP.NET Core Data Protection system](xref:security/data-protection/introduction) is used by apps to protect data. Data Protection relies upon a set of cryptographic keys stored in a *key ring*. When the Data Protection system is initialized, it applies [default settings](xref:security/data-protection/configuration/default-settings) that store the key ring locally. The default configuration is appropriate for apps that run in a single instance.

Apps that are running in distributed environments that don't configure Data Protection automatically need to explicitly configure Data Protection. See <xref:security/data-protection/configuration/scaling> for environments that require explicit Data Protection configuration and those that don't.

Under the default configuration, a unique key ring is stored on each node of the web farm. Consequently, each web farm node can't decrypt data that's encrypted by an app on any other node. The default configuration isn't generally appropriate for hosting apps in a web farm. Sticky sessions using [ARR Affinity](/azure/app-service/manage-automatic-scaling?#how-does-arr-affinity-affect-automatic-scaling) is an alternative to implementing a shared key ring is to always route user requests to the same node. However, ARR can reduce the scalability of a web farm.
Rick-Anderson marked this conversation as resolved.
Show resolved Hide resolved

For more information on Data Protection system configuration for web farm deployments, see <xref:security/data-protection/configuration/overview>.

### Caching

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ By [Rick Anderson](https://twitter.com/RickAndMSFT)

The app attempts to detect its operational environment and handle key configuration on its own.

1. If the app is hosted in [Azure Apps](https://azure.microsoft.com/services/app-service/), keys are persisted to the *%HOME%\ASP.NET\DataProtection-Keys* folder. This folder is backed by network storage and is synchronized across all machines hosting the app.
1. If the app is hosted in [Azure Apps](/azure/app-service/overview), keys are persisted to the *%HOME%\ASP.NET\DataProtection-Keys* folder. This folder is backed by network storage and is synchronized across all machines hosting the app.
* Keys aren't protected at rest.
* The *DataProtection-Keys* folder supplies the key ring to all instances of an app in a single deployment slot.
* Separate deployment slots, such as Staging and Production, don't share a key ring. When you swap between deployment slots, for example swapping Staging to Production or using A/B testing, any app using Data Protection won't be able to decrypt stored data using the key ring inside the previous slot. This leads to users being logged out of an app that uses the standard ASP.NET Core cookie authentication, as it uses Data Protection to protect its cookies. If you desire slot-independent key rings, use an external key ring provider, such as Azure Blob Storage, Azure Key Vault, a SQL store, or Redis cache.
Expand Down
36 changes: 36 additions & 0 deletions aspnetcore/security/data-protection/configuration/scaling.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
---
title: Configure ASP.NET Core Data Protection in distributed or load-balanced environments
author: acasey
description: Learn how to configure Data Protection in ASP.NET Core for multi-instance apps.
ms.author: acasey
ms.date: 7/18/2024
content_well_notification: AI-contribution
ms.prod: aspnet-core
uid: security/data-protection/configuration/scaling
---

# Configure ASP.NET Core Data Protection in distributed or load-balanced environments

:::moniker range=">= aspnetcore-8.0"

ASP.NET Core [Data Protection](xref:security/data-protection/introduction) is a library that provides a cryptographic API to protect data. Data Protection protects anti-forgery tokens, authentication cookies, and other sensitive data. However, in some distributed environments that don't put data protection keys in shared storage, when an app scales horizontally by adding more instances:

* It's necessary to explicitly configure Data Protection to establish a shared storage location for Data Protection keys.
* There’s ***NO*** guarantee that the HTTP POST request, used to submit a form, will be routed to the same instance that served the initial page via an HTTP GET request. If the requests are handled by different instances, the anti-forgery tokens aren’t synchronized, and an exception occurs. Sticky sessions via [ARR Affinity](/azure/app-service/manage-automatic-scaling?#how-does-arr-affinity-affect-automatic-scaling) routes user requests to the same node. However, ARR can reduce the scalability of a web farm.

The following distributed environments provide automatic key storage in a shared location:
amcasey marked this conversation as resolved.
Show resolved Hide resolved

* [Azure apps](/aspnet/core/security/data-protection/configuration/default-settings). For more information see <xref:security/data-protection/configuration/default-settings#key-management>.
* Newly created Azure Container Apps built using ASP.NET Core. For more information see [Autoscaling considerations
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've asked ACA for a date we can use in place of "newly created".

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Did you get a date?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@claudiaregio Can you remember how we scoped this? I've suddenly remembered that this might only affect Aspire apps for now?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@claudiaregio Can you remember how we scoped this? I've suddenly remembered that this might only affect Aspire apps for now?

@claudiaregio ?

](/azure/container-apps/dotnet-overview#autoscaling-considerations).

The following scenarios do ***NOT*** provide automatic key storage in a shared location:
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This list still feels off to me. What if we framed it as a list of caveats and dropped the mention of non-Azure and ARR?

If ARR is important, we could say that it's an alternative (that applies everywhere, not just non-Azure) though, personally, I think we covered that adequately in the intro.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@amcasey Can you use the suggestion feature to rough draft your approach? I can wordsmith your suggestion


* Separate [deployment slots](/azure/app-service/deploy-staging-slots), such as Staging and Production.
* Azure Container Apps built using ASP.NET Core Kestrel 7.0 or earlier. For more information see [Autoscaling considerations
Rick-Anderson marked this conversation as resolved.
Show resolved Hide resolved
](/azure/container-apps/dotnet-overview#autoscaling-considerations).
* Asp.net core apps hosted on multiple non-Azure VMs that don't use server affinity. Server affinity ensures that a client's requests are always routed to the same server so having the keys in a shared location is not necessary. For more information see [Server affinity](/azure/app-service/manage-automatic-scaling?#how-does-arr-affinity-affect-automatic-scaling).

:::moniker-end
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I couldn't figure out a nice way to phrase "ACA will do this for you automatically, if you let it".

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

review my rewrite and use the suggestion feature if needed.


[!INCLUDE[](~/security/data-protection/configuration/scaling/includes/scaling7.md)]
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@

:::moniker range="< aspnetcore-8.0"
Rick-Anderson marked this conversation as resolved.
Show resolved Hide resolved

<!--
Duplicate of primary doc, only change:
using .NET 8.0
-->

:::moniker-end
Loading