Files

145 lines
5.0 KiB
Markdown
Raw Permalink Normal View History

# 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 +1
- `ssh_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 预览
- ❌ 推送结果邮件报告