自建 HTTPS 运维网关:原理、设计与踩坑实录

作者:

自建 HTTPS 运维网关:原理、设计与踩坑实录

背景

在跨地域运维场景中,通过 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/shell
Body: {"command": "whoami", "timeout": 30}

核心设计考虑:

  1. **命令安全**:白名单 + 黑名单双重校验
  2. **超时控制**:防止命令挂死连接
  3. **后台执行**:nohup 命令需要特殊处理
  4. **输出截断**:限制最大输出量防止内存溢出

文件操作端点

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=simple
User=root
ExecStart=/usr/bin/python3 /opt/xr-api/xr_api.py
Restart=always
RestartSec=5

总结

  1. 命令白名单 + IP 白名单 + 审计日志 = 三层安全
  2. subprocess.run 不用于后台命令,改用 Popen + start_new_session
  3. 命令长度限制 1000 字符,长命令需 base64 中转
  4. WP-CLI 写入内容用 PHP 绕过 stdin bug
  5. 超时设置要注意服务端和客户端一致
  6. 自签证书必须带 IP SAN

评论

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注