This repository has been archived on 2026-03-28. You can view files and clone it, but cannot push or open issues or pull requests.
old-sysmonitord/docs/ARCHITECTURE.md
2026-03-22 12:16:48 +08:00

267 lines
9.6 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# SysMonitord 开发规范与架构说明书
> **版本**: v1.0.1
> **日期**: 2026-03-22
---
## 1. 设计理念与架构总览
### 1.1 核心架构
SysMonitord 采用 **模块化** 设计,旨在降低耦合度,提升扩展性。系统主要包含以下核心域:
* **Config Domain (配置域)**: 负责配置的拉取、解析、合并与热更新。
* **Monitor Domain (监控域)**: 负责SSH审计、系统基础指标采集。
* **Security Domain (安全域)**: 负责文件完整性扫描与实时防护。
* **Network Domain (通讯域)**: 负责与中心服务器的 WebSocket 长连接通讯。
### 1.2 配置分层设计 (核心规范)
为了解决“配置混乱、前后端字段对不上”以及“官方策略与用户环境耦合”的问题,我们将配置严格划分为两个独立的 JSON 文件:
1. **官方策略**: `official.json`
* **权限**: 只读,由官方/安全团队维护,随版本更新发布。
* **内容**: **仅包含安全基线**核心白名单Hash、强制忽略路径、扫描范围
* **注意**: **不再包含服务器地址**,因为官方策略包应适用于所有客户环境,不应硬编码服务端地址。
* **优先级**: 基线级(定义“什么是合法的”)。
2. **用户配置**: `user.json`
* **权限**: 读写,由用户/运维人员维护,可通过控制台动态下发。
* **内容**: **运行时环境配置**(服务器地址、审计开关、业务自定义白名单、性能阈值)。
* **优先级**: 补充级(在官方基线之上进行扩充或覆盖特定参数)。
---
## 2. 配置文件数据结构定义
> **重要**: 前后端交互必须严格遵循以下数据结构定义。字段命名统一使用 **snake_case** (下划线命名法)。
### 2.1 官方策略结构
**用途**: 定义不可篡改的安全基线,与具体部署环境无关。
```json
{
"version": "1.0.20260322",
"whitelist_files": {
"/bin/ls": ["sha256:abc123def456..."],
"/bin/cat": ["sha256:789xyz..."],
"/usr/bin/top": ["sha256:example123..."]
},
"whitelist_processes": [
"systemd",
"sshd",
"dockerd",
"nginx",
"python3"
],
"ignored_paths": [
"/tmp/",
"/var/log/",
"/proc/",
"/sys/",
"/dev/"
],
"scan_paths": [
"/bin",
"/sbin",
"/usr/bin",
"/usr/sbin",
"/etc/init.d"
]
}
```
**字段说明**:
* `whitelist_files`: `Map<string, []string>`。Key 为绝对路径Value 为允许的 Hash 列表(支持多版本二进制)。
* `ignored_paths`: `[]string`。忽略扫描的目录前缀,用于减少无效报警和性能消耗。
### 2.2 用户配置结构
**用途**: 定义业务个性化需求及连接参数。
```json
{
"version": "user_v1",
"connection": {
"center_server_url": "ws://localhost:8090/api/v1/ws",
"audit_server_url": ""
},
"modules": {
"file_scanner": false,
"file_watcher": true,
"ssh_monitor": true,
"system_monitor": true
},
"supplement_files": {
"/home/admin/app/myapp": ["sha256:user_hash_123..."]
},
"supplement_processes": [
"java_app",
"python_worker",
"my_custom_service"
],
"ignored_paths": [
"/home/admin/logs/",
"/var/cache/myapp/"
],
"monitor_config": {
"ssh_monitor": {
"enabled": true,
"alert_on_root_login": true
},
"system_monitor": {
"collect_interval": "10s",
"collect_network": true,
"collect_process": true,
"process_limit": 10,
"scan_cpu_threshold": 80
}
}
}
```
**字段变更说明**:
* `connection`: 服务器地址**仅**在此处配置,实现环境与策略分离。
* `supplement_processes`: 统一为数组格式 `[]string`,简化白名单管理逻辑。
* `scan_cpu_threshold`: 新增字段允许用户自定义扫描时的CPU上限默认推荐 80。
---
## 3. 通讯协议规范
Agent 与 Server 之间通过 WebSocket 进行全双工通讯。数据格式采用统一的 JSON 信封结构。
### 3.1 消息信封格式
所有下行和上行消息均遵循以下结构:
```go
// 位于 network/types.go
type Packet struct {
Type string `json:"type"` // 消息类型,大写下划线命名
Timestamp int64 `json:"timestamp"` // Unix 时间戳 (秒级)
Code int `json:"code"` // 状态码200=成功, 400=参数错误, 500=服务器错误
Payload interface{} `json:"payload"` // 实际业务数据负载
}
```
### 3.2 上行消息类型定义
| Type 常量 | Payload 结构 | 说明 | 触发频率 |
| :--- | :--- | :--- | :--- |
| `STATUS_UPDATE` | `SystemMetrics` | 系统状态心跳 | 30s/次 |
| `SSH_ALERT` | `SSHLoginEvent` | SSH 登录审计日志 | 事件触发 |
| `REALTIME_FILE_ALERT` | `FileEventPayload` | 实时文件篡改/新增告警 | 事件触发 |
| `SCAN_RESULT` | `FileEventPayload` | 周期性全盘扫描结果 | 周期触发 |
**Payload 结构定义**:
```go
// 1. 系统状态心跳
type SystemMetrics struct {
CpuPercent float64 `json:"cpu_percent"` // 保留2位小数例: 45.23
MemPercent float64 `json:"mem_percent"`
DiskUsage float64 `json:"disk_usage"` // 根分区使用率
LoadAvg1 float64 `json:"load_avg_1"` // 1分钟负载
AgentVersion string `json:"agent_version"` // Agent 当前版本
}
// 2. SSH 审计日志
type SSHLoginEvent struct {
User string `json:"user"` // 登录用户名
IP string `json:"ip"` // 来源IP
Port int `json:"port"` // 来源端口
Status string `json:"status"` // "SUCCESS" 或 "FAILED"
Time int64 `json:"event_time"` // 事件发生时间戳
Method string `json:"method"` // "password" 或 "key"
}
// 3. 文件告警负载
type FileEventPayload struct {
FilePath string `json:"filepath"`
Operation string `json:"operation"` // CREATE, MODIFY, DELETE
Status string `json:"status"` // DETECTED, HASH_MISMATCH
Timestamp int64 `json:"event_time"`
}
```
### 3.3 下行消息类型定义
| Type 常量 | Payload 结构 | 说明 |
| :--- | :--- | :--- |
| `CONFIG_UPDATE` | `{ "url": "..." }` | 通知 Agent 配置已更新,需重新拉取 |
| `TASK_SCAN` | `{ "path": "/" }` | 下发即时扫描任务 |
| `TASK_STOP` | `null` | 停止指定模块 |
| `COMMAND_RESPONSE` | `{ "result": "ok" }` | 服务端对上行消息的确认或错误返回 |
---
## 4. 核心模块实现规范
### 4.1 配置加载器
**逻辑规范**:
1. 启动时加载 `user.json` 获取服务器地址。
2. 连接服务器,通过 HTTP GET 请求拉取最新的 `official.json`
3. 将两者合并为内存配置对象 `RuntimeConfig`
**错误处理**:
*`user.json` 缺失,尝试连接默认地址或提示启动失败(视部署策略而定)。
* 若拉取 `official.json` 失败,使用本地缓存(如果存在)继续运行,并输出 WARN 日志,不应 Crash 进程。
### 4.2 白名单管理器
**逻辑规范**:
1. **判定优先级**: 首先检查 `IgnoredPaths` -> 其次检查 `WhitelistFiles`
2. **合并策略 (重要)**:
* 对于文件白名单:采用 **并集策略**
*`official.json` 允许 Hash A`user.json` 允许 Hash B则该文件 Hash 为 A 或 B 均判定为合法。
* 实现示例:
```go
// 伪代码
allowedHashes := append(officialConfig.WhitelistFiles[path], userConfig.SupplementFiles[path]...)
if contains(allowedHashes, currentHash) { status = SAFE }
```
3. **判定结果状态**:
* `IGNORED`: 在忽略列表中
* `SAFE`: 在白名单中且 Hash 匹配
* `NON_WHITELISTED`: 未在白名单中
* `HASH_MISMATCH`: 在白名单中但 Hash 不匹配
4. **并发安全**: 必须使用 `sync.RWMutex` 保护配置更新和查询操作。
### 4.3 监控模块
**数据规范**:
* **时间单位**: 配置文件中使用字符串 (`"30s"`),代码中解析为 `time.Duration`。传输协议中使用 **秒级 Unix 时间戳** (int64)。
* **数据精度**: 百分比和容量数据,传输时统一保留小数点后 **2位**
* **性能限制**: `process_limit` 必须生效,防止采集 Top N 进程时导致 Payload 超过 WebSocket 帧大小限制。
---
## 5. 错误处理与日志规范
### 5.1 日志分级
* `DEBUG`: 详细的扫描路径、心跳发送详情(生产环境默认关闭)。
* `INFO`: 模块启动/停止、配置更新成功、检测到的安全事件。
* `WARN`: CPU 负载避让生效(暂停扫描)、网络断线重连中、使用本地缓存配置。
* `ERROR`: 配置下载失败、文件权限错误、JSON 解析失败。
### 5.2 异常处理策略
* **网络中断**: 必须实现 **指数退避** 重连机制。
* 初始延迟: 1s
* 最大延迟: 60s
* 因子: 2.0
* **JSON 解析失败**: 丢弃收到的畸形消息,记录 ERROR 日志,不断开连接。
---
## 6. 前后端对接检查清单
在开发前后端接口时,请对照以下清单进行自测:
- [ ] **字段命名**: 后端 JSON Tag 是否使用了 `snake_case` (如 `cpu_percent`),而非 `camelCase`?
- [ ] **空值处理**: 当列表为空时,后端返回的是 `[]` 空数组,还是 `null`? (建议统一返回 `[]`)。
- [ ] **时间格式**: 时间戳是返回 Unix 毫秒还是秒? (本文档强制要求 **秒**)。
- [ ] **枚举值**: 告警类型 (`REALTIME_FILE_ALERT` 等) 及状态码 (`Code: 200`) 是否有明确定义?
- [ ] **版本兼容**: 当新增字段时,旧版 Agent 是否会因为未知字段 Crash? (Go 解析 JSON 默认忽略未知字段,确认其他语言实现也遵循此原则)。
- [ ] **服务器地址**: 确认 `official.json` 中不包含任何硬编码的服务器 IP 或域名。