Files

7.8 KiB
Raw Permalink Blame History

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.py5 种方法探测 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.pyensure_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.py29KB 源码)
  • 首次使用 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