From f70b344c85ab19a3e0377ff5b0005698ce319c6b Mon Sep 17 00:00:00 2001 From: CaoWangrenbo Date: Sat, 29 Aug 2026 21:28:52 +0800 Subject: [PATCH] =?UTF-8?q?chore:=20initial=20commit=20=E2=80=94=20?= =?UTF-8?q?=E9=A1=B9=E7=9B=AE=E8=AE=A1=E5=88=92=20v0.3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 服务器用户管理节点(ws_usernode): - docs/PLAN.md:需求交互确认后的完整项目计划(v0.3) - 单机节点 + RESTful API v1,后期可扩展多节点 agent - Go + Gin / Vue3 + Element Plus,GORM 双驱动(MySQL/SQLite) - 外部用户 OTP 双通道登录(邮件 + CLI)、sudoers 白名单系统操作 - 账号生命周期、SSH 公钥管理、申请审批、审计归档 - .gitignore:Go / 前端 / 运行时产物忽略规则 --- .gitignore | 22 ++++ docs/PLAN.md | 325 +++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 347 insertions(+) create mode 100644 .gitignore create mode 100644 docs/PLAN.md diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..3f4a5b8 --- /dev/null +++ b/.gitignore @@ -0,0 +1,22 @@ +# Go +/bin/ +*.test +coverage.out +*.prof + +# 前端构建产物 +web/node_modules/ +web/dist/ +web/.vite/ + +# 运行时产物 +*.log +data/ +*.db +*.db-shm +*.db-wal + +# 其他 +.DS_Store +.env +config.toml diff --git a/docs/PLAN.md b/docs/PLAN.md new file mode 100644 index 0000000..e399e46 --- /dev/null +++ b/docs/PLAN.md @@ -0,0 +1,325 @@ +# 项目计划:服务器用户管理节点(ws_usernode) + +> 版本:v0.3(需求已交互确认,含构建/配置细化) +> 日期:2026-08-29 +> 状态:待评审 + +--- + +## 1. 项目概述 + +构建一个基于 Go 的**服务器用户管理节点**,提供 Web 前后端,用于对服务器上的**外部用户**(非本机管理员)进行集中化管理,覆盖: + +- 系统账号的创建、禁用、删除、过期与回收(统一 `ext_` 前缀、`external` 组) +- 外部用户自助上传与管理 SSH 公钥,实时同步 `authorized_keys` +- 用户自助申请新账号 + 管理员审批流 +- SMTP 邮件通知(OTP 登录验证码、审批结果、到期提醒、密码重置) +- 管理操作审计(保留 30 天 + 手动/每日定时归档) + +**部署形态**:单机节点,一个 Go 二进制(前端产物 go:embed 嵌入),参考 Gitea 单二进制风格。所有能力通过 **RESTful API v1** 暴露,系统账号操作层接口化,为后期扩展"控制面 + 多节点 agent"预留空间。 + +--- + +## 2. 已确认决策汇总 + +### 2.1 架构与部署 + +| 决策点 | 结论 | +|---|---| +| 部署形态 | 单机节点;RESTful API v1;后期可扩展多节点 agent | +| 后端 | Go ≥ 1.22 + Gin | +| 前端 | Vue 3 + Vite + TypeScript + Element Plus + Pinia + Vue Router + Axios | +| 前端部署 | **go:embed 嵌入 Go 二进制**,单文件分发;开发期走 Vite dev server | +| 数据库 | GORM 抽象,**MySQL 生产 / SQLite 开发**,可平滑迁移 | +| 进程管理 | systemd 服务 | +| 系统账号操作权限 | 节点以**专有用户运行**(如 `usernode`,加入 sudo 组),通过 **sudoers 白名单**执行 `useradd/usermod/userdel/passwd` 等,便于审计程序行为 | +| 日志 | log/slog 结构化日志 | +| 构建环境 | **podman 容器**构建(多阶段);前端可单独拉取**前端 dev 镜像**热开发 | +| 配置格式 | **TOML**(`config.example.toml`,支持环境变量覆盖) | + +### 2.2 账号与认证 + +| 决策点 | 结论 | +|---|---| +| 外部用户系统账号 | 统一加入 `external` 组;用户名强制 `ext_` 前缀(如 `ext_zhangsan`);系统账号口令锁定(`passwd -l`),仅密钥登录 | +| 外部用户登录 | **图形验证码 + 6 位 OTP**;OTP 支持**邮件**与 **CLI 子命令**双通道获取(同一验证码、同一 10 分钟有效期、同一 60s 冷却与失败限速,两通道对齐);会话 **cookie**(HttpOnly/Secure/SameSite) | +| 管理员登录 | 用户名 + 密码(bcrypt);密码可通过 **CLI 子命令**或**邮件重置**修改;不做 TOTP | +| 用户邮箱 | 仅管理员可修改(OTP 接收方);用户不可自助改 | +| 默认有效期 | 批准激活起默认 **90 天**(全局可配置),管理员创建/延期时可覆盖 | + +### 2.3 功能范围 + +| 决策点 | 结论 | +|---|---| +| 管理范围 | 账号生命周期 + SSH 密钥(仅用户上传,管理员不代签) | +| 新账号申请 | 表单:**用户名、邮箱、挂靠老师、用途**;批准后**自动 useradd** 并邮件通知 | +| 审批范围 | **仅新账号申请**走审批流;延期由管理员操作 | +| 密钥来源 | 仅用户自行上传公钥;无管理员代签、无密钥对下发路径 | +| 过期回收 | 到期自动禁用(锁系统账号)+ 邮件通知;可配置**回收期**(默认 30 天),期内可延期恢复,超期自动删除系统账号与密钥(**保留审计**) | +| 用户自助范围 | 管理自己的公钥(上传/重命名/吊销)、查看账号信息与状态、查看自己的审计痕迹 | +| 审计 | 管理操作审计,append-only;保留 **30 天**自动清理;**手动 CSV 导出 + 每日定时归档**(文件存磁盘) | +| 批量导入 | 本期不做,接口预留(二期) | + +--- + +## 3. 需求范围 + +### 3.1 功能需求(FR) + +**F1 认证与会话** +- 管理员:用户名+密码登录;bcrypt 存储;登录限速防暴力;忘记密码走 SMTP 邮件重置;CLI 子命令重置 +- 外部用户:图形验证码(防机器人)→ 6 位 OTP → 验证登录;OTP 经**邮件**或 **CLI 子命令**获取(同一验证码、同一有效期与限速,两通道对齐);发送冷却 60s、单账号失败限速 +- 会话:cookie(HttpOnly/Secure/SameSite),默认 24h,可配置;登出即失效 +- 外部用户无 Web 口令(系统账号口令锁定,纯密钥登录) + +**F2 用户生命周期管理** +- 管理员创建外部用户:自动生成 `ext_` 系统账号(`external` 组、锁定口令、默认 shell) +- 启用 / 禁用 / 删除 / 延期;状态与系统账号一致性校验 +- 到期自动禁用(锁账号)+ 邮件提醒;进入回收期(默认 30 天,可配置);回收期内可延期恢复;超期自动删除系统账号与密钥(保留审计) +- 用户模型记录:邮箱、挂靠老师、用途、过期时间、创建者、最近登录 + +**F3 SSH 密钥管理** +- 用户上传自己的公钥(格式校验:类型/长度/重复) +- 密钥列表、重命名、吊销、删除 +- 有效密钥实时同步到 `~/.ssh/authorized_keys`(原子写 + 并发锁),吊销立即失效 + +**F4 申请与审批** +- 新账号申请单:用户名、邮箱、挂靠老师、用途 +- 管理员审批(通过 / 拒绝 + 理由),结果邮件通知;通过后自动创建账号 +- 拒绝后可重新提交 + +**F5 邮件通知(SMTP)** +- OTP 登录验证码、审批结果、账号创建通知、到期提醒、回收提醒、管理员密码重置 +- 发送队列 + 重试 + 失败记录(mail_logs);OTP 为双通道(邮件 + CLI),邮件失败不阻断登录 + +**F6 审计** +- 记录管理操作:操作者、动作、对象、详情(JSON)、IP、结果、时间;append-only +- 保留 30 天自动清理;手动 CSV 导出接口;每日定时归档到磁盘目录(归档后可安全清理) + +**F7 系统设置** +- SMTP、默认有效期、回收期、会话时长、审计保留天数等(config + settings 表) + +### 3.2 非功能需求(NFR) + +- **安全**:私钥不经系统(无代签);系统命令 sudoers 白名单、最小权限;OTP/图形验证码/限速;cookie 安全属性;审计不可篡改 +- **兼容性**:SQLite ↔ MySQL 迁移无忧(GORM 通用类型 + 迁移脚本) +- **部署**:单二进制 + go:embed 前端 + systemd + sudoers 配置;提供 Docker 可选 +- **可观测**:结构化日志、审计表、状态接口 +- **可扩展**:system 层接口化,预留多节点 agent;API 无状态化(cookie 会话 + DB session 存储) + +--- + +## 4. 技术选型 + +| 层 | 选型 | 理由 | +|---|---|---| +| 语言 | Go ≥ 1.22 | 单二进制、并发好、部署简单 | +| Web 框架 | Gin | 生态成熟、中间件丰富 | +| ORM | GORM v2(sqlite + mysql 驱动) | 一套模型双库支持 | +| 认证 | 服务端会话(DB 存储)+ cookie;bcrypt;OTP(crypto/rand 生成) | 符合"cookie 会话"确认 | +| 图形验证码 | 内置生成(图像,随机字符),不依赖第三方服务 | 防机器人,自包含 | +| 定时任务 | robfig/cron/v3 | 过期扫描、回收、审计归档 | +| 邮件 | gomail(net/smtp 封装) | TLS 支持,队列+重试 | +| SSH 公钥 | crypto/ssh 解析校验 | 标准库,免依赖 | +| 前端 | Vue 3 + Vite + TS + Element Plus + Pinia + Router + Axios | 后台管理生态成熟 | +| 日志 | log/slog | 标准库结构化日志 | +| 配置 | TOML(github.com/BurntSushi/toml) | 配置文件 + 环境变量覆盖 | +| 构建 | podman 多阶段容器构建 | Go 镜像 + 前端 dev 镜像 | + +--- + +## 5. 总体架构 + +### 5.1 分层 + +``` +┌───────────────────────────────────────────────┐ +│ Web 前端 (Vue3 SPA, go:embed 进二进制) │ +└───────────────┬───────────────────────────────┘ + │ HTTPS / RESTful API v1 +┌───────────────▼───────────────────────────────┐ +│ HTTP 层 (Gin) 路由 / 中间件 / 参数校验 / 鉴权 │ +├───────────────────────────────────────────────┤ +│ 服务层 (service) │ +│ auth │ user │ key │ approval │ mail │ audit │ +├───────────────────────────────────────────────┤ +│ 系统账号抽象层 (system) 接口: CreateUser / │ +│ RemoveUser / SetLock / SyncAuthorizedKeys │ +│ └── 本地实现: sudoers 白名单 + sudo -n 执行 │ +│ useradd/usermod/userdel/passwd、原子写 │ +│ authorized_keys ──(未来)──> 远程 agent │ +├───────────────────────────────────────────────┤ +│ 数据层 (GORM) users/ssh_keys/approvals/ │ +│ audit_logs/sessions/settings │ +│ ├─ MySQL(生产) │ +│ └─ SQLite(开发/单机) │ +└───────────────────────────────────────────────┘ +``` + +### 5.2 目录结构(规划) + +``` +ws_usernode/ +├── cmd/usernode/main.go # 入口 + CLI 子命令 +│ ├── serve # 启动服务 +│ ├── migrate # 数据库迁移 +│ ├── admin create # 创建初始管理员 +│ ├── admin reset-password # 重置管理员密码(CLI) +│ └── user otp # 外部用户 OTP 获取(与邮件对齐) +├── internal/ +│ ├── config/ # 配置加载(yaml + 环境变量) +│ ├── server/ # HTTP server、优雅启停 +│ ├── router/ # 路由注册 +│ ├── api/ # handler 层(v1) +│ ├── model/ # GORM 模型 +│ ├── service/ # 业务逻辑 +│ ├── system/ # 系统账号抽象层(sudoers 白名单实现) +│ ├── auth/ # 会话、bcrypt、OTP、图形验证码、限速 +│ ├── cron/ # 过期扫描、回收、审计归档 +│ └── pkg/ # 工具(随机、时间、校验) +├── web/ # Vue3 前端 +│ ├── src/ +│ └── Containerfile.dev # 前端 dev 镜像(podman 热开发) +├── docs/ # 本计划、API、数据库、部署 +├── deploy/ # systemd 单元、sudoers 配置、迁移脚本、Containerfile +├── config.example.toml +├── go.mod +└── Makefile # build / test / dev 工作流 +``` + +--- + +## 6. 数据库设计(核心表) + +> GORM 定义;避免平台特有类型;时间统一 UTC;SQLite/MySQL 双兼容。 + +| 表 | 关键字段 | 说明 | +|---|---|---| +| `admin_users` | username, password_hash, email, role, status | 管理端账号(唯一) | +| `users` | username(`ext_` 强制前缀), email, supervisor, purpose, status(active/disabled/expired), expire_at, shell, created_by, last_login_at, recycled_at | 外部用户(1:1 系统账号) | +| `ssh_keys` | user_id, name, key_type, public_key, fingerprint, status(active/revoked), source(默认 user_uploaded), created_by, revoked_at | 仅用户上传公钥 | +| `approvals` | username_requested, email, supervisor, purpose, status(pending/approved/rejected), reviewer_id, reviewed_at, reason | 仅新账号申请 | +| `audit_logs` | actor_id, actor_name, action, resource_type, resource_id, detail(JSON), ip, result, created_at | append-only | +| `sessions` | session_id, user_type(admin/user), ref_id, expire_at, ip, user_agent | cookie 会话 | +| `settings` | key, value | SMTP、策略等 | +| `mail_logs` | to, subject, status, error, retry_count | 邮件队列/重试/失败记录 | + +OTP 验证码与图形验证码:单实例可用内存缓存 + 限速计数(DB 或内存);文档注明多实例时需改为 DB/Redis。 + +--- + +## 7. API 设计(RESTful v1) + +统一前缀 `/api/v1`;会话基于 cookie(非 Bearer header)。 + +| 模块 | 方法 & 路径 | 说明 | 权限 | +|---|---|---|---| +| 认证 | `GET /auth/captcha` | 图形验证码 | - | +| 认证 | `POST /auth/otp/send` | 外部用户:用户名 + 图形验证码 → 发 OTP 邮件(60s 冷却) | - | +| 认证 | `POST /auth/otp/login` | 用户名 + 6 位 OTP → 建立 cookie 会话 | - | +| 认证 | `POST /auth/admin/login` | 管理员用户名+密码登录 | - | +| 认证 | `POST /auth/logout` / `GET /auth/me` | 登出 / 当前会话 | user/admin | +| 认证 | `POST /auth/admin/forgot` / `POST /auth/admin/reset` | 管理员邮件重置密码 | - | +| 用户 | `GET /users` | 列表(筛选/分页:状态、到期、挂靠老师) | admin | +| 用户 | `POST /users` | 管理员创建(自动 useradd) | admin | +| 用户 | `GET /users/:id` / `PATCH /users/:id` | 详情 / 更新(含改邮箱) | admin | +| 用户 | `POST /users/:id/disable` / `enable` | 禁用 / 启用 | admin | +| 用户 | `POST /users/:id/extend` | 延长过期时间 | admin | +| 用户 | `DELETE /users/:id` | 删除并回收(系统账号+密钥,保留审计) | admin | +| 密钥 | `GET /me/keys` | 我的密钥列表 | user | +| 密钥 | `POST /me/keys` | 上传公钥 | user | +| 密钥 | `PATCH /me/keys/:id` | 重命名 | user | +| 密钥 | `DELETE /me/keys/:id` | 吊销 / 删除 | user | +| 密钥 | `GET /users/:id/keys` | 用户密钥列表(管理员) | admin | +| 审批 | `POST /approvals` | 提交新账号申请 | -(公开) | +| 审批 | `GET /approvals` | 申请单列表(按状态筛选) | admin | +| 审批 | `POST /approvals/:id/review` | 审批(通过→自动建号 / 拒绝+理由) | admin | +| 审计 | `GET /audit` | 查询(操作者/资源/时间范围/分页) | admin | +| 审计 | `GET /audit/export` | 手动 CSV 导出 | admin | +| 设置 | `GET /settings` / `PUT /settings` | 系统设置读写 | admin | +| 状态 | `GET /healthz` | 健康检查 | - | + +--- + +## 8. 前端规划(Vue3) + +参考 Gitea 后台管理布局: + +1. **登录页**:管理员(密码)与外部用户(图形验证码 + 邮件 OTP)双入口 +2. **仪表盘**:用户数、待审批数、近期待过期账号、最近审计 +3. **用户管理**(admin):列表筛选/分页、新建、详情、禁用/启用/延期/删除、改邮箱 +4. **密钥管理**:我的密钥上传/重命名/吊销 +5. **申请审批**(admin):待办列表、通过/拒绝 + 理由 +6. **审计日志**(admin):查询 + CSV 导出 +7. **系统设置**(admin):SMTP、默认有效期、回收期、会话时长、审计保留 +8. **个人中心**(user):账号信息(挂靠老师/用途/到期时间)、我的密钥、我的审计痕迹 + +技术栈:Vite + Vue Router + Pinia + Axios(统一拦截 401/错误码)+ Element Plus;构建产物 go:embed。 + +--- + +## 9. 安全设计 + +| 风险 | 对策 | +|---|---| +| 系统账号操作提权 | 节点以专有用户运行;**sudoers 白名单**仅允许固定命令(useradd/usermod/userdel/passwd/chsh)且禁任意 shell;命令参数程序内强校验;不在生产直接验证 | +| OTP 爆破 / 滥用 | 图形验证码前置、发送冷却 60s、单账号失败限速、OTP 一次性 + 10 分钟过期;CLI 通道受同一限速约束 | +| 会话劫持 | cookie HttpOnly/Secure/SameSite;会话过期;登出吊销;IP 变更可选提示 | +| 口令安全 | 管理员 bcrypt 存储、强度校验、登录限速 | +| authorized_keys 并发写 | 文件锁 + 原子写(tmp + rename);全量重写基于 DB 状态 | +| 审计不可篡改 | audit_logs 仅 INSERT;30 天自动清理前先归档;定期备份 | +| 邮件安全 | SMTP TLS、邮件内容不含验证码明文记录、密码不出现在日志 | +| 外部用户口令 | 系统账号 `passwd -l` 锁定,仅密钥登录 | + +--- + +## 10. 里程碑与排期 + +> 估算总周期约 3~4 周(单人),每阶段含测试。 + +| 阶段 | 内容 | 交付物 | 估算 | +|---|---|---|---| +| **M0 骨架** | Go 工程、CLI 子命令(含 OTP 获取)、TOML 配置、日志、GORM 双驱动、**podman 多阶段构建**、前端脚手架(Vite **dev 镜像** + go:embed 打通) | 可运行空壳 + 迁移 | 2–3 天 | +| **M1 认证 + 用户管理** | 管理员登录(密码/CLI/邮件重置)、外部用户 OTP 登录(图形验证码 + 邮件/CLI 双通道)、cookie 会话、用户 CRUD、system 层 sudoers 对接 | 可创建/禁用/删除真实系统用户 | 5–6 天 | +| **M2 SSH 密钥** | 公钥上传/管理、authorized_keys 原子同步、吊销即时失效 | 端到端密钥管理 | 3–4 天 | +| **M3 审批 + 邮件** | 新账号申请流(用户名/邮箱/挂靠老师/用途)、审批、SMTP 通知、拒绝重提 | 完整申请-审批闭环 | 3–4 天 | +| **M4 生命周期 + 审计** | 过期扫描 cron、回收期策略、审计(30 天 + 手动导出 + 每日归档) | 自动化回收 + 可查可导出审计 | 3–4 天 | +| **M5 前端完善 + 部署** | Vue3 全部页面、联调、podman 构建镜像、systemd + sudoers 部署、迁移脚本、文档 | 可交付部署版本 | 5–7 天 | + +**验收标准(M5 完成时)** +- 管理员创建用户 → 用户图形验证码 + OTP(邮件或 CLI)登录 → 上传公钥 → 立即 SSH 登录服务器 +- 吊销密钥立即失效;到期自动禁用并通知;回收期内可延期,超期自动回收(保留审计) +- 所有管理操作可审计、可查询、可 CSV 导出,每日归档 +- SQLite 数据可迁移至 MySQL(提供脚本与验证) +- 单二进制部署(systemd + sudoers 白名单)通过;podman 容器构建通过(Go 镜像 + 前端 dev 镜像) + +--- + +## 11. 风险与对策 + +| 风险 | 影响 | 对策 | +|---|---|---| +| 系统账号操作失误(误删/误改) | 高 | sudoers 白名单、命令参数强校验、回收二次确认、测试环境验证 | +| OTP/邮件链路故障 | 中 | 邮件队列 + 重试 + 失败告警;OTP 双通道(邮件 + CLI),邮件不可用时经 CLI 获取 | +| SQLite ↔ MySQL 迁移差异 | 中 | GORM 通用类型、迁移前校验、迁移脚本 + 演练 | +| 定时任务并发触发 | 中 | 单实例部署说明;预留分布式锁接口 | +| 管理员密码丢失 | 中 | CLI `admin reset-password` 兜底 | +| 多实例扩展(未来 agent) | 低(预留) | system 层接口化;会话/OTP 存储预留 DB 方案 | + +--- + +## 12. 待定项 / 二期展望 + +- 多节点 agent 模式(system 层远程化) +- CSV 批量导入用户 +- 用户自助延期申请(当前管理员操作) +- TOTP 双因素(当前不做) +- 审计归档格式扩展(当前 CSV;可加 JSON) +- 通知渠道扩展(Webhook/企业微信/钉钉) + +--- + +## 13. 下一步 + +1. 评审本计划(v0.2),确认范围与里程碑 +2. 评审通过后启动 **M0**:工程骨架、CLI、CI、前端脚手架