5.0 KiB
5.0 KiB
Nexus 设计标准
最后更新: 2026-05-22
适用范围: 所有功能迭代、代码审查、安全审计
1. 安全模型:信任管理员 + 防注入/XSS
核心理念: 认证管理员是可信用户,但必须防御注入攻击和 XSS。
运维管理后台的认证管理员即为可信用户,应用层不对操作内容做业务限制。 但必须防御技术层面的攻击向量(命令注入、路径注入、XSS)。
依据:
- 使用者均为经过认证的运维管理员
- 绕过应用层限制的门槛极低(SSH 直连即可)
- 应用层业务限制增加维护成本,假安全感大于实际安全收益
- 但技术层面注入攻击是真实风险,必须防御
实施要求:
- 所有 API 端点必须校验 JWT 令牌(
Depends(get_current_admin)) - WebSocket 连接必须通过 JWT 查询参数认证(ADR-011)
- Agent 通信使用 X-API-Key 认证
- Shell 命令参数必须
shlex.quote()防注入 - 前端禁止在模板字面量中直接输出用户内容(防 XSS)
- 数据库凭据加密存储(Fernet + AES-CBC)
不做的事:
- ❌ 不在应用层限制上传文件类型
- ❌ 不在应用层限制文件写入目标路径
- ❌ 不在应用层限制执行命令的业务内容
- ❌ 不做 RBAC 权限体系(保持"鉴权即信任")
- ❌ 不做会话录像(asciicast)
2. 配置存储
| 层 | 存储 | 用途 |
|---|---|---|
| 热层 | Redis | 心跳、缓存、告警去重、Pub/Sub (TTL 管理) |
| 持久层 | MySQL | 服务器、日志、设置、审计 |
| 文件 | .env |
启动必需: DB连接、SECRET_KEY、API_KEY |
配置加载优先级: .env (启动) → MySQL settings 表 (动态覆盖)
原则: 可热配项走 MySQL settings(load_settings_from_db 启动时加载),不可热配项走 .env。
不可改配置 (.env only):
- SECRET_KEY, API_KEY, ENCRYPTION_KEY, DATABASE_URL
可改配置 (MySQL settings 可覆盖):
- system_name/title, pool_size/overflow, redis_url, 告警阈值, Telegram 配置
3. 性能基线
| 指标 | 值 |
|---|---|
| API 安全并发 | ≤50 |
| P50 延迟 | <60ms |
| P95 延迟 | <300ms |
| 最大文件上传 | 500MB |
| sync_logs 保留 | 30 天 |
| 心跳批量刷到 MySQL | 每 10min |
| SSH 连接池 | 最大 100 连接,空闲 5min 关闭 |
4. 代码规范
Python 后端
- 所有 API 路由使用 Pydantic 模型验证请求体(
server/api/schemas.py) - 所有 API 路由使用 JWT 认证(
Depends(get_current_admin)) - Shell 命令参数必须
shlex.quote()防注入 - DB session 由 DbSessionMiddleware 自动管理,通过
request.state.db共享 - Service 层通过依赖注入获取 Repository 实例(
server/api/dependencies.py) - 加密使用 Fernet (Python) + AES-CBC (PHP 兼容),密钥统一从 API_KEY/SECRET_KEY 派生
- Redis 操作使用
redis.asyncio,连接池为BlockingConnectionPool
前端 (Tailwind + Alpine.js)
- 所有页面引入
api.js共享模块(JWT 自动刷新、apiFetch 封装) - JWT 令牌存储在 localStorage,自动刷新(2分钟内到期触发)
- 所有 API 调用使用
apiFetch()自动附带 Authorization 头 - CORS 由
NEXUS_CORS_ORIGINS环境变量配置 - 侧边栏和导航在所有页面保持一致
5. 测试标准
收尾前必修: 部署完成后必须用浏览器直接访问页面验证核心流程。curl / API 测试不能替代浏览器验收。
检查清单:
- 登录 → 仪表盘正常加载(含 WebSocket 实时更新)
- 核心页面可交互(点击、表单提交有响应)
- 浏览器 Console 无报错
- 浏览器 Network 面板无 404/500
- JWT 令牌自动刷新正常
6. 架构模式
后台任务
| 任务 | 间隔 | 文件 |
|---|---|---|
| heartbeat_flush | 10min | server/background/heartbeat_flush.py |
| self_monitor | 30s | server/background/self_monitor.py |
| schedule_runner | 60s | server/background/schedule_runner.py |
| retry_runner | 5min | server/background/retry_runner.py |
| asyncssh_cleanup | 60s | server/infrastructure/ssh/asyncssh_pool.py |
所有后台任务使用 asyncio.create_task() 在 lifespan 中启动,支持优雅关闭。
SSH 连接池
引用计数模式 (ADR-004):
ssh_pool.acquire(server)→ 获取/创建连接,ref_count +1ssh_pool.release(server_id)→ ref_count -1,空闲连接保留复用- 清理循环每 60s 扫描,空闲 >5min 的连接自动关闭
WebSocket 两层架构 (ADR-010)
- Layer 1: 内存
ConnectionManager管理本 worker 的 WebSocket 连接 - Layer 2: Redis Pub/Sub
nexus:alerts频道中继跨 worker 消息 - Ping/pong 心跳 30s,僵尸连接 60s 清理
7. 不做清单(永久)
- ❌ RBAC 权限体系 (保持"鉴权即信任")
- ❌ 会话录像 asciicast (不需要)
- ❌ 移动端适配 (运维不会用手机管理服务器)
- ❌ MQTT 协议 (HTTP+Redis 足够 2000 台)
- ❌ 文件差异比较
- ❌ 图片/PDF 预览
- ❌ 推送结果邮件报告