12 KiB
VPS-Commander 双通道架构与安全整改——送审交接文档
文档版本: 2026-10-02 / Review Handoff v1
项目: VPS-Commander v2.0
用途: 提交外部审核,审核通过后作为生产上线前置依据
1. 本次交接目标
本次开发针对双通道架构重构及此前审核专家 A/B 提出的安全、并发、权限、会话和文件操作问题进行集中整改。
本文件只描述当前代码实际完成状态,不把尚未部署到生产的代码描述为“已上线”。
当前原则:
- 生产 Hub / Agent 在本轮整改过程中没有重启。
- 所有新增能力先在代码与测试环境完成验证。
- 生产切换采用分阶段、可回滚方式。
- 审核通过后,才进入生产上线阶段。
2. 当前生产保护状态
本轮整改期间确认生产进程仍保持运行,未执行 Hub/Agent 重启:
- Hub:
/opt/vps-commander/vps-commander-hub - Agent:
/opt/vps-commander/vps-commander-agent
因此,本次代码整改本身没有主动造成生产节点失联。
注意: 当前生产进程运行的是现有部署版本,不等同于本工作树代码已经上线。
3. 审核问题整改总表
| 审核问题 | 当前状态 | 说明 |
|---|---|---|
| Security Snapshot 统一门禁 | PASS | API/MCP 等执行路径使用统一安全模式判断 |
| MCP 绕过安全门禁 | PASS | exec/read/write/edit/mcp 路径已接入门禁;Agent-MCP 直通已补齐 |
| 未知设备继承 GlobalRisk | PASS | 未注册/未知设备 fail-closed 为 unknown |
| Security Policy Version 回退 | PASS | Snapshot Publish 拒绝版本回退 |
| Admin 安全策略权限 | PASS | 安全策略修改要求独立 Admin Token |
| edit_block 原子写入 | PASS | 临时文件、fsync、原子 rename、权限保留 |
| edit_block 并发/生成冲突 | PASS* | 已增加提交前重新读取校验及进程内串行保护;可选 expected hash |
| Session Owner | PARTIAL / HARDENING | 当前 owner 绑定认证主体指纹;若所有调用者共享同一全局 token,无法天然区分操作者 |
| Session TTL | PASS | 30 分钟硬 TTL + 10 分钟 idle TTL,访问会刷新 LastAccess |
| Session 资源上限 | PASS | 单 Manager 会话/缓冲总量有限制 |
| WebSocket 并发写 | PASS | Node 写操作通过 WriteMu 串行化 |
| Agent 业务错误导致断链 | PASS | 业务错误返回错误消息,不主动关闭 WebSocket |
| Agent 能力声明 | PASS | Modern Agent 按 capability 校验;旧 Agent 保持兼容 |
| 设备级凭证 | IMPLEMENTED / NOT DEPLOYED | SQLite 已支持 per-device credential hash;未切换生产认证 |
| URL Query Token | PASS | Auth 不再接受 ?token/?key/?api_key |
| 审计记录 | PASS | 关键安全拒绝、MCP 调用等路径具备审计 |
| 审计敏感信息治理 | HARDENING | 仍建议上线前进一步检查 command/error 的敏感字段脱敏 |
| 全局 exec/search 资源配额 | HARDENING | 已有 session/ring buffer 限制,但仍可进一步增加全局并发/搜索资源配额 |
| 生产部署验证 | PENDING | 必须在审核通过后分阶段执行 |
PASS*表示代码层已完成并通过测试;最终生产审核仍应覆盖真实文件系统与并发场景。
4. 已完成的核心安全机制
4.1 Security Snapshot
Hub 启动时加载安全策略 Snapshot。策略版本保存在 SQLite 中。
安全模式包括:
lowmediumhighinherit
工具动作通过固定 Registry 映射到风险等级,避免调用方自行声明风险等级。
4.2 Fail-Closed
对于未知、未注册或不在线的远程设备,不再默认继承 GlobalRisk。
此类设备的有效安全模式为 unknown,高风险执行因此被拒绝。
4.3 MCP 安全门禁
MCP 不再被视为绕过 Hub Security Snapshot 的旁路。
目前已经覆盖:
exec_commandread_filewrite_fileedit_blockcall_agent_mcplist_agent_mcp
并增加了对应单元测试。
4.4 Admin Token
安全策略修改接口要求独立 Admin Token:
X-Admin-Token
启动时优先读取:
VPS_COMMANDER_ADMIN_TOKEN
同时保留旧 Web Password 作为兼容 fallback,方便后续迁移。
4.5 URL Token 禁用
API Auth 不再从 URL Query 中接受:
tokenkeyapi_key
统一使用 Authorization Bearer 认证路径。
5. 文件修改安全
edit_block 当前实现包含:
- 唯一匹配检查
- 初始内容 SHA-256 generation
- 提交前重新读取
- generation/hash 冲突检测
- 进程内编辑串行化
- 同目录临时文件
- 写入后 fsync
- atomic rename
- 保留原文件权限
- 目录同步
目标是避免“读取后文件被其他操作修改,随后旧内容覆盖新内容”的典型 lost-update 问题。
6. Session 安全
当前 Session 具备:
- Owner
- 30 分钟 hard TTL
- 10 分钟 idle TTL
- 访问刷新
LastAccess - 最大输入 64 KiB
- 环形输出缓冲
- Manager 总缓冲/会话上限
- terminate / kill 按 Session 控制
Owner 校验失败或 Session 过期时,不允许继续操作。
已知边界
当前 Owner 来源仍然是 API 认证主体的 token fingerprint。在所有调用者共用同一个 API Token 的部署中,这个 fingerprint 无法区分不同人工操作者。
因此上线前如果要求强操作者隔离,应继续引入明确的 principal/operator identity。
7. WebSocket 稳定性
Agent 与 Hub 通信增加了写锁,避免多个 goroutine 同时向同一 WebSocket 写入。
Agent 业务请求错误不再直接导致 WebSocket 连接被关闭。
设备断线后:
- Node 保留在 Manager
- 状态变为 offline
- SQLite 保留设备记录
- pending request 收到 disconnect error
- 自动重连可以恢复 online 状态
8. 设备级凭证迁移
这是本轮新增的重要安全能力。
SQLite 新增:
device_credentials
数据库只保存 token 的 SHA-256 hash,不保存明文 token。
当前 WebSocket 握手逻辑:
设备存在独立 credential
|
+--> 使用该设备 credential 校验
设备尚未配置 credential
|
+--> 暂时兼容 Cluster Secret
这样可以支持逐节点迁移,而不是一次性切换所有 Agent。
当前状态
代码已经实现,但尚未在生产逐节点启用。
这是有意保留的上线门禁,避免在没有审核和迁移计划的情况下直接造成 Agent 全部掉线。
9. 测试与验证结果
当前工作树已经完成:
go test ./... PASS
go test -race ./... PASS
go build ./cmd/hub PASS
go build ./cmd/agent PASS
go build ./cmd/mcp-stdio PASS
git diff --check PASS
并增加/验证了:
- MCP Security Snapshot 测试
- 未知设备 fail-closed 测试
- MCP Agent-MCP gate 测试
- MCP list-agent gate 测试
- Session idle authorization 测试
- Device credential hash/rotation 测试
- Cluster lifecycle acceptance 测试
- Race detector
10. 审核者重点检查项
建议审核者重点确认以下问题,而不是重复审查已经验证的普通功能:
A. 设备身份
确认:
- device name 不能单独成为可信身份
- 已配置 credential 的设备必须使用对应 credential
- credential 不能跨设备复用
- revoked device 不能重新建立连接
- 迁移期间 legacy Cluster Secret 的边界是否可接受
B. Session 操作者身份
确认:
- Owner 是否满足当前部署需要
- 是否需要进一步引入 operator/principal ID
- kill/terminate/input/output 是否全部经过 Owner 检查
C. 审计
确认:
- command/error 是否可能写入密码、Token、Cookie、Authorization 等敏感内容
- MCP 参数是否需要脱敏
- 安全拒绝事件是否足够追踪
D. 资源控制
确认:
- exec 并发数
- search 并发数
- 单文件读取大小
- 单 Agent MCP 请求并发
- WebSocket pending request 数量
是否满足生产部署规模。
E. 上线安全
审核通过后必须采用:
备份 → 单节点 → 健康检查 → 保持旧进程可回滚 → 再逐节点扩散
而不是直接全量替换。
11. 上线前置条件
只有审核者确认以下事项后,才进入生产部署:
- 代码审核通过
- 明确 Session principal 要求
- 明确设备 credential 迁移方案
- 确认现有 Cluster Secret fallback 的过渡期限
- 确认审计脱敏要求
- 确认生产资源配额
- 确认 DB 备份/回滚方案
12. 推荐上线顺序
Stage 0 — Preflight
- 备份
commander.db - 记录当前 Hub/Agent PID、版本、配置
- 记录当前在线节点
- 保留当前生产 binary
Stage 1 — Hub
先部署 Hub 新版本。
验证:
/panel- API Auth
- Security Snapshot
- MCP
- Device state
- WebSocket handshake
Stage 2 — 单 Agent
选择非关键节点进行验证:
- 独立 credential
- online/offline
- exec
- read
- write
- edit_block
- MCP
- reconnect
Stage 3 — 逐节点迁移
每次只迁移一个 Agent,并确认:
connected
→ authenticated
→ heartbeat
→ command
→ MCP
→ disconnect
→ reconnect
全部正常后再处理下一节点。
Stage 4 — Legacy Secret 收口
所有 Agent 完成 credential migration 后,再考虑关闭 shared Cluster Secret fallback。
不能提前关闭。
13. 审核结论请求
请审核者对本文件给出以下三类结论之一:
A — APPROVED FOR DEPLOYMENT
允许进入生产上线阶段。
B — APPROVED WITH CONDITIONS
允许进入上线准备,但指定条件必须在上线前完成。
C — BLOCKED
存在必须修复的阻断性安全/架构问题。
如果选择 B 或 C,请明确指出:
- 问题
- 风险
- 必须修改的代码/配置
- 验证方法
- 是否要求生产变更
14. 当前开发团队声明
截至本文件生成时:
- 本轮整改代码未直接替换生产二进制。
- 生产 Hub/Agent 未因本轮整改重启。
- 自动化测试与 race detector 已通过。
- 设备级 credential 已实现兼容迁移机制,但尚未执行生产迁移。
- 当前目标是先接受独立审核,再执行生产上线。
因此,本文件是“送审版”,不是“生产上线完成报告”。
11. 最终上线收口(2026-10-02)
本轮批准后的生产实施已完成:
- Hub 已部署最终版本并验证启动;共享 Cluster Secret fallback 已关闭。
- 5 个远程 Agent 均已配置独立设备凭证,数据库仅保存 SHA-256 hash。
- 5 个远程 Agent 均已滚动升级到最终 Agent 构建,且重新上线。
wjyhk / N3450 / hwhk / hwsg / m4-live-agent / qnvn六个节点全部 online。- 六个节点均已通过实际执行请求验证控制链路可用。
- Hub 全局安全级别保持
medium;节点级策略保持high,未通过降低全局策略绕过门禁。 - 审计写入增加敏感字段脱敏、换行清理和长度上限。
- Hub 增加 exec 32 并发槽、search 8 并发槽,防止高频资源请求拖垮主控。
- DC 工具池补齐:多文件读取、进程列表、目录创建、文件移动,并接入 Agent/Hub/MCP。
- Agent 仍保留协议兼容能力;设备级凭证优先,未配置设备不会再因为共享 Secret fallback 而自动获得认证。
最终验证:
go test ./... PASS
go test -race ./... PASS
git diff --check PASS
最终生产 Agent SHA-256:
1969456fb09004e4be5b05ba1bf30a0a19a6ed2d41236c2bccd391b2ad6bc362
最终生产 Hub SHA-256:
0978eb06a993909137ee64913c0b09b85835b51a65ef854ddcfbb9cecbd63f6c
Shared Secret 已从 Hub 生产环境移除;现阶段生产认证权威为 per-device credential。