✓
ASP.NET Core

ASP.NET Core Data Protection in Docker: Persist Keys Safely Across Restarts

Advertisement
Ad space
.NET

ASP.NET Core Data Protection in Docker: Persist Keys Safely Across Restarts

A container restart should not silently invalidate every authentication cookie, anti-forgery token, password-reset link, or protected payload in your ASP.NET Core application. Yet that is exactly the failure mode you can create when Data Protection keys live only inside an ephemeral container filesystem.

This guide explains why the failure happens, how to persist the key ring deliberately, and what changes when you run more than one application instance. It focuses on a production boundary that is easy to overlook during local development.

Why keys matter

ASP.NET Core Data Protection is the framework cryptographic system used by several web features, including cookie authentication. It protects data with a managed key ring. If a new container starts with a new, unrelated key ring, it cannot unprotect data created by the old one. From a user’s perspective, that often looks like an unexpected sign-out.

Containers are designed to be replaceable. Their writable layer is therefore the wrong place to rely on for durable cryptographic state. Microsoft’s guidance is explicit: a container-hosted app should keep keys in a Docker volume that outlives the container, or use an external persistence provider.

Use a persistent volume for one deployed application

For a single-host deployment, mount a named volume at a known path and configure the application to use it. The volume survives a container replacement; the image stays immutable.

using Microsoft.AspNetCore.DataProtection;

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddDataProtection()
    .PersistKeysToFileSystem(new DirectoryInfo("/var/app/keys"))
    .SetApplicationName("orders-api-production");

var app = builder.Build();
app.MapGet("/", () => "OK");
app.Run();
services:
  api:
    image: example/orders-api:1.0.0
    volumes:
      - data-protection-keys:/var/app/keys

volumes:
  data-protection-keys:

SetApplicationName is intentional. It defines an isolation boundary for applications that share the same physical key repository. Use a stable, environment-specific name. Do not point unrelated applications at the same key store and assume the name alone creates a security boundary; separate storage and least-privilege access remain the safer design.

Protect the persisted key ring

Changing the persistence location changes the default protection behavior. In particular, a custom file location is not automatically encrypted at rest because the framework cannot infer the right encryption mechanism for that store. Protect the key ring with a suitable key-management service or certificate, and restrict read/write access to only the application identity that needs it.

For multi-instance deployments, every instance that must read the same protected payload needs access to the same durable key ring and the same application name. An external provider is often easier to operate than a shared filesystem across hosts. The storage choice is an operational decision: it needs availability, backup, access control, and a documented recovery path.

Do not “fix” restarts by disabling protection

Turning off cookies, reducing key lifetime, copying keys into an image, or baking secrets into a Dockerfile may hide the symptom while creating a larger security problem. Images are broadly distributed build artifacts; secrets and live key material do not belong in them. Keep configuration and key access separate from the build artifact.

Test the failure mode before production

  1. Sign in to a non-production environment and retain the authentication cookie.
  2. Replace the application container without deleting the mounted key volume.
  3. Make an authenticated request again. It should remain valid when the deployment intentionally shares its key ring.
  4. Repeat the test with a fresh, isolated key store. Confirm that the old protected payload is rejected; this proves the test detects the expected boundary.
  5. Verify that a principal without the application’s runtime identity cannot read or modify the key repository.

Production checklist

  • Persist Data Protection keys outside the ephemeral container filesystem.
  • Use a stable, environment-specific application name.
  • Protect keys at rest and grant least-privilege access.
  • Use a shared, durable repository for instances that must decrypt the same payloads.
  • Back up and test restoration of the key store; deleting keys can make protected data permanently unreadable.
  • Enable Data Protection information logging during diagnosis, without logging secrets.

Related deployment practices

A persistent key ring is one part of a safe container boundary. Pair it with the image-size, non-root runtime, and build-cache practices in ASP.NET Core Dockerfile best practices. Then ensure orchestrators only send traffic to an application that is actually ready by applying readiness and liveness health checks. For a broader architecture mindset, follow the System Design learning track.

Conclusion

Container restarts are normal; lost cryptographic continuity should not be. Persist, protect, and deliberately share Data Protection keys only where the deployment requires it. That small design decision prevents a disruptive class of authentication and state failures.

Sources

Sponsored
Ad space
🎉 Finished reading. Nice work!