密钥管理规范¶
最后更新:2026-05-16(TFRM-118:VictoriaMetrics 拆除,remote_write 鉴权改为 OTLP Bearer)
本文档描述 TFRSManager 生产环境的密钥管理体系,包括 Infisical 平台、Machine Identity 认证、以及计费链路 OTLP Receiver 鉴权。
一、Infisical 密钥管理平台¶
1.1 部署信息¶
| 项 | 值 |
|---|---|
| 访问地址 | https://secret.turingfocus.cn |
| 部署方式 | 自托管 Docker Compose(/opt/infisical-infra/) |
| 容器 | infisical + postgres:16-alpine + redis:7-alpine |
| 备份 | crontab 每日 03:00 执行 PostgreSQL dump,保留 30 天 |
1.2 项目与环境¶
Infisical 中按以下项目组织密钥:
| 项目 | 说明 | 环境 |
|---|---|---|
tfrs-manager |
后端服务配置 | Development / Staging / Production |
tfrs-portals |
前端配置 | Development / Staging / Production |
tfrs-k8s-platform |
K8s 集群配置 | Production |
tfrs-shared |
共享配置 | Production |
infisical-infra |
Infisical 自身配置 | Production |
1.3 tfrs-manager 密钥目录结构¶
/ → 顶层通用配置(GIN_MODE, LOG_LEVEL 等)
├── auth/ → JWT_SECRET
├── cos/ → 腾讯云 COS 凭证
├── database/ → PostgreSQL 连接信息
├── feishu/ → 飞书集成
├── k8s/ → K8s 集群配置
├── otlp/ → OTLP 计费链路 Bearer token(按 {cluster_id} 分目录,TFRM-119)
├── observability/ → OpenTelemetry 配置
├── payment/ → 支付宝/微信支付凭证
├── redis/ → Redis 连接信息
├── sms/ → 腾讯云短信
└── smtp/ → 邮件服务
二、Machine Identity(服务端认证)¶
2.1 概念¶
Machine Identity 是 Infisical 提供的非人类身份认证机制,用于让服务器/CI 以编程方式访问密钥。
2.2 当前 Identity¶
| 名称 | ID | 认证方式 | 项目权限 | 用途 |
|---|---|---|---|---|
cvm-prod-tfrs-manager |
756c6d22-228c-4145-bed6-ec6473ccd1c4 |
Universal Auth | tfrs-manager (Viewer) | prod 服务器运行时 |
2.3 凭证存放¶
Machine Identity 的 Client ID / Client Secret 存放在 .env.prod 中:
INFISICAL_CLIENT_ID=634f5fde-...
INFISICAL_CLIENT_SECRET=86ee80a1...
INFISICAL_PROJECT_ID=8a9fd5ba-...
INFISICAL_ENVIRONMENT=prod
.env.prod 由 CNB CI/CD 流水线从密钥仓库文件 tfrsmanager_env.prod.yml 生成,通过 SSH 传输到服务器 /opt/tfrs/.env.prod。
2.4 API 调用方式¶
由于 prod 服务器无法直接从 GitHub 下载 Infisical CLI(网络限制),脚本通过 HTTP API 直接调用自托管 Infisical:
# Step 1: 获取 Access Token
curl -sf https://secret.turingfocus.cn/api/v1/auth/universal-auth/login \
-X POST -H "Content-Type: application/json" \
-d '{"clientId":"...","clientSecret":"..."}'
# 返回 { "accessToken": "eyJ..." }
# Step 2: 读取密钥(示例:镜像仓库密码)
curl -sf https://secret.turingfocus.cn/api/v3/secrets/raw/CNB_REGISTRY_PASSWORD \
-H "Authorization: Bearer <token>" \
-G --data-urlencode "workspaceId=..." \
--data-urlencode "environment=prod" \
--data-urlencode "secretPath=/registry/"
# 返回 { "secret": { "secretValue": "..." } }
2.5 创建新 Machine Identity¶
如需为其他服务器或 CI 环境创建新的 Machine Identity:
- 登录
https://secret.turingfocus.cn - Organization → Access Control → Machine Identities → Create
- 命名规则:
{环境}-{服务器}-{项目}(如cvm-staging-tfrs-manager) - 添加 Universal Auth 认证方式
- 在项目中授权,角色设为
Viewer(只读,最小权限原则) - 创建 Client Secret 并妥善保存(创建后仅显示一次)
三、OTLP 计费链路鉴权(TFRM-119)¶
VictoriaMetrics 已于 TFRM-118 拆除, 原 Nginx Basic Auth +
REMOTE_WRITE_PASSWORD鉴权随之移除。计费 of-record 链路改由 OTLP Receiver 承载,鉴权方式由 Basic Auth 改为 Bearer Token。
3.1 架构¶
K8s 集群内 ns 共享 StatefulSet OTel Collector 经公网 OTLP/HTTP 单一 /v1/logs
推送计费事件日志到管理平面 OTLP Receiver,使用 Bearer Token 鉴权。
ns 共享 StatefulSet OTel Collector
│ OTLP/HTTP /v1/logs (HTTPS + Authorization: Bearer <token>)
▼
┌──────────────────────────────────────────────────────┐
│ Nginx (metrics{,-staging,-beta}.turingfocus.cn:443) │
│ └─ proxy_pass → 127.0.0.1:4318 (Receiver 仅监听本地) │
└─────────────────┬────────────────────────────────────┘
│
┌───────▼────────────────────────────────┐
│ OTLP Receiver :4318 (本地) │
│ sha256(token) 校验 + cluster_id 强制重写 │
│ → 中央 TimescaleDB(of-record) │
└─────────────────────────────────────────┘
3.2 Token 下发与轮换¶
- Token 存于 Infisical
/otlp/{cluster_id}/PRIMARY_TOKEN(+SECONDARY_TOKEN用于零停机轮换) - Manager Admin API 触发 rotate(写 PRIMARY/SECONDARY),ESO 同步到 K8s Secret
tfrs-otlp-bearer - Receiver 侧对 token 做 sha256 比对,并按 cluster 强制重写
cluster_id,防伪造 - 契约与轮换细节详见 TFRM-119 与
docs/specs/otlp-receiver-contract.md
四、.env.prod 密钥分类¶
.env.prod 中的环境变量按安全级别分类:
高敏感(泄露可直接造成资金损失)¶
| 变量 | 说明 |
|---|---|
ALIPAY_APP_PRIVATE_KEY |
支付宝应用私钥 |
WECHAT_MCH_PRIVATE_KEY |
微信商户私钥 |
WECHAT_APIV3_KEY |
微信 APIv3 密钥 |
SECRET_ENCRYPTION_KEY |
AES-256-GCM 数据加密密钥 |
JWT_SECRET |
JWT 签名密钥 |
ADMIN_JWT_SECRET |
Admin JWT 签名密钥 |
OIDC_SIGNING_KEY |
管理域 OIDC ID token 的 RS256 私钥(base64 编码 PEM);泄露可伪造 OIDC 身份 |
OIDC_CLIENT_SECRET |
oauth2-proxy 的 OIDC client_secret(亦用于派生 auth code 加密密钥) |
ACCESS_TOKEN_SIGNING_KEY[_SECONDARY] |
连接数据面短 JWT 的 RS256 私钥(PRIMARY [+ 可选 SECONDARY 轮换槽],base64 PEM);泄露可伪造短 JWT。独立于上方 OIDC keyset。零中断轮换三步流见 08-access-token-signing-key-rotation.md |
中敏感(泄露可导致数据访问)¶
| 变量 | 说明 |
|---|---|
DB_PASSWORD |
PostgreSQL 密码 |
REDIS_PASSWORD |
Redis 密码 |
INFISICAL_CLIENT_SECRET |
Infisical Machine Identity 密钥 |
COS_SECRET_KEY |
腾讯云对象存储密钥 |
SMS_TENCENT_SECRET_KEY |
腾讯云短信密钥 |
低敏感(配置信息)¶
| 变量 | 说明 |
|---|---|
GIN_MODE / LOG_LEVEL |
运行模式 |
REGISTRY / REPO / IMAGE_TAG |
镜像信息 |
DB_PORT / DB_NAME / DB_DRIVER |
数据库连接参数 |
OIDC_ENABLED / OIDC_ISSUER_URL / OIDC_CLIENT_ID / OIDC_REDIRECT_URIS / OIDC_SIGNING_KEY_ID |
管理域 OIDC 非机密配置 |
管理域 OIDC Provider 凭据生成(TFRM-143): - 签名私钥:
openssl genrsa 2048 | base64 -w0→ 写入 InfisicalOIDC_SIGNING_KEY(≥2048 位;admin-service 启动期解码校验,PKCS#1/#8 均可)。轮换:换OIDC_SIGNING_KEY并改OIDC_SIGNING_KEY_ID以更新 JWKSkid。 -OIDC_CLIENT_SECRET:openssl rand -hex 32(≥16 字符;同时用于派生 auth code 的 AES 加密密钥,须稳定)。与 Operator 侧 oauth2-proxy 的client_secret(存为 K8s Secret)保持一致。 -OIDC_REDIRECT_URIS:逗号分隔,填各集群的 oauth2-proxy callback(auth host,非 jaeger host),如https://auth.enaic.turingfocus.cn/oauth2/callback。 -OIDC_CLIENT_SECRET须与被纳管集群内 K8s Secrettfr-mgmt-system/oauth2-proxy-client-secret的client-secret同值(Operator 经clientSecretRef读取)。 - 全部仅当OIDC_ENABLED=true时校验生效;暴露面与 Nginx 直连见 02-network.md §2.2。完整端到端落地清单(含 K8s Secret、TFRCluster CR、CLB auth 子域、Operator 最低版本 0.5.1-dev10)见 02-network.md §2.7。
密钥流转链路¶
Infisical (唯一真实来源)
│
├─→ CNB CI/CD 密钥仓库 (tfrsmanager_env.prod.yml)
│ └─→ scripts/env-keys.txt 白名单过滤
│ └─→ .env.prod → 传输到 /opt/tfrs/
│
└─→ /otlp/{cluster_id}/PRIMARY_TOKEN (集群初始化 / Admin rotate 写入)
└─→ ESO 同步 → K8s Secret tfrs-otlp-bearer
五、安全检查清单¶
定期检查(建议每月):
- [ ] SSL 证书是否即将过期(特别是手动上传的证书)
- [ ] Infisical Machine Identity 是否有异常登录(Access Control → 查看 Last Logged In)
- [ ] OTLP Receiver 未对外暴露(
curl http://<prod_ip>:4318应无响应,仅经 metrics 子域 Nginx 反代) - [ ] 所有业务端口仅绑定 127.0.0.1(
ss -tlnp | grep -v 127.0.0.1应仅有 80/443) - [ ] Infisical 备份正常执行(
/opt/infisical-infra/backup/backup.log)