Data Protection Key Encryption
Chronicle uses ASP.NET Core Data Protection to securely manage encryption keys for OAuth tokens and other sensitive data. In production environments, these keys must be protected with an X.509 certificate to ensure security across multiple Chronicle instances.
Overview
Section titled “Overview”When Chronicle runs in a clustered environment, all instances need access to the same Data Protection keys to correctly encrypt and decrypt tokens. These keys are stored in MongoDB and shared across all instances using Orleans grains.
In production, an encryption certificate is required to protect these keys at rest. In development mode, the certificate is optional for convenience.
Configuration
Section titled “Configuration”JSON Configuration
Section titled “JSON Configuration”Add the encryption certificate configuration to your chronicle.json:
{ "encryptionCertificate": { "certificatePath": "/path/to/encryption-cert.pfx", "certificatePassword": "your-certificate-password" }}Environment Variables
Section titled “Environment Variables”Configure using environment variables (recommended for containerized deployments):
# Path to the PFX certificate fileCratis__Chronicle__EncryptionCertificate__CertificatePath=/app/certs/encryption-cert.pfx
# Certificate passwordCratis__Chronicle__EncryptionCertificate__CertificatePassword=your-certificate-passwordConfiguration Properties
Section titled “Configuration Properties”| Property | Type | Required (Production) | Description |
|---|---|---|---|
| certificatePath | string | Yes | Path to the PFX certificate file |
| certificatePassword | string | Yes* | Password for the certificate (* can be empty if cert has no password) |
Generating a Certificate
Section titled “Generating a Certificate”You can use the same certificate for both TLS and Data Protection key encryption, or generate a separate certificate specifically for key encryption.
Using .NET CLI
Section titled “Using .NET CLI”# Generate a certificate for key encryptiondotnet dev-certs https -ep ./encryption-cert.pfx -p YourSecurePassword123Using OpenSSL
Section titled “Using OpenSSL”# Generate a private keyopenssl genrsa -out encryption.key 2048
# Create a self-signed certificateopenssl req -x509 -new -nodes -key encryption.key -sha256 -days 3650 \ -out encryption.crt \ -subj "/CN=Chronicle Data Protection/O=Your Organization"
# Convert to PFX formatopenssl pkcs12 -export -out encryption-cert.pfx \ -inkey encryption.key -in encryption.crt \ -password pass:YourSecurePassword123Docker Configuration
Section titled “Docker Configuration”Mount the certificate when running Chronicle in Docker:
version: '3.8'
services: chronicle: image: cratis/chronicle:latest ports: - "8080:8080" - "35000:35000" volumes: - ./certs/encryption-cert.pfx:/app/certs/encryption-cert.pfx:ro environment: - Cratis__Chronicle__Storage__ConnectionDetails=mongodb://mongodb:27017 - Cratis__Chronicle__EncryptionCertificate__CertificatePath=/app/certs/encryption-cert.pfx - Cratis__Chronicle__EncryptionCertificate__CertificatePassword=YourSecurePassword123Using Same Certificate for TLS and Encryption
Section titled “Using Same Certificate for TLS and Encryption”You can use the same PFX certificate for both TLS and Data Protection key encryption:
services: chronicle: image: cratis/chronicle:latest volumes: - ./certs/chronicle.pfx:/app/certs/chronicle.pfx:ro environment: # TLS configuration - Cratis__Chronicle__Tls__CertificatePath=/app/certs/chronicle.pfx - Cratis__Chronicle__Tls__CertificatePassword=YourPassword # Data Protection key encryption (same certificate) - Cratis__Chronicle__EncryptionCertificate__CertificatePath=/app/certs/chronicle.pfx - Cratis__Chronicle__EncryptionCertificate__CertificatePassword=YourPasswordMulti-Instance Deployments
Section titled “Multi-Instance Deployments”In clustered deployments, all Chronicle instances must use the same encryption certificate. This ensures that any instance can decrypt Data Protection keys stored in the shared MongoDB database.
services: chronicle-1: image: cratis/chronicle:latest environment: - Cratis__Chronicle__EncryptionCertificate__CertificatePath=/app/certs/encryption-cert.pfx - Cratis__Chronicle__EncryptionCertificate__CertificatePassword=SharedPassword volumes: - ./certs/encryption-cert.pfx:/app/certs/encryption-cert.pfx:ro
chronicle-2: image: cratis/chronicle:latest environment: - Cratis__Chronicle__EncryptionCertificate__CertificatePath=/app/certs/encryption-cert.pfx - Cratis__Chronicle__EncryptionCertificate__CertificatePassword=SharedPassword volumes: - ./certs/encryption-cert.pfx:/app/certs/encryption-cert.pfx:roDevelopment Mode
Section titled “Development Mode”In development mode (when Chronicle is built with the DEVELOPMENT configuration), the encryption certificate is optional. This allows for easier local development without certificate management overhead.
Auto-Generated Certificates (Development Only)
Section titled “Auto-Generated Certificates (Development Only)”When no encryption certificate is configured and Chronicle is compiled with DEVELOPMENT mode, Chronicle will automatically generate a self-signed certificate for development purposes. This certificate is:
- Location: Stored in a
certificatesfolder in the current working directory - Filename:
encryption-cert.pfx - Password:
chronicle-auto-generated(auto-assigned) - Validity: 10 years from generation
- Reuse: If the certificate already exists, Chronicle will use it instead of generating a new one
This feature is designed to simplify local development and testing. The certificate is automatically created on first use and persisted for subsequent runs, ensuring encrypted data remains accessible across restarts.
Important: In production builds (without the DEVELOPMENT directive), Chronicle will throw an
EncryptionCertificateNotConfiguredexception if no certificate is configured. Auto-generation only occurs in development mode.
Running Without Configuration
Section titled “Running Without Configuration”To run without a certificate in development:
# No certificate configuration needed in developmentdocker run -d \ --name chronicle-dev \ -p 8080:8080 \ -p 35000:35000 \ -e Cratis__Chronicle__Storage__ConnectionDetails=mongodb://localhost:27017 \ cratis/chronicle:latest-developmentWarning: Auto-generated certificates should never be used in production environments. They are not cryptographically secure for production use and are intended only for development convenience. Production deployments must configure a proper encryption certificate.
Security Best Practices
Section titled “Security Best Practices”- Use strong passwords - Certificate passwords should be complex and unique
- Protect certificate files - Store certificates securely and limit access
- Rotate certificates - Implement a certificate rotation strategy for production
- Separate concerns - Consider using different certificates for TLS and key encryption
- Backup certificates - Ensure certificates are backed up securely; losing the certificate means losing access to encrypted keys
- Use secrets management - In production, use a secrets manager (Azure Key Vault, HashiCorp Vault, etc.) to store certificate passwords
Troubleshooting
Section titled “Troubleshooting”Certificate Not Found
Section titled “Certificate Not Found”If you see an error about the certificate not being found:
- Verify the certificate path is correct and accessible
- Check file permissions on the certificate file
- Ensure the path uses forward slashes in Docker/Linux environments
Invalid Certificate Password
Section titled “Invalid Certificate Password”If authentication fails after configuration:
- Verify the certificate password is correct
- Check for special characters that may need escaping in environment variables
- Ensure the password matches what was used during certificate generation
Next Steps
Section titled “Next Steps”- Local Certificates - TLS certificate setup for development
- Production Hosting - Production deployment requirements
- Configuration - Complete configuration reference