Files
aiops/docs/rdp.md
T
LoganandClaude 76ec9387f0 feat(rdp): 新增 RDP 远程桌面/SMB/账单同步能力 + 清理编译产物
主要变更:
- RDP 远程桌面:新增 backend/pkg/rdp(RDP 引擎 + credssp/display/rle/trace)、
  backend/controller/rdp*(连接/凭证/文件/会话/实时)、frontend RDP 组件与 API
- Windows SMB 文件传输:backend/pkg/winsmb
- 云账单同步:backend/pkg/billingsync + billing_sync/aliyun_billing,前端账单详情
- Agent CLI Kubernetes 工具:kubernetes_action/get、pod_execute/logs
- 服务器导入助手:server_import_helpers、ImportCredentialSettings
- 国际化与组件重构(cloud/deploy/monitor/server/system 等多模块)
- 清理编译产物二进制:移除 backend/server、backend/agent/bin/aiops-agent-*
- .gitignore:新增 backend/agent/ 与 .cache/(避免 334MB go-build 缓存误入库)

Co-Authored-By: Claude <noreply@anthropic.com>
2026-07-04 01:50:36 +08:00

235 lines
8.5 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.
# AIOps Web RDP 远程桌面
> 作者:Logan.Li
> 更新:2026-07-03
> 归档副本:`/opt/rdp/docs/rdp.md` · 变更记录:`/opt/rdp/CHANGELOG.md`
---
## 概述
AIOps 提供浏览器内 Windows 远程桌面(Canvas 渲染 + WebSocket)。当前已移除第三方 `grdp` 兜底实现,后端固定使用 AIOps 自研 RDP 协议栈。// Logan.Li
| 环境变量 | 行为 |
|----------|------|
| `RDP_ENGINE` | 已不再参与引擎选择,保留环境变量不会改变行为 |
| `RDP_DEBUG=1` | 打开 `[RDP:TRACE]` 协议级日志 |
| 层级 | 状态 | 路径 |
|------|------|------|
| X.224 / TPKT / TLS | ✅ 自研灰度 | `backend/pkg/rdp/transport/` |
| CredSSP / NTLMv2 (NLA) | ✅ 自研灰度 | `backend/pkg/rdp/credssp/` |
| MCS / GCC / 许可证 / 激活 | ✅ 自研灰度 | `backend/pkg/rdp/mcs_probe.go`、`session_connect.go` |
| FastPath 位图 / MPPC / RLE | ✅ 自研灰度 | `bitmap_decode.go`、`fastpath_recv.go`、`mppc.go`、`rle/` |
| 键鼠 / 剪贴板 / auto_exec | ✅ 自研灰度 | `input_fastpath.go` |
| 文件传输 (SMB + 暂存回退) | ✅ 自研 | `pkg/winsmb/`、`pkg/rdpfilestage/` |
| 前端 Canvas + 工具面板 | ✅ 自研 | `RdpDialog.tsx`、`RdpToolsPanel.tsx` |
自研协议栈不依赖第三方 RDP 实现,也不直接依赖控制器、数据库或 WebSocket。已删除的第三方目录备份在 `/opt/rdp/third-party/grdp-aiops-backup-20260703`。// Logan.Li
---
## 2026-07-03 变更记录
### 自研 RDP 引擎
| 变更项 | 说明 |
|--------|------|
| 引擎入口 | `NewEngine()` 固定返回 `SessionEngine` |
| 兜底依赖 | 已移除 `github.com/nakagami/grdp` 和 `backend/third_party` |
| Dockerfile | 不再复制 third_party 模块 |
| 新增模块 | `session_engine.go`、`session_connect.go`、`packet_io.go`、`fastpath_recv.go`、`bitmap_decode.go`、`input_fastpath.go`、`mppc.go`、`rle/` |
| 自研会话激活 | `ConfirmActive` 后可选读 FontMap,发送 `SuppressOutput(ALLOW_DISPLAY_UPDATES)` 触发服务端推帧 |
| 自研位图输出 | FastPath / SlowPath Bitmap + SurfaceCmd → PNG base64 → WebSocket `type:bitmap` |
| 自研输入通道 | Fast-Path Input:扫描码键鼠、Unicode 剪贴板、`auto_exec`(Win+R 粘贴命令) |
| 协议日志 | `RDP_DEBUG=1` 输出 `[RDP:TRACE]`,定位连接、bitmap、input 阶段 |
### 仍保留的探测 API(诊断用)
| 函数 | 用途 |
|------|------|
| `ProbeHandshake` | X.224 安全协议协商 |
| `ProbeCredSSP` | NLA 凭据验证 |
| `ProbeMCSConnect` | MCS/GCC 握手探测(读完即关连接) |
| `ProbeSessionFrames` | 建立会话后统计位图矩形数量 |
### 已知限制 / 待完善
- `mcs_probe.go` 超 700 行红线,后续需按 MCS/GCC/PDU 拆文件
- 未实现 cliprdr 虚拟通道双向同步、RDPGFX/H.264、动态虚拟通道
- 部分 Windows 主机在频繁探测后可能 `connection reset`(目标机策略/限流,非 NLA 失败)
---
## 架构与调用链
```
RdpDialog.tsx
│ WebSocket /ws/rdp?id=&width=&height=&token=
▼
controller/rdp.go
│ loadRDPCredential() → engine.Run()
▼
pkg/rdp/engine.go → SessionEngine
├── session_engine.go readLoop + handleEvent
├── session_connect.go OpenSession (CredSSP + MCS + SuppressOutput)
├── packet_io.go TPKT / FastPath 读写
├── fastpath_recv.go 服务端更新解析
├── bitmap_decode.go RLE/翻转 → PNG
├── input_fastpath.go 键鼠 / 剪贴板 / auto_exec
├── mppc.go MPPC 解压
└── rle/ 位图 RLE 解压算法
```
---
## 后端文件清单
### 协议栈 `backend/pkg/rdp/`
| 文件 | 说明 |
|------|------|
| `engine.go` | `Engine` 接口、`RDP_ENGINE` 引擎选择 |
| `client.go` | `ProbeHandshake` / `ProbeTLSHandshake` / `ProbeCredSSP` |
| `session_engine.go` | 图形会话主循环、帧推送、输入分发 |
| `session_connect.go` | `OpenSession`、SuppressOutput 激活 |
| `mcs_probe.go` | MCS Connect、GCC、ClientInfo、ConfirmActive 构建与探测 |
| `packet_io.go` | `ReadWirePacket`、`WriteFastPathInput` |
| `fastpath_recv.go` | FastPath 更新、MPPC、SurfaceCmd 解析 |
| `bitmap_decode.go` | 位图解码与 PNG 编码 |
| `input_fastpath.go` | Fast-Path Input 事件编码 |
| `mppc.go` | MPPC-64K 解压器 |
| `keymap.go` | 浏览器 `KeyboardEvent.code` → RDP 扫描码 |
| `transport/` | TPKT、X.224、TLS |
| `credssp/` | CredSSP + NTLMv2 + ASN.1 |
| `rle/` | RLE 位图解压(`DecompressInto`) |
### 控制器 / 模型
| 文件 | 说明 |
|------|------|
| `controller/rdp.go` | WebSocket 会话、审计录制 |
| `controller/rdp_session.go` | 会话列表 / 回放 / 终止 API |
| `controller/rdp_file.go` | 文件 list/upload/download/stage |
| `controller/rdp_cred.go` | 凭据加载辅助 |
| `model/rdp_session.go` | `RDPSession` 表 |
### 文件传输
| 文件 | 说明 |
|------|------|
| `pkg/winsmb/` | SMB 管理共享直传 `C:\Users\Public\AIOpsShare\Download` |
| `pkg/rdpfilestage/` | 服务端暂存 + 一次性 token |
| `frontend/.../RdpToolsPanel.tsx` | 工具面板(通用命令 / 文件 Tab) |
| `frontend/.../rdpConstants.ts` | 虚拟 Download 盘路径常量 |
---
## 前端
| 文件 | 说明 |
|------|------|
| `RdpDialog.tsx` | Canvas 渲染、WebSocket、键鼠捕获、工具栏 |
| `RdpToolsPanel.tsx` | 剪贴板同步、文件上传下载、auto_exec 回退 |
| `api/server/rdp-files.ts` | 文件传输 REST |
| `api/audit/rdp.ts` | 会话审计 API |
---
## WebSocket 帧协议
### 服务端 → 浏览器
```json
{ "type": "session", "message": "123", "width": 1280, "height": 800 }
{ "type": "status", "message": "正在连接 RDP ..." }
{ "type": "error", "message": "..." }
{ "type": "bitmap", "x": 0, "y": 0, "width": 64, "height": 64, "image": "data:image/png;base64,..." }
{ "type": "clipboard","text": "远端剪贴板内容" }
```
### 浏览器 → 服务端
```json
{ "type": "mouse_move", "x": 100, "y": 200 }
{ "type": "mouse_down", "x": 100, "y": 200, "button": 0 }
{ "type": "mouse_up", "x": 100, "y": 200, "button": 0 }
{ "type": "wheel", "x": 100, "y": 200, "delta_y": -120 }
{ "type": "key", "code": "KeyA", "key": "a", "down": true }
{ "type": "clipboard", "text": "本地剪贴板" }
{ "type": "auto_exec", "text": "C:\\Users\\Public\\AIOpsShare\\Download\\setup.exe" }
```
---
## CredSSP 多策略重试
每条策略使用**新建 TCP 连接**(`client.go`):
1. `v6 + binding`(默认)
2. `v6 + binding + UseCBT`
3. `v6 + binding + ForceMIC`
4. `v2 + raw`(兼容旧服务端)
关键修复:`credssp.subjectPublicKey()` 使用证书 `SubjectPublicKey` 原始 ASN.1,而非 PKIX SPKI。
---
## 外部项目借鉴边界
| 项目 | 可借鉴点 | 不直接采用原因 |
|------|----------|----------------|
| FreeRDP | 协议完整性、通道、编解码、客户端能力矩阵 | C 生态和体量过大,不适合直接嵌入 |
| Apache Guacamole | Web 网关、协议代理、录制与前端桥接分层 | 依赖 guacd/C,不符合单 Go 后端目标 |
| IronRDP | 现代模块化、状态机测试、安全边界 | Rust 生态,适合作为测试和分层参考 |
| Teleport | 身份、RBAC、审计、Desktop Gateway 架构 | 产品目标偏堡垒机,不是轻量 RDP client |
| tomatome/grdp / nakagami/grdp | Go 协议状态机、能力集、bitmap/input 参考 | 第三方实现已移除,仅保留 `/opt` 备份用于协议对照 |
## 第三方代码归档与文档
归档与变更记录目录:
```
/opt/rdp/
├── CHANGELOG.md # 变更记录
├── README.md # 索引
├── docs/rdp.md # 完整说明(与本文档同步)
└── third-party/
├── nakagami-grdp-v0.8.7/
├── rdp-web-refs/
└── grdpprobe/
```
> 第三方源码只能作为协议行为和工程分层参考;涉及 GPL 的项目不得直接搬运实现。// Logan.Li
---
## 验证命令
```bash
# 编译
cd backend && CGO_ENABLED=1 go build -o aiops .
# NLA 探测
go run /tmp/rdp_cred_probe.go # ProbeCredSSP
# 会话位图统计(需可达的 Windows:3389)
go run /tmp/rdp_session_probe_main.go
# Docker 端到端
./run.sh docker up
# 浏览器:服务器管理 → Windows 主机 → RDP 连接
```
---
## 相关路由
| 路径 | 说明 |
|------|------|
| `GET /ws/rdp` | WebSocket 图形会话 |
| `GET /api/v1/rdp-sessions` | 会话审计列表 |
| `GET /api/v1/servers/:id/rdp-files` | 远端文件列表 |
| `POST /api/v1/servers/:id/rdp-files/upload` | 上传 |
| `GET /api/v1/servers/:id/rdp-files/download` | 下载 |