Key Management
Encryption key derivation, rotation, and security best practices for Open-ACE.
Overview
Open-ACE uses Fernet symmetric encryption to protect sensitive data at rest:
- API keys for remote workspaces (
api_key_storetable) - SMTP passwords (
smtp_settingstable) - Model Gateway API keys (
model_gateway_configtable)
Proxy tokens use HMAC-SHA256 signatures (not Fernet) for authentication.
Key Derivation
The encryption key is derived from the OPENACE_ENCRYPTION_KEY environment variable:
OPENACE_ENCRYPTION_KEY (env var, >= 32 chars)
│
│ SHA-256 hash
▼
32-byte key
│
│ base64.urlsafe_b64encode
▼
Fernet key (44 chars)
│
├────────────────┬────────────────┐
▼ ▼ ▼
API Key SMTP Password Model Gateway
Encryption Encryption Encryption
│
│ Same key for HMAC-SHA256
▼
Proxy Token
Signing
Key derivation code:
import hashlib
import base64
key_env = os.environ.get("OPENACE_ENCRYPTION_KEY")
derived_key = hashlib.sha256(key_env.encode()).digest()
fernet_key = base64.urlsafe_b64encode(derived_key)
Key Sharing Impact
The same key is used for:
- API Key encryption -
api_key_store.encrypted_key - SMTP password encryption -
smtp_settings.encrypted_password - Model Gateway encryption -
model_gateway_config.encrypted_api_key - Proxy Token signing - HMAC-SHA256 signatures for remote agent authentication
Implications:
- Key rotation requires re-encrypting all three data stores
- Active proxy tokens signed with the old key will fail validation after rotation
- Key compromise affects all four security domains
Key Rotation
Current Limitations
- Single-key Fernet: No support for MultiFernet multi-key decryption
- Rotation requires downtime: Cannot rotate keys without service restart
- Manual process: No automated key rotation mechanism
Rotation Methods
Method A: Stop-and-Rotate (Recommended for small deployments)
Prerequisites:
- Database backup capability
- Planned maintenance window
- Root access to environment variables
Steps:
-
Backup the database
# PostgreSQLpg_dump openace > openace_backup_$(date +%Y%m%d).sql# SQLitecp app.db app_backup_$(date +%Y%m%d).db -
Export encrypted data
python scripts/export_encrypted_data.py --output encrypted_data_backup.jsonThis exports:
api_key_store.encrypted_key→ plaintext API keyssmtp_settings.encrypted_password→ plaintext SMTP passwordsmodel_gateway_config.encrypted_api_key→ plaintext gateway keys
-
Generate and set new key
# Generate a new 32-byte keyNEW_KEY=$(openssl rand -hex 32)echo "New key: $NEW_KEY"# Update environment variable# Docker Compose: edit .env file# Kubernetes: update Secret# Systemd: edit /etc/open-ace/environment -
Restart the service
# Docker Composedocker-compose restart# Systemdsudo systemctl restart open-ace -
Re-encrypt and import data
python scripts/import_encrypted_data.py --input encrypted_data_backup.json -
Verify functionality
- Test API key storage and retrieval
- Test SMTP email sending
- Test Model Gateway calls
- Note: Existing proxy tokens will be invalid (users need to restart sessions)
-
Secure cleanup
# Remove plaintext backup after verificationrm encrypted_data_backup.json# Optionally archive encrypted database backupgzip openace_backup_*.sql
Method B: MultiFernet Support (Future enhancement)
Requirements:
- Code modification to support
MultiFernet - Environment variable format:
KEY1;KEY2(primary;fallback) - Zero-downtime rotation capability
Implementation needed:
- Modify
_get_encryption_key()to return key list - Use
MultiFernet([key1, key2])for decryption - Use primary key for new encryption
- Gradual migration path
Security Best Practices
Key Generation
# Generate a strong random key (256 bits = 32 bytes = 64 hex chars)
openssl rand -hex 32
Key Storage
- Never commit to source control
- Use environment variables or secrets management:
- Docker Compose:
.envfile (add to.gitignore) - Kubernetes: Secrets resource
- Cloud: AWS Secrets Manager, Azure Key Vault, GCP Secret Manager
- Docker Compose:
Key Rotation Schedule
- Recommended: Every 90 days
- Required: Immediately after suspected compromise
- Document: Maintain rotation log with timestamps
Key Compromise Response
- Immediately generate and set new key
- Revoke all active proxy tokens (if applicable)
- Rotate all encrypted credentials
- Audit access logs for suspicious activity
- Document incident and remediation steps
Database Schema
Encryption Version Field
Tables with encrypted data include an encryption_version field:
api_key_store.encryption_version(default: 1)smtp_settings.encryption_version(default: 1)model_gateway_config.encryption_version(default: 1)
Version mapping:
| Version | Algorithm | Notes |
|---|---|---|
| 1 | Fernet (AES-128-CBC + HMAC-SHA256) | Current |
| 2+ | Reserved for future algorithms | e.g., AES-256-GCM |
Future algorithm upgrades will:
- Support reading version 1 data
- Write new data with version 2
- Provide migration scripts for gradual transition
Troubleshooting
"Invalid Fernet key" errors
- Verify
OPENACE_ENCRYPTION_KEYis set - Check key format (should be hex or base64, >= 32 chars)
- Ensure no whitespace or newlines in the value
Decryption failures after rotation
- Confirm you're using the correct key for the data's encryption version
- Check if data was encrypted with a different key
- Restore from backup if key is lost
Proxy tokens invalid after rotation
- Expected behavior: tokens signed with old key
- Users need to restart remote sessions
- No action needed if sessions are short-lived
Related Documentation
- Remote Workspace - Feature overview
- Deployment - Production deployment guide
- Security Policy - Security reporting and policy details