# 光湖自部署密钥管理页 · secrets-vault > 主权: TCS-0002∞ · ICE-GL∞ · 国作登字-2026-A-00037559 > 守护: 铸渊 · ICE-GL-ZY001 > 棒次: PR-5 (baton-005) > 模板版本: 0.1.0 ## 这是什么 光湖国内域名机 (`ZY-SVR-CN01` / 广州 2C2G / `guanghulab.com`) 上的"自部署密钥管理页"。 **1 步保存立即生效** —— vs GitHub Secrets 的 5 步 round-trip (登录 → 仓库 Settings → Secrets → New → Save → 再去 Actions → Re-run)。 为什么独立建: | 场景 | GitHub Secrets | 自部署 vault | |---|---|---| | AutoDL 重开机后端口漂移 | 5 步, 还要重跑工作流 | 1 步保存, 立即生效 | | 主密钥可见性 | GitHub 看得见 | 主密钥落 `.master`, 仅本机 root 可读 | | 域名机离线 | 没法改 | 没法改 (但本来就是给这台机器用的) | | 谁能进 | 全 repo collaborator | 仅 SSH 隧道 + basic-auth | ## 三层安全 1. **网络层** —— Express 监听 `127.0.0.1:8080`, 永不 bind 公网 2. **nginx 层** —— `/admin/` location `allow 127.0.0.1; deny all;` + basic-auth 3. **加密层** —— `vault.enc` 走 AES-256-GCM, 主密钥 `.master` chmod 600 冰朔访问方式: ```bash # 本地起隧道 ssh -L 8080:127.0.0.1:80 ubuntu@<2C2G_HOST> # 浏览器访问 open http://localhost:8080/admin/ # 输入 basic-auth 用户名密码 (来自 _logs/vault-credentials-FIRST-BOOT.txt, 抄完删) ``` ## 路由 ### 公开 (走 nginx /admin/ + basic-auth) | 方法 | 路径 | 作用 | |---|---|---| | GET | `/admin/__healthz` | 健康检查 | | GET | `/admin/` | 前端 SPA | | GET | `/admin/secrets/` | 列出已配置 key (遮罩值) | | GET | `/admin/secrets/manifest` | 按工作流分组的元数据 | | POST | `/admin/secrets/:key` | 写入 `{value}` | | DELETE | `/admin/secrets/:key` | 删除 | | POST | `/admin/secrets/autodl/save_and_refresh` | AutoDL 一键 (vault 落 + 探活 + 写 endpoint + pm2 reload) | ### 内部 (本机 only · 神笔马良用) | 方法 | 路径 | 作用 | |---|---|---| | GET | `/internal/fetch/:key` | 拉明文 (仅 127.0.0.1) | ## 文件布局 ``` server/secrets-vault/ ├── server.js Express 入口 ├── ecosystem.config.js pm2 (max_memory_restart=128M) ├── package.json ├── lib/ │ ├── vault.js AES-256-GCM 加解密 + 主密钥 │ ├── manifest.js 按 secrets-manifest.json 分组 │ └── refresh-inference.js AutoDL 探活+写 inference-endpoint.json ├── routes/ │ ├── secrets.js /admin/secrets/* 路由 │ └── internal.js /internal/fetch/* (本机 only) └── tests/ ├── vault.test.js 加解密 + 主密钥 + 篡改检测 └── routes.test.js 路由烟测 ``` ## 落盘文件 | 文件 | 路径 | 权限 | 说明 | |---|---|---|---| | 主密钥 | `/data/guanghulab/secrets-vault/.master` | 600 | 32 字节随机, 首次启动生成 | | 加密库 | `/data/guanghulab/secrets-vault/vault.enc` | 600 | AES-256-GCM 加密的 JSON | | basic-auth | `/etc/nginx/.htpasswd_admin` | 644 | bootstrap 写入 | | 首启凭据 | `/data/guanghulab/_logs/vault-credentials-FIRST-BOOT.txt` | 600 | 首启随机 user/pass, **抄完删** | ## 跑测试 ```bash cd server/secrets-vault npm install npm test ``` 预期输出: ``` ✔ loadOrCreateMaster 首次随机生成 32 字节 + chmod 600 ✔ loadOrCreateMaster 重启加载已有 .master, 不重建 ✔ set/get/delete/list — 加密落盘往返一致 ✔ 加密文件不含明文 (基础保密线) ✔ 换主密钥后解密失败 (cc-004 防换机器忘 .master) ✔ vault.enc 篡改 (改 ciphertext) 应被 GCM tag 检测 ✔ set 拒绝非字符串 value ✔ maskValue 长短分级遮罩 ✔ GET /admin/__healthz 返回 vault 状态 ✔ GET /admin/secrets/manifest 按 workflow 分组 ✔ POST /admin/secrets/:key — 白名单外拒绝 ✔ POST /admin/secrets/:key — key 名格式错拒绝 ✔ POST /admin/secrets/:key — 强校验长度不够拒绝 ✔ POST + GET + DELETE 完整往返 (值不返回明文, 只遮罩) ✔ /internal/fetch/:key 只允许本机 (loopback 通) ✔ /internal/fetch/:key — 未配置 key 返回 404 ✔ autodl/save_and_refresh — host/port 缺失 → 400 ✔ autodl/save_and_refresh — 探活失败仍然把 vault 落了 (vault_saved=true) ``` ## 灾备 / 换机 主密钥 `.master` **不上 git, 不上 COS, 不传冰朔**。换机器流程: ```bash # 老机器 sudo cat /data/guanghulab/secrets-vault/.master | base64 > /tmp/master.b64 # 安全通道传到新机器 (例如 ssh 直传) # 新机器 sudo bash -c 'base64 -d /tmp/master.b64 > /data/guanghulab/secrets-vault/.master && chmod 600 /data/guanghulab/secrets-vault/.master' # 然后再 rsync vault.enc 过来 ``` 如果 `.master` 真的丢了,没办法恢复 — 重新生成 + 让冰朔在新页面里逐项重填一次 (大约 10 项, 5 分钟内搞定)。这是 cc-004 系统自管的代价:宁愿忘了重填,也不让密钥本身被外部托管。