Files

167 lines
7.8 KiB
Markdown
Raw Permalink 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.
# JumpServer 自动化演进日志
## 概述
从 2026-06-21 到 2026-06-25JumpServer 自动化经历了 **5 种技术路线、17+ 个主要版本** 的迭代,最终选择了 Playwright Web CLI 方案作为生产方案。
## 时间线
```
2026-06-21 ─ 06-22 │ 06-22 ─ 06-23 │ 06-23 ─ 06-25
SSH 路线探索 │ Web CLI 路线验证 │ 生产化 + 部署实战
│ │
• plink.exe (v8) │ • webcli_probe │ • webcli_v4-v7 迭代
• Paramiko (v1-v7) │ • webcli_login_v1 │ • SFTP 文件上传
• wexpect (v11) │ • webcli_inspect │ • 分块 base64 传输
• API auth 探测 │ • webcli_v2-v3 │ • hotfix 实战部署
│ │ • SSH Key 方案探索
```
## 各路线详细记录
### 路线 1: plink.exe (PuTTY CLI) — 已废弃
| 版本 | 文件 | 发现 |
|------|------|------|
| v8 | `test_plink_v8.py` | plink 可以连接但输出捕获不稳定 |
| - | `test_plink_formats.py` | MFA 提示格式有 3 种变体 |
| - | `test_plink_verbose.py` | 详细日志模式可看到完整交互 |
**废弃原因**:中文编码问题、交互式菜单导航不可靠、plink 不支持 PTY 分配。
### 路线 2: Paramiko (Python SSH) — 已废弃
| 版本 | 文件 | 关键发现 |
|------|------|---------|
| v1-v5 | `test_paramiko_v1.py` ~ `v5.py` | 基本连接可行,但 OTP 流程脆弱 |
| v6-v7 | `test_paramiko_v6.py` ~ `v7.py` | 交互式 shell 模式可绕过部分菜单 |
| v8 | `jumpserver_paramiko_v8.py` | 尝试 channel.recv 非阻塞读取 |
| v9 | `jumpserver_paramiko_v9.py` | 尝试 expect 模式(timeout 可控) |
| v12 | `jumpserver_paramiko_v12.py` | SSH Gateway 方式(JumpServer → 目标) |
| v13 | `jumpserver_paramiko_v13.py` | PTY 分配尝试 |
| v14-v16 | `jumpserver_paramiko_v14.py` ~ `v16.py` | 多线程读写分离 |
**废弃原因**JumpServer 堡垒机菜单变化频繁(每次登录可能不同),Paramiko 的 expect 匹配无法适应。OTP 二次认证流程极其脆弱。
### 路线 3: wexpect (Windows expect) — 已废弃
| 版本 | 文件 | 发现 |
|------|------|------|
| v11 | `jumpserver_wexpect_v11.py` | 可以 spawn plink 进程并交互 |
| v2 | `jumpserver_wexpect_v2.py` | 中文输出匹配不稳定 |
| v3 | `jumpserver_wexpect_v3.py` | timeout 设置和重试逻辑优化 |
**废弃原因**wexpect 在 Windows 上不稳定,中文编码问题难以解决,且与 plink 有相同的基础问题。
### 路线 4: Web CLI (Playwright) — ✅ 当前生产方案
| 版本 | 文件 | 关键里程碑 |
|------|------|-----------|
| probe | `jumpserver_webcli_probe.py` | 成功探测 Luna 终端结构 |
| login | `jumpserver_webcli_login_v1.py` | 实现自动登录(密码+OTP) |
| inspect | `jumpserver_webcli_inspect.py` | 分析 Web 终端的 DOM 结构 |
| v2 | `jumpserver_webcli_v2.py` | 基本命令执行 |
| v3 | `jumpserver_webcli_v3.py` | 增加截图和输出保存 |
| v4 | `jumpserver_webcli_v4.py` | 文件上传探索 |
| v5 | `jumpserver_webcli_v5.py` | SFTP 界面自动化 |
| v6 | `jumpserver_webcli_v6.py` | 超时控制 + 错误重试 |
| **v7** | **`jumpserver_webcli_v7.py`** | **生产版本**:完整部署流程 |
**v7 核心能力**
- 自动登录 JumpServer(用户名 + 密码 + OTP
- 导航到目标服务器(税友集团 → hz-oa-ai-g-dataquery-90-5-110
- 在 Web 终端中执行任意命令
- 截图保存(用于验证)
- 输出日志保存
- SFTP 文件上传(set_input_files 方式)
**关键突破**:发现 `OTP 双回车`问题 — 发送验证码后需按 2 次 Enter 触发验证流程。
### 路线 5: SSH Key 认证 — 开发中
| 文件 | 状态 |
|------|------|
| `generate_ssh_keys.py` | 生成 RSA 密钥对 |
| `jumpserver_auto_v17_key_auth.py` | 尝试用密钥认证连接 |
| `ssh_keys/jumpserver_id_rsa` | 已生成的私钥 |
**目标**:绕过 OTP 流程,实现完全无人值守的自动化。
### 路线 6: JumpServer API Token — 探索中
| 文件 | 发现 |
|------|------|
| `create_connection_token.py` | 可通过 API 创建连接 Token |
| `test_connection_token.py` | Token 可用于 SSH 连接 |
| `probe_koko_token.py` | KokoWeb 终端)的 Token 格式不同 |
| `probe_terminal_api.py` | 终端 API 端点探测 |
### 2026-06-25 (下午): xterm.js 输出捕获分析 + probe_v2
- **创建 `probe_xterm_buffer_v2.py`**5 种方法探测 xterm.js 缓冲区
- 全局 Terminal 实例搜索
- DOM .xterm-rows 遍历
- helper-textarea 读取
- 渲染器类型检测(DOM vs Canvas
- React Fiber 组件树搜索
- **创建 `ANALYSIS.md`**:完整的能力-限制-优化分析
- 现有能力矩阵 + 已验证部署记录
- 输出捕获不可靠问题分析(3 种失败模式)
- v8 结构化捕获设计 + Monkey Patch 兜底方案
- 不适用的 6 种场景
- 短/中/长期优化路线图
- **发现**v7 的 `inner_html()` 输出捕获依赖 DOM 渲染器,Canvas 渲染器下失效
### 下一步
- [ ] 运行 probe_xterm_buffer_v2.py 确认 xterm.js 实例暴露方式
- [ ] 根据探测结果实现 webcli_v8.py(结构化缓冲区读取)
### 2026-06-25 (晚间): v10.16 OTP 等待时间修复
**问题**:用户反馈 `ensure_logged_in()` 中 OTP 提交后 `wait_for_timeout(5000)` 只有 5 秒,JumpServer 服务端 OTP 校验通常需要 8-15 秒,导致过早判定超时并进入 URL 跳转检测,进而误判登录失败。
**修复**
1. **MFA 页面消失轮询**:替代固定 5s 等待,改为 500ms × 40 次轮询(max 20s),检测 `input[name="code"]` 消失
2. **OTP 错误检测**:轮询中检测页面正文是否含 "验证码错误/OTP 错误/已过期/expired/Invalid" 关键字
3. **URL 跳转延长**workbench URL 检测从 15×1s=15s 延长到 60×500ms=30s
4. **超时截图**30s 未跳转时自动截图留存(`v10_post_otp_stuck.png`
5. **代码安全**:截图前确保 `OUTPUT_DIR` 存在
**影响范围**`jumpserver_webcli_v10_persistent.py``ensure_logged_in()` 函数 (lines 209-245)
**副作用**:正常流程下 MFA 页面通常在 3-5s 消失,轮询会在第 6-10 次检查(3-5s)时返回,不影响正常速度。仅在网络慢/服务器高负载时才会触发更长的等待。
## 成功部署记录
### Hotfix #116: 扫码获取 (2026-06-22)
- 使用 webcli v2-v4
- 部署 `auth_qrcode.py`
- 5 个部署诊断迭代(diag_v7 ~ diag7_v7
### Hotfix #120: 扫码自动确认 (2026-06-23)
- 使用 webcli v5 + v7
- 部署 `qrcode_service.py`29KB 源码)
- **首次使用 SFTP 分块上传**8 chunks
- 18 个 webcli 子脚本(part1/2、diag、verify、sub、tail、view
- 从 Part A SFTP 到 Part B 部署到 Part C 验证
### Hotfix #48: Nginx Upstream (2026-06-24)
- 使用 webcli v7
- 修复 nginx upstream 配置
- 包含 HTTPS/SSL 验证
### Hotfix SSO: 单点登录启用 (2026-06-25)
- 使用 webcli v7
- 部署 config.py + 环境变量注入
## 记录在案的错误与解决方案
| 错误 | 根因 | 解决方案 | 记录 |
|------|------|---------|------|
| OTP 验证失败 | 发送验证码后未按2次回车 | `test_double_enter.py` 确认需要 `\r\n` | 代码中固定加 `\n` |
| Web CLI 命令输入截断 | 输入框字符限制 ~20KB | 分2批次输入(16KB + 12.8KB | `upload_chunks_sftp.py` |
| Docker cp 路径错误 | 容器内路径与宿主机不同 | 使用 `docker exec` 确认后操作 | webcli_v5_part2.sh |
| 容器重启后立即 curl 失败 | 服务启动需要时间 | 加 `sleep 8` 等待 | webcli_v5_cmd.sh |
| Luna 终端编码乱码 | .sh 文件非 UTF-8 | 使用 `webcli_v3_cmd.utf8.sh` | webcli_v3 |
| SFTP 文件选择器不弹 | webkitdirectory 属性过滤 | v9.8 修复 set_input_files 跳过验证 | upload_chunks_sftp.py |