
背景
在跨地域运维场景中,通过 HTTPS API 控制远程服务器是一种高效方案。我们搭建的运维网关基于 FastAPI,运行在境外服务器上,通过 HTTPS + Token 认证,为 AI Agent 提供远程 shell 执行、文件读写、WordPress CLI 等能力。
这种架构避开了 SSH 直连的复杂性,但也引入了一些典型的工程陷阱。本文将完整拆解其设计原理和踩过的坑。
架构概览
服务运行在境外服务器,通过 HTTPS + Bearer Token 认证,为前端 AI Agent 提供 API 接口。
- **框架**: FastAPI + uvicorn
- **传输**: HTTPS(自签证书)
- **认证**: Bearer Token
- **安全**: IP 白名单 + 命令白名单 + 审计日志
核心端点设计
Shell 执行端点
POST /api/v1/shellBody: {"command": "whoami", "timeout": 30}
核心设计考虑:
- **命令安全**:白名单 + 黑名单双重校验
- **超时控制**:防止命令挂死连接
- **后台执行**:nohup 命令需要特殊处理
- **输出截断**:限制最大输出量防止内存溢出
文件操作端点
POST /api/v1/file/read Body: {"path": "/var/log/app.log"}POST /api/v1/file/write Body: {"path": "/tmp/out.txt", "content": "data"}
文件传输限制在允许的目录内,禁止访问 /etc/、/root/、/boot/ 等敏感目录。
安全机制
IP 白名单
只允许指定 IP 访问。生产环境还需在防火墙层面加固。
命令白名单
命令必须匹配至少一个白名单正则模式:
{"allowed_commands": ["wp .*", "mysql .*", "python3 .*","cat .*", "grep .*", "ps .*","nohup .*", "sleep .*"],"blocked_commands": ["rm -rf /", "mkfs .*"]}
审计日志
所有请求写入审计日志文件,包含时间戳、客户端 IP、操作端点、参数(脱敏)、耗时。
踩坑实录
坑1: nohup 后台命令进程消失
**现象**: nohup python3 xxx.py & 发出后无 PID,进程消失。
**根因**: subprocess.run(shell=True, capture_output=True) 创建管道,进程返回时关闭管道,后台进程收到 SIGPIPE 被杀死。
**修复**:
if is_background:proc = subprocess.Popen(command,shell=True,stdout=subprocess.DEVNULL,stderr=subprocess.DEVNULL,start_new_session=True, # 新会话组)return {"pid": proc.pid, "background": True}
坑2: 命令长度限制
API 限制命令最大长度 1000 字符。长命令会被截断导致执行失败。
**应对**: 短命令走 API 端点,长命令通过 base64 编码中转。
坑3: 文件传输仅限文本
二进制文件需 base64 编码(小文件)或服务端 wget/curl 下载。
坑4: WP-CLI 内容写入 Bug
wp post create --post_content=@file 写入字面文本 “@”。
**应对**: 用 PHP wp_insert_post() 绕过。
坑5: 超时设置
服务端 timeout_keep_alive 设为 600s,客户端需设 timeout=300 以上。
systemd 部署
[Service]Type=simpleUser=rootExecStart=/usr/bin/python3 /opt/xr-api/xr_api.pyRestart=alwaysRestartSec=5
总结
- 命令白名单 + IP 白名单 + 审计日志 = 三层安全
subprocess.run不用于后台命令,改用Popen + start_new_session- 命令长度限制 1000 字符,长命令需 base64 中转
- WP-CLI 写入内容用 PHP 绕过 stdin bug
- 超时设置要注意服务端和客户端一致
- 自签证书必须带 IP SAN
发表回复