密钥管理
使用 AES-256-GCM 加密、作用域访问和零停机轮换来存储和管理敏感配置值。
sh0 如何加密密钥
所有密钥(标记为敏感的环境变量)在 sh0 的 SQLite 数据库中使用 AES-256-GCM 认证加密进行静态加密,由 ring 加密库提供支持。
加密工作流程:
- 在 sh0 安装期间生成唯一的 256 位加密密钥,存储在服务器的配置目录中。
- 每个密钥值使用唯一的随机数(96 位随机数)加密,确保相同的值产生不同的密文。
- 认证标签(GCM)确保密钥不能在未被检测到的情况下被篡改。
- 密钥仅在启动时注入容器时在内存中解密。
Note
变量值在静态存储时加密,且绝不会写入日志。列表中显示为掩码;拥有 Developer 及以上角色的成员可以在控制台中显示明文,或通过 API 使用
?reveal=true 获取。只读 API 密钥同样可以:请只把密钥和角色交给您愿意托付机密的人员和工具。通过控制台添加密钥
管理密钥最常见的方式是通过控制台的环境变量面板。
- 导航到应用并打开 设置 → 环境变量。
- 点击 添加变量。
- 输入变量名称(例如
DATABASE_URL)。 - 输入值。
- 每个值在存储前都会加密,无需任何开关。
- 点击 保存。
环境变量面板,包含添加变量表单
通过 API:
curl -X POST https://panel.example.com/api/v1/apps/APP_ID/env-vars \
-H "Authorization: Bearer $SH0_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"key": "DATABASE_URL",
"value": "postgres://user:pass@db:5432/mydb"
}' Tip
环境变量的修改会在下一次部署时生效。保存后请重新部署应用。
从 .env 文件批量导入
如果你有现有的 .env 文件,可以一次性导入所有变量。
- 在环境变量面板中,点击 批量导入。
- 粘贴
.env文件的内容或直接上传文件。 - sh0 解析文件并显示所有变量的预览。
- 审阅,将敏感值标记为密钥,然后点击 导入。
批量导入对话框,显示解析后的 .env 文件内容
解析器支持标准 .env 语法:
# Database
DATABASE_URL=postgres://user:pass@db:5432/mydb
REDIS_URL=redis://redis:6379
# API Keys
STRIPE_SECRET_KEY=sk_live_abc123
SENDGRID_API_KEY=SG.xyz789
# App Config
NODE_ENV=production
PORT=3000 Warning
批量导入会覆盖同名的现有变量。导入文件中不存在的变量保持不变。
密钥作用域
密钥可以在两个级别设置作用域,让你控制哪些容器可以访问哪些值。
堆栈级密钥
堆栈级密钥在堆栈中的所有服务间共享。这对于多个服务需要的共享配置(如数据库凭据)非常理想。
堆栈级环境变量,在所有服务间共享
从 堆栈设置 → 环境变量 或通过 API 设置堆栈级密钥:
curl -X POST https://panel.example.com/api/v1/projects/PROJECT_ID/env-vars \
-H "Authorization: Bearer $SH0_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"key": "DATABASE_URL",
"value": "postgres://user:pass@db:5432/mydb"
}'应用级密钥
应用级密钥针对单个服务。它们优先于同名的堆栈级密钥,允许你为个别服务覆盖共享值。
Note
优先级顺序:应用级变量覆盖堆栈级变量。如果两者都定义了
DATABASE_URL,则该特定服务使用应用级的值。密钥轮换
轮换机密意味着更新其值,并重新部署使用它的应用:
- 在控制台中或通过 API 更新该值。
- 重新部署应用:新容器会以新值启动。
- 旧容器会继续处理流量,直到新容器通过健康检查。
- 随后流量切换到新容器。
curl -X PATCH https://panel.example.com/api/v1/apps/APP_ID/env-vars/ENV_ID \
-H "Authorization: Bearer $SH0_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"value": "sk_live_new_key_456"
}'
curl -X POST https://panel.example.com/api/v1/apps/APP_ID/deployments \
-H "Authorization: Bearer $SH0_TOKEN" \
-H "Content-Type: application/json" \
-d '{}' 密钥轮换,蓝绿部署进行中
Tip
对于数据库密码轮换,先在数据库中更新密码,然后在 sh0 中更新密钥并重新部署。这个顺序可以防止过渡期间的连接失败。
在容器中访问密钥
密钥作为标准环境变量注入容器。你的应用访问它们的方式与访问任何环境变量相同:
const dbUrl = process.env.DATABASE_URL;
const stripeKey = process.env.STRIPE_SECRET_KEY;import os
db_url = os.environ["DATABASE_URL"]
stripe_key = os.environ["STRIPE_SECRET_KEY"]let db_url = std::env::var("DATABASE_URL")?;
let stripe_key = std::env::var("STRIPE_SECRET_KEY")?;密钥在容器启动时设置,并在容器的整个生命周期内可用。它们不会写入容器内的磁盘。
Danger
永远不要记录环境变量或将其包含在错误报告中。虽然 sh0 在静态和传输中保护密钥,但你的应用代码也必须负责任地处理它们。