ASP.NET Core Data Protection on Web Farm
Asked Answered
K

2

9

I have a ASP.NET Core application that uses cookie authentication and runs on web farm. The data protection keys are stored in DB. My application implements the IXmlRepository and the ASP.NET Core will call the IXmlRepository.GetAllElements to get the key ring. So, application in all nodes are using the same key ring and cookie encrypted in Node1 can be decrypted in Node2. It works fine.

However, data protection key will expire and ASP.NET Core will generate a new key. ASP.NET Core also cache the keys and will refresh each 18-24 hours. So, when the key expires, Node1 may generate a new key, but all other nodes may not refresh right away and get the new key. Cookie encrypted by Node1 cannot be decrypted in all other nodes.

How can this situation by handled by ASP.NET Core?

I read this https://learn.microsoft.com/en-us/aspnet/core/host-and-deploy/web-farm?view=aspnetcore-2.2, it states

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.

Is it the only option to route all requests to the same node after user login using that node?

Kiarakibble answered 24/5, 2019 at 16:46 Comment(1)
Simply put, you can't cache stuff locally if to be enabled cross servers, unless they in one way or the other expires (or renews) simultaneously. Search for and use "distributed caching", or route a user to a specific node.Rodrique
F
6

In principle, this is no different than any other shared configuration scenario. You need to do two things:

  1. Persist the key ring to a common filesystem or network location path all the processes/apps can access:

    services.AddDataProtection()
        .PersistKeysToFileSystem(new DirectoryInfo(@"\\server\share\directory\"));
    
  2. Ensure that all the process/apps are using the same application name:

    services.AddDataProtection()
        .SetApplicationName("shared app name");
    

The second item is less important for a web farm scenario, since it's all the same app and will have the same app name by default. However, it's always better to be explicit, and then if you do need to share with an entirely different app, you're already set up and ready to go.

In short, you need to add the following code:

services.AddDataProtection()
    .SetApplicationName("shared app name")
    .PersistKeysToFileSystem(new DirectoryInfo(@"\\server\share\directory\"));

To @LGSon's point in the comments below your question, you'll also run into an issue with caching/sessions eventually, as well. Regardless of being the same "app", you should think of the each instance in the web farm as a separate app. Each is a separate process, which means they have their own separate memory allocation. If you use memory caching (which is also the default storage for sessions), then that will be available only to the individual process that created it. Each process will therefore end up with separate cache and separate sessions. To share this information, you need to employ a distributed cache like Redis or SQL Server. See: https://learn.microsoft.com/en-us/aspnet/core/performance/caching/distributed?view=aspnetcore-2.2#establish-distributed-caching-services.

Note: Even though there's a "distributed" memory cache, it's not actually distributed. This is just an implementation of the IDistributedCache that stores in memory. Since it stores in-memory, it's still process bound.

Florentinoflorenza answered 24/5, 2019 at 18:12 Comment(2)
I don't use PersistKeysToFileSystem, but I use the IXmlRepository to persist the keys to DB. The difference is, for the data protection key, I have no control when it will read or refresh it. For configuration, I can use the IOptionsMonitor that will update the config when it is changed.Kiarakibble
How does this work when each instance of the application will attempt to roll new keys at the same-ish (within milliseconds if the applications are auto-deployed) time?Bottommost
L
0

There's an interesting GitHub issue discussing the key ring storage and key rotation here https://github.com/dotnet/aspnetcore/issues/26786

Also, if you want to know more about how you can store the key ring in Azure Key Vault, then I recently blogged about that here: Storing the ASP.NET Core Data Protection Key Ring in Azure Key Vault

Lovelovebird answered 12/10, 2020 at 14:39 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.