Update .NET DataProtection config to be resilient against container restarts (#493)

This commit is contained in:
Leendert de Borst
2025-07-21 16:13:03 +02:00
committed by Leendert de Borst
parent 80a9996a23
commit e8a40ea18e
3 changed files with 32 additions and 20 deletions

View File

@@ -58,13 +58,9 @@ public static class LoggingConfiguration
// Log all warning and above to database via EF core except for:
// - Microsoft.EntityFrameworkCore logsas this would create a loop.
// - Microsoft.AspNetCore.Antiforgery logs
// - Microsoft.AspNetCore.DataProtection logs
.WriteTo.Logger(lc => lc
.Filter.ByIncludingOnly(evt => evt.Level >= LogEventLevel.Warning)
.Filter.ByExcluding(Matching.FromSource("Microsoft.EntityFrameworkCore"))
.Filter.ByExcluding(Matching.FromSource("Microsoft.AspNetCore.Antiforgery"))
.Filter.ByExcluding(Matching.FromSource("Microsoft.AspNetCore.DataProtection"))
.WriteTo.Sink(new DatabaseSink(CultureInfo.InvariantCulture, () => services.BuildServiceProvider().GetRequiredService<IDbContextFactory<AliasServerDbContext>>(), applicationName)))
.CreateLogger());

View File

@@ -18,7 +18,7 @@ using Microsoft.Extensions.DependencyInjection;
public static class DataProtectionExtensions
{
/// <summary>
/// Setup .NET DataProtection to use common AliasVault settings with self-signed certificate.
/// Setup .NET DataProtection to use common AliasVault settings.
/// </summary>
/// <param name="services">Services.</param>
/// <param name="applicationName">Application name.</param>
@@ -36,25 +36,41 @@ public static class DataProtectionExtensions
certPath = Path.Combine(AppContext.BaseDirectory, $"{applicationName}.DataProtection.Development.pfx");
}
var certificateFlags = X509KeyStorageFlags.MachineKeySet |
X509KeyStorageFlags.PersistKeySet |
X509KeyStorageFlags.Exportable;
// Use different protection methods for containerized environments
var isContainer = Environment.GetEnvironmentVariable("DOTNET_RUNNING_IN_CONTAINER") == "true" ||
Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT") == "Production";
X509Certificate2 cert;
if (!File.Exists(certPath))
var dataProtectionBuilder = services.AddDataProtection()
.PersistKeysToDbContext<AliasServerDbContext>()
.SetApplicationName(applicationName);
if (isContainer)
{
cert = CertificateGenerator.GeneratePfx($"{applicationName}.DataProtection", certPassword);
CertificateGenerator.SaveCertificateToFile(cert, certPassword, certPath);
// When running in containers, don't use certificate-based key protection due to Linux keystore limitations
dataProtectionBuilder.UseCryptographicAlgorithms(new Microsoft.AspNetCore.DataProtection.AuthenticatedEncryption.ConfigurationModel.AuthenticatedEncryptorConfiguration()
{
EncryptionAlgorithm = Microsoft.AspNetCore.DataProtection.AuthenticatedEncryption.EncryptionAlgorithm.AES_256_CBC,
ValidationAlgorithm = Microsoft.AspNetCore.DataProtection.AuthenticatedEncryption.ValidationAlgorithm.HMACSHA256,
});
}
else
{
cert = X509CertificateLoader.LoadPkcs12FromFile(certPath, certPassword, certificateFlags);
}
// Use certificate-based protection for development
var certificateFlags = X509KeyStorageFlags.MachineKeySet | X509KeyStorageFlags.PersistKeySet | X509KeyStorageFlags.Exportable;
services.AddDataProtection()
.PersistKeysToDbContext<AliasServerDbContext>()
.ProtectKeysWithCertificate(cert)
.SetApplicationName(applicationName);
X509Certificate2 cert;
if (!File.Exists(certPath))
{
cert = CertificateGenerator.GeneratePfx($"{applicationName}.DataProtection", certPassword);
CertificateGenerator.SaveCertificateToFile(cert, certPassword, certPath);
}
else
{
cert = X509CertificateLoader.LoadPkcs12FromFile(certPath, certPassword, certificateFlags);
}
dataProtectionBuilder.ProtectKeysWithCertificate(cert);
}
return services;
}

View File

@@ -1242,7 +1242,7 @@ print_install_success_message() {
# Function to recreate (restart) Docker containers
recreate_docker_containers() {
printf "${CYAN} (Re)creating Docker containers...${NC} "
printf "${CYAN} (Re)creating Docker containers...${NC}\n"
if [ "$VERBOSE" = true ]; then
printf "\b${NC}\n"
@@ -1454,7 +1454,7 @@ handle_build() {
printf "\n${YELLOW}+++ Building and starting services +++${NC}\n"
printf "${CYAN} Building Docker Compose stack...${NC} "
printf "${CYAN} Building Docker Compose stack...${NC}\n"
if [ "$VERBOSE" = true ]; then
printf "\b${NC}\n"
if ! $(get_docker_compose_command) build; then