I am a bit unclear on how Data Protection keys work in a web farm environment. I don't have a common location that all servers can use (and don't want to deal with permissions). Therefore I'd like to generate a key and distribute it with the web application.
I am doing the following, but not sure if that is right. So I generate a key file locally on my dev pc with:
var specialFolder = Environment.SpecialFolder.CommonApplicationData;
var appDataPath = Path.Combine(
Environment.GetFolderPath(specialFolder),
"company",
"product"
);
services.AddDataProtection().PersistKeysToFileSystem(new DirectoryInfo(appDataPath));
This creates a key-some-guid.xml
file. I then distribute this file with my web application.
Now, when I run my web app, in the Startup.Configure services, copy this file to the appDataPath
location (defined above) and call services.AddDataProtection().PersistKeysToFileSystem(new DirectoryInfo(appDataPath));
.
Will that work? Or am I fundamentally missing something?
Answering my own question. The following seems to work across a web farm. Call the method below from Startup.ConfigureServices. It assumes that the key (that was generated on a dev machine) resides in the Keys folder off the root of the project.
public Startup(IHostingEnvironment env)
{
/* skipping boilerplate setup code */
Environment = env;
}
private IHostingEnvironment Environment { get; set; }
private void ConfigureDataProtection(IServiceCollection services) {
// get the file from the Keys directory
string keysFile = string.Empty;
string keysPath = Path.Combine(Environment.ContentRootPath, "Keys");
if (!Directory.Exists(keysPath)) {
Log.Add($"Keys directory {keysPath} doesn't exist");
return;
}
string[] files = Directory.GetFiles(keysPath);
if (files.Length == 0) {
LLog.Add($"No keys found in directory {keysPath}");
return;
} else {
keysFile = files[0];
if (files.Length >= 2) {
LLog.Add($"Warning: More than 1 key found in directory {keysPath}. Using first one.");
}
}
// find and optionally create the path for the key storage
var appDataPath = Path.Combine(
System.Environment.GetFolderPath(System.Environment.SpecialFolder.CommonApplicationData),
"companyName",
"productName"
);
if (!Directory.Exists(appDataPath)) {
try {
Directory.CreateDirectory(appDataPath);
} catch (Exception ex) {
Log.Add($"Error creating key storage folder at {appDataPath}. Error: {ex.Message}");
return;
}
}
// delete any keys from the storage directory
try {
foreach (var file in new DirectoryInfo(appDataPath).GetFiles()) file.Delete();
} catch (Exception ex) {
Log.Add($"Error deleting keys from {appDataPath}. Error: {ex.Message}");
return;
}
try {
string targetPath = Path.Combine(appDataPath, new FileInfo(keysFile).Name);
File.Copy(keysFile, targetPath, true);
} catch (Exception ex) {
Log.Add($"Error copying key file {keysFile} to {appDataPath}. Error: {ex.Message}");
return;
}
// everything is in place
services.AddDataProtection()
.PersistKeysToFileSystem(new DirectoryInfo(appDataPath))
.DisableAutomaticKeyGeneration();
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With