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` 以及拒绝原因,以便代理可以修改命令。
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 模式下被阻止 ```
## 安全模型 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
标签:AI 代理防护, AI 工具链, Cargo, JSONLines, LLM 安全, OpenRouter, Rust, SSH 安全, 入侵预防, 可视化界面, 命令过滤, 提示注入防御, 服务端守护进程, 权限控制, 源代码安全, 生产环境保护, 策略审计, 系统命令审计, 网络流量审计, 通知系统, 零信任