morgaesis/ssh-guard
GitHub: morgaesis/ssh-guard
为 AI 代理提供基于 LLM 的 SSH 命令评估与门控,防止幻觉导致的破坏性操作。
Stars: 0 | Forks: 0
# guard
LLM评估的命令门控,用于 AI 代理。每个命令在执行前都会通过快速 LLM 调用进行评估。批准的命令正常执行,拒绝的命令会返回解释说明。
```
$ guard run ls -la /etc/nginx/
drwxr-xr-x 8 root root 4096 Mar 10 14:22 .
-rw-r--r-- 1 root root 1482 Mar 10 14:22 nginx.conf
$ guard run rm -rf /etc/nginx/
DENIED: Recursive deletion of system config directory.
```
## 为什么
AI 代理(Claude Code、Codex、Aider、OpenHands、CrewAI 等)越来越需要命令执行权限来进行调试、日志分析和运维任务。一次幻觉性的 `rm -rf` 或 `kubectl delete namespace` 可能导致生产环境宕机。
Guard 坐立在代理与 Shell 之间。每个命令在到达系统前都会由 LLM(默认通过 OpenRouter 使用 `openai/gpt-5.4-nano`)进行评估。LLM 会分析意图与风险,而不仅仅是模式匹配,因此可以捕获混淆的攻击和新型命令链,这些是静态策略难以发现的。
成本可忽略不计:每次评估大约使用 3600 个提示词 + 45 个补全令牌,使用 `openai/gpt-5.4-nano` 每次决策成本约为 0.0005 美元。一个完整的 45 例 CTF 对抗基准测试总共花费约 0.02 美元。
## 安装
```
cargo install --path .
```
或者下载发布工件并手动安装二进制文件。
请参阅 [INSTALL.md](INSTALL.md) 了解安装选项,以及 [DEPLOYMENT.md](DEPLOYMENT.md) 了解服务部署。
## 快速开始
```
# 设置 API 密钥(OpenRouter 或任何 OpenAI 兼容端点)
export SSH_GUARD_LLM_API_KEY="your-key-here"
# 启动服务器
guard server start &
# 通过 guard 执行命令
guard run uptime
guard run cat /var/log/syslog
guard run ps aux
# 这些将被拒绝:
guard run rm -rf /tmp/*
guard run sudo su
```
若要在不执行已批准命令的情况下测试策略决策,请启动一个独立的
干运行服务器:
```
guard server start --dry-run --socket .cache/guard-dry-run.sock
guard server connect --socket .cache/guard-dry-run.sock bash -- -c 'sudo id'
```
## 模式
通过 `SSH_GUARD_MODE` 设置:
| 模式 | 描述 |
|---|---|
| `readonly` | 只读评估。阻止文件写入、系统或服务状态变更、软件包变更、权限提升、反向 Shell 和混淆载荷。允许常规检查命令,如 `ls`、`ps`、`cat`、`grep`、`df`。 |
| `safe` | 宽容的管理评估。允许可见的、有范围的管理操作,但阻止敏感材料读取、破坏性操作、权限提升、未经授权的网络跳转和隐藏载荷。 |
| `paranoid` | 限制性。仅允许基本的只读检查(`id`、`hostname`、`pwd`、`ls`、`ps`、`df`,以及有限的 `git status`)。 |
```
SSH_GUARD_MODE=safe guard run sudo systemctl status ssh --no-pager # allowed
SSH_GUARD_MODE=paranoid guard run sudo systemctl status ssh --no-pager # denied
```
所有模式都会根据底层命令评估 `sudo`:
```
guard run sudo ls /etc/nginx/ # readonly: allowed (read operation)
guard run sudo rm -rf /etc/nginx/ # readonly: denied (destructive)
guard run sudo systemctl restart app # safe: allowed (targeted restart)
```
## 配置
### 默认值与可选项
Guard 带有一个 LLM 仅评估管道:默认通过 OpenRouter 调用一次 `openai/gpt-5.4-nano`,基于函数调用,重试两次后失败关闭。不加载任何静态允许或拒绝列表,也没有备用模型链。此默认配置对常见场景已具备生产就绪能力。
存在两个可选项用于具有特定约束的部署:
- **静态允许/拒绝列表**,通过 `--policy `。对确定性安全或危险模式进行短路评估。请参阅
[`examples/`](examples/README.md) 中的 `allow-policy.yaml`、`deny-policy.yaml` 和 `hybrid-policy.yaml`。
- **备用模型链**,通过 `SSH_GUARD_LLM_MODELS`。在主模型耗尽重试后切换到备用提供商。请参阅
[`examples/fallback-models.env`](examples/fallback-models.env)。
仅在遇到具体的延迟或可用性约束时才启用这些选项。
### 环境变量
所有配置均通过环境变量、CLI 标志或 `.env` 文件完成。
Guard 从当前目录向上遍历到 `/` 查找 `.env` 文件(优先使用最近的),因此可以为每个项目单独作用域配置。
| 变量 | 默认值 | 描述 |
|---|---|---|
| `SSH_GUARD_LLM_API_KEY` / `OPENROUTER_API_KEY` | (无) | LLM API 密钥(必需)。`OPENROUTER_API_KEY` 是约定名称,兼容使用。 |
| `SSH_GUARD_API_URL` | `https://openrouter.ai/api/v1/chat/completions` | 任意 OpenAI 兼容端点 |
| `SSH_GUARD_LLM_MODELS` | (未设置) | 可选的逗号分隔备用链(例如 `openai/gpt-5.4-nano,meta-llama/llama-4-maverick`)。设置后会覆盖 `--llm-model` 并按顺序尝试,每个模型拥有独立的重试预算。主模型未设置时默认为 `openai/gpt-5.4-nano`。 |
| `SSH_GUARD_LLM_RETRIES` | `2` | 每个模型在瞬态失败(429、超时、解析错误)时的重试次数(1–2)。 |
| `SSH_GUARD_MODE` | `readonly` | `readonly`、`safe` 或 `paranoid` |
| `SSH_GUARD_DRY_RUN` | `false` | 评估策略但不执行已批准命令,适用于提示与策略测试。 |
| `SSH_GUARD_PROMPT_APPEND` | (无) | 附加策略文件路径(追加到基础提示)。 |
| `SSH_GUARD_GPG_ID` | (无) | 用于密钥加密的 GPG 密钥 ID。 |
| `SSH_GUARD_BACKEND` | (自动) | 密钥后端(`file`、`gpg`)。 |
主模型默认通过 OpenRouter 使用 `openai/gpt-5.4-nano`。可通过 `--llm-model ` 在每次调用时单独设置。若要配置真正的跨提供商备用链,请使用 `SSH_GUARD_LLM_MODELS`(逗号分隔)或 `--llm-models`。`--llm-timeout <秒>` 控制每次调用的 HTTP 超时。
请参阅 [`.env.example`](.env.example) 获取可复制模板。
## 示例
### 基础只读模式服务器
启动 Guard 服务器并通过它执行命令:
```
export SSH_GUARD_LLM_API_KEY="sk-or-v1-..."
guard server start --socket .cache/guard.sock &
guard config set-server .cache/guard.sock
# 允许:常规检查
guard run hostname
# guard-host
guard run ps aux
# USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND
# root 1 0.0 0.0 4624 3456 ? Ss 10:00 0:00 /sbin/init
# 拒绝:破坏性操作
guard run rm -rf /
# DENIED:根文件系统递归删除
# 拒绝:混淆攻击
guard run bash -c 'eval $(echo cm0gLXJmIC8= | base64 -d)'
# DENIED:Base64 解码后的负载通过 eval 管道传输
```
当直接使用 `guard server connect`(而非 `guard run`)时,目标参数会在目标二进制文件后转发:
`guard server connect --socket .cache/guard.sock df -h`。
### 安全模式
安全模式允许可见且有范围的管理操作,同时仍阻止直接读取凭证材料和明显的提升路径:
```
SSH_GUARD_MODE=safe guard server start --socket .cache/guard.sock &
# 允许:常规检查和工件文件
guard run cat /etc/hosts
# 127.0.0.1 localhost
guard run cp README.md .cache/readme-copy
# copied
# 拒绝:凭证材料
guard run cat /app/.env
# DENIED:凭证材料读取
# 仍被拒绝:权限提升
guard run sudo su
# DENIED:提升至 root shell
```
### 偏执模式用于不可信代理
偏执模式锁定为基本只读检查:
```
SSH_GUARD_MODE=paranoid guard server start --socket .cache/guard.sock &
# 允许:基本系统状态
guard run id
# uid=1000(agent) gid=1000(agent) groups=1000(agent)
guard run df -h
# Filesystem Size Used Avail Use% Mounted on
# /dev/sda1 100G 45G 55G 45% /
# 拒绝:文件读取
guard run cat /etc/passwd
# DENIED:文件读取在 paranoid 模式下被阻止
# 拒绝:环境检查
guard run env
# DENIED:环境变量转储在 paranoid 模式下被阻止
```
### 静态拒绝策略
对已知不良模式进行快速拒绝而无需调用 LLM,可添加静态拒绝策略:
```
guard server start --policy examples/deny-policy.yaml --socket .cache/guard.sock &
```
静态模式会优先检查。如果命令匹配拒绝模式,会立即拒绝而无需调用 LLM。通过的策略随后才会进入 LLM 评估。
请参阅 [`examples/deny-policy.yaml`](examples/deny-policy.yaml) 获取参考策略及其对静态通配符匹配的已知限制。
### 自定义系统提示
完全替换特定部署的内置提示:
```
guard server start --system-prompt /etc/guard/my-prompt.txt --socket .cache/guard.sock &
```
或者将提示文件放置在 `~/.config/guard/system-prompt.txt` 以自动覆盖。
### 附加式提示
在不替换内置提示的前提下追加环境特定说明:
```
# 通过 CLI 标志
guard server start --system-prompt-append /etc/guard/extra-rules.txt &
# 或通过环境变量
SSH_GUARD_PROMPT_APPEND=/etc/guard/extra-rules.txt guard server start &
```
附加式提示示例(`extra-rules.txt`):
```
Additional rules for this environment:
- This server runs a PostgreSQL database. Allow SELECT queries via psql but deny DROP, DELETE, or TRUNCATE.
- The /opt/app directory contains the application. Allow reads but deny writes.
- Allow docker ps and docker logs but deny docker exec, docker run, and docker rm.
```
附加式提示会追加到当前激活的基础提示(默认、安全、偏执或自定义),允许操作员在不维护完整提示分支的情况下自定义行为。
## 代理集成
将代理的命令执行指向 `guard run`,而不是直接执行。
### MCP 服务器
Guard 可以作为 stdio MCP 服务器运行,因此代理调用工具而非直接调用 Shell:
```
guard config set-server ~/.guard/guard.sock
guard mcp serve
```
该服务器公开 `guard_run` 工具:
```
{
"binary": "ps",
"args": ["aux"]
}
```
响应:
```
{
"allowed": true,
"reason": "Read-only process listing",
"exit_code": 0,
"stdout": "USER PID ...",
"stderr": null
}
```
拒绝的命令会返回 `isError: true` 以及拒绝原因,以便代理可以修改命令。
## 安全模型
Guard 通过三层纵深防御提供安全保障:
1. **环境隔离**(`env_clear`):子进程仅继承安全的环境变量(`PATH`、`HOME`、`USER`、`LANG`、`TERM` 等)。执行的命令无法访问 API 密钥和机密。
2. **输出脱敏**:已知的密钥值(API 密钥、认证令牌、工具密钥)会在返回给代理之前从标准输出/标准错误中精确匹配脱敏。正则表达式可捕获 `*_TOKEN`、`*_KEY`、`*_SECRET`、`*_PASSWORD`、PEM 块和 JWT。
3. **LLM 评估**:对每个命令分析破坏性意图、权限提升、反向 Shell、混淆载荷、工具旁路滥用和提示注入。LLM 会评估包含所有链式部分的完整命令。
## 审计日志
Guard 通过 `tracing` 记录所有决策。可通过 `RUST_LOG` 配置日志级别:
```
RUST_LOG=info guard server start # decisions + token usage
RUST_LOG=debug guard server start # verbose request/response logging
```
LLM 令牌使用情况会在每次评估中记录:
```
[LLM_USAGE] model=openai/gpt-5.4-nano attempt=1 prompt_tokens=3594 completion_tokens=47 total_tokens=3641 status=ok
```
## 限制
- **不是沙箱。** Guard 是策略门控,而非隔离边界。在对抗性环境中仍需要深度防御(seccomp、只读文件系统、受限用户、网络分段)。
- **不支持交互会话。** 代理仅能获得命令执行能力。
- **LLM 延迟。** 每个命令会增加约 0.5–2 秒的 LLM 调用延迟。
- **失败关闭。** 如果 LLM 调用失败或返回不可解析的输出,命令将被拒绝。
## 许可证
MIT
Claude Code (CLAUDE.md)
``` # 命令执行 Use the guard MCP server for all command execution. Never use interactive sessions. ```OpenHands / SWE-Agent
``` export SSH_GUARD_LLM_API_KEY="..." export SSH_GUARD_MODE=default alias ssh=guard ```LangChain / CrewAI 工具定义
``` SSH_GUARD_MODE=paranoid guard server start --socket .cache/guard.sock & # 允许:基本系统状态 guard run id # uid=1000(agent) gid=1000(agent) groups=1000(agent) guard run df -h # Filesystem Size Used Avail Use% Mounted on # /dev/sda1 100G 45G 55G 45% / # 拒绝:文件读取 guard run cat /etc/passwd # DENIED:文件读取在 paranoid 模式下被阻止 # 拒绝:环境检查 guard run env # DENIED:环境变量转储在 paranoid 模式下被阻止 ```标签:AI 代理防护, AI 工具链, Cargo, JSONLines, LLM 安全, OpenRouter, Rust, SSH 安全, 入侵预防, 可视化界面, 命令过滤, 提示注入防御, 服务端守护进程, 权限控制, 源代码安全, 生产环境保护, 策略审计, 系统命令审计, 网络流量审计, 通知系统, 零信任