密钥管理
Open-ACE 的加密密钥派生、轮换和安全最佳实践。
概述
Open-ACE 使用 Fernet 对称加密保护静态敏感数据:
- 远程工作区的 API Key(
api_key_store表) - SMTP 密码(
smtp_settings表) - Model Gateway API Key(
model_gateway_config表)
Proxy Token 使用 HMAC-SHA256 签名(非 Fernet)进行认证。
密钥派生
加密密钥从 OPENACE_ENCRYPTION_KEY 环境变量派生:
OPENACE_ENCRYPTION_KEY (环境变量,>= 32 字符)
│
│ SHA-256 哈希
▼
32 字节密钥
│
│ base64.urlsafe_b64encode
▼
Fernet 密钥 (44 字符)
│
├────────────────┬────────────────┐
▼ ▼ ▼
API Key SMTP 密码 Model Gateway
加密 加密 加密
│
│ 同一密钥用于 HMAC-SHA256
▼
Proxy Token
签名
密钥派生代码:
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)
密钥共享影响面
同一密钥用于:
- API Key 加密 -
api_key_store.encrypted_key - SMTP 密码加密 -
smtp_settings.encrypted_password - Model Gateway 加密 -
model_gateway_config.encrypted_api_key - Proxy Token 签名 - 远程代理认证的 HMAC-SHA256 签名
影响:
- 密钥轮换需要重新加密三个数据存储
- 使用旧密钥签名的活跃 Proxy Token 轮换后验证失败
- 密钥泄露影响四个安全域
密钥轮换
当前限制
- 单密钥 Fernet:不支持 MultiFernet 多密钥解密
- 轮换需停机:无法在不重启服务的情况下轮换密钥
- 手动流程:无自动化密钥轮换机制
轮换方法
方法 A:停机轮换(推荐用于小规模部署)
前提条件:
- 数据库备份能力
- 计划维护窗口
- 环境变量的 root 访问权限
步骤:
-
备份数据库
# PostgreSQLpg_dump openace > openace_backup_$(date +%Y%m%d).sql# SQLitecp app.db app_backup_$(date +%Y%m%d).db -
导出加密数据
python scripts/export_encrypted_data.py --output encrypted_data_backup.json导出内容:
api_key_store.encrypted_key→ 明文 API Keysmtp_settings.encrypted_password→ 明文 SMTP 密码model_gateway_config.encrypted_api_key→ 明文 Gateway Key
-
生成并设置新密钥
# 生成新的 32 字节密钥NEW_KEY=$(openssl rand -hex 32)echo "新密钥: $NEW_KEY"# 更新环境变量# Docker Compose: 编辑 .env 文件# Kubernetes: 更新 Secret# Systemd: 编辑 /etc/open-ace/environment -
重启服务
# Docker Composedocker-compose restart# Systemdsudo systemctl restart open-ace -
重加密并导入数据
python scripts/import_encrypted_data.py --input encrypted_data_backup.json -
验证功能
- 测试 API Key 存储和读取
- 测试 SMTP 邮件发送
- 测试 Model Gateway 调用
- 注意 :现有 Proxy Token 将失效(用户需重启会话)
-
安全清理
# 验证后删除明文备份rm encrypted_data_backup.json# 可选:归档加密数据库备份gzip openace_backup_*.sql
方法 B:MultiFernet 支持(未来增强)
需求:
- 代码修改支持
MultiFernet - 环境变量格式:
KEY1;KEY2(主密钥;备用密钥) - 零停机轮换能力
需要实现:
- 修改
_get_encryption_key()返回密钥列表 - 使用
MultiFernet([key1, key2])解密 - 新加密使用主密钥
- 渐进式迁移路径
安全最佳实践
密钥生成
# 生成强随机密钥(256 位 = 32 字节 = 64 个十六进制字符)
openssl rand -hex 32
密钥存储
- 永不提交到源代码管理
- 使用环境变量或密钥管理:
- Docker Compose:
.env文件(添加到.gitignore) - Kubernetes: Secret 资源
- 云平台: AWS Secrets Manager、Azure Key Vault、GCP Secret Manager
- Docker Compose:
密钥轮换周期
- 推荐:每 90 天
- 必须:疑似泄露后立即轮 换
- 文档:维护带时间戳的轮换日志
密钥泄露响应
- 立即生成并设置新密钥
- 撤销所有活跃 Proxy Token(如适用)
- 轮换所有加密凭据
- 审计访问日志查找可疑活动
- 记录事件和修复步骤
数据库 Schema
加密版本字段
包含加密数据的表都有 encryption_version 字段:
api_key_store.encryption_version(默认:1)smtp_settings.encryption_version(默认:1)model_gateway_config.encryption_version(默认:1)
版本映射:
| 版本 | 算法 | 说明 |
|---|---|---|
| 1 | Fernet (AES-128-CBC + HMAC-SHA256) | 当前 |
| 2+ | 保留用于未来算法 | 如 AES-256-GCM |
未来算法升级将:
- 支持读取版本 1 数据
- 新数据使用版本 2 写入
- 提供渐进式迁移脚本
故障排查
"Invalid Fernet key" 错误
- 验证
OPENACE_ENCRYPTION_KEY已设置 - 检查密钥格式(应为十六进制或 base64,>= 32 字符)
- 确保值中无空格或换行
轮换后解密失败
- 确认使用正确的密钥匹配数据的加密版本
- 检查数据是否用不同密钥加密
- 若密钥丢失则从备份恢复
轮换后 Proxy Token 无效
- 预期行为:使用旧密钥签名的 Token
- 用户需重启远程会话
- 会话短暂时无需操作
相关文档
- 远程工作区 - 功能概述
- 部署 - 生产部署指南
- Security Policy - 安全报告与策略说明