内容
# prescryb - 修复编排器
修复编排器,以MCP服务器形式暴露。指向一个MCP客户端(Claude Desktop,Claude Code等)并以对话方式询问:
> 登录到主机 a.b.c,检查已安装的软件包,查找CVE,并建议修复 - 如果可能使用Ansible,并告诉我它映射到哪些合规控制。
`prescryb` 提供基本功能(SSH库存,CVE匹配,实时顾问查找,合规主题映射,Ansible剧本渲染)。连接的模型负责推理:哪些发现很重要,哪些CVE需要深入研究,哪些剧本需要生成。`prescryb` 绝不会对目标主机应用任何操作 - 所有工具都只读或纯文本/数据生成。
## 工作原理
| 工具 | 功能 |
| --- | --- |
| `inventory_host(host, user="", port=22, hostname="", identity_file="", trust_unknown_host=False)` | SSH登录,检测发行版,列出已安装的软件包及其版本。 |
| `check_cves(system, packages)` | 批量匹配软件包版本与 [OSV.dev](https://osv.dev) 的生态系统感知版本比较(非仅名称匹配)。 |
| `fetch_advisory(cve_id)` | 获取当前NVD记录,包含CVE描述、CVSS、CWE、引用等 - 实时,非训练数据。 |
| `map_compliance(area)` | 将自由文本主题(`"ssh"`、`"sudo"`、`"kernel modules"`等)映射到CIS/DISA STIG主题区域和(如果在`konstruktoid.hardening` GitHub仓库中存在)匹配的角色 - 以及MITRE ATT&CK技术和缓解措施。 |
| `lookup_cce(target, keyword, cve_id)` | 查询 [NIST CCE](https://ncp.nist.gov/cce) (通用配置枚举)条目,适用于平台(例如`"rhel8"`),来源于社区JSON转换,位于 [`konstruktoid/cce-web`](https://github.com/konstruktoid/cce-web)。 |
| `list_cce_targets()` | 列出所有`lookup_cce`可以查询的平台。 |
| `generate_playbook(system, cve_matches, compliance_areas, hosts_alias)` | 渲染一个**仅建议**的Ansible剧本:CVE修复变为软件包升级任务,合规区域变为`roles:`引用。 |
典型流程:`inventory_host` → 在返回的软件包上调用 `check_cves` → 可选地对有趣的CVE调用 `fetch_advisory` → 调用 `map_compliance`(和 `lookup_cce`)以获取任何发现的不安全配置区域 → 调用 `generate_playbook` 以生成供审查的内容。
## 安装
```console
uv sync
```
### 在MCP客户端中注册
Claude Code:
```console
claude mcp add prescryb -- uv --directory /path/to/prescryb run prescryb
```
Claude Desktop(`claude_desktop_config.json`):
```json
{
"mcpServers": {
"prescryb": {
"command": "uv",
"args": ["--directory", "/path/to/prescryb", "run", "prescryb"]
}
}
}
```
## SSH身份验证模型
`inventory_host` 绝不接受密码参数。MCP工具调用参数可以被客户端记录并对连接的模型可见,因此凭证绝不能通过它们流动。身份验证方式与您自己运行`ssh host`的方式完全相同:
- 主机/用户/端口/身份文件从`~/.ssh/config`解析。
- 密钥来自SSH代理或默认身份文件。
- `inventory_host`的`hostname`/`identity_file`参数直接覆盖解析的地址/密钥路径,用于您不想添加到`~/.ssh/config`的主机(仅传递路径,从不传递密钥内容)。
- 除非您传递`trust_unknown_host=True`,否则未知主机密钥会被**拒绝** - 建议手动运行`ssh host`一次以固定密钥。
## 示例:运行claude对抗仓库Vagrant VM
```console
claude 'run vagrant up, connect to the created VM, check any vulnerabilities and suggest a fix, include compliance mapping if possible, write the playbook suggestion to /tmp/ and print the file location'
```
## 示例:检查常规主机
对于已经可以通过`ssh`访问的主机(通过`~/.ssh/config`解析,通过代理密钥或默认身份文件),只需命名它 - 无需端口或身份文件操作:
> 库存 prod-web-01,检查已安装的软件包,查找CVE,并建议修复 - 如果可能使用Ansible,并告诉我它映射到哪些合规控制。
如果主机尚不在`~/.ssh/config`中,可以添加一个`Host`块或直接将`user`/`port`/`hostname`/`identity_file`传递给`inventory_host`进行一次性连接 - 与下面的molecule示例相同。
## 示例:检查molecule测试实例
```console
molecule converge -s default
```
从该场景的`molecule.yml`平台条目(例如`ssh_port: 22201`,`ssh_user: almalinux`适用于`almalinux10`平台)查找`ssh_port`/`ssh_user`,以及`molecule login`用于连接的私钥 - 可以在`~/.ssh/config`中添加一个`Host`块,或者完全跳过该文件,直接将它们传递给`inventory_host`进行一次性、短暂的连接:
> 库存 127.0.0.1,端口 22201,用户 almalinux,身份文件 /path/to/molecule's/generated/key,检查已安装的软件包,查找CVE,并建议修复 - 如果可能使用Ansible,并告诉我它映射到哪些合规控制。
运行完成后调用`molecule destroy -s default` - `prescryb`不会为您执行此操作,也不会在读取实例之外对其进行任何操作。
## 合规映射
`map_compliance` 命名主题区域(例如“SSH服务器配置”),如果在 [`konstruktoid/ansible-collection-hardening`](https://github.com/konstruktoid/ansible-collection-hardening) GitHub仓库中找到,则链接到实现它的Ansible角色。
默认情况下,它查询GitHub API以获取 [`konstruktoid/ansible-collection-hardening`](https://github.com/konstruktoid/ansible-collection-hardening)。覆盖它:
```console
export HARDENING_COLLECTION_REPO=owner/repo
```
设置 `GITHUB_TOKEN` 以提高(原本较低的)未经身份验证的GitHub API速率限制。如果在仓库中找不到角色,`map_compliance` 仍然返回主题/框架/角色名称,以便您知道要安装什么(`ansible-galaxy collection install konstruktoid.hardening`)。
## CCE查找
`lookup_cce` 查找 [NIST通用配置枚举](https://ncp.nist.gov/cce) 条目 - 各个配置检查的唯一标识符,与上述主题区域CIS/DISA STIG映射不同。NIST仅发布CCE作为电子表格,因此它读取由社区项目 [`konstruktoid/cce-web`](https://github.com/konstruktoid/cce-web) 托管的预转换JSON导出,而不是解析Excel。
覆盖范围按平台而非主题划分,对于该项目的目标发行版而言非常薄:只有RHEL系列(`rhel6`/`rhel7`/`rhel8` - AlmaLinux/Rocky使用匹配的上游RHEL编号)和SUSE(`SLES12-DISA-STIG`/`SLES15-DISA-STIG`/`SLES15-PCI-DSS`)有可用的数据。Debian、Ubuntu、Alpine和Arch完全没有上游CCE数据。一些较旧的`cce-web`导出(例如`rhel4`、`rhel5`、`apache-httpd2.2`)在其Excel到JSON转换中丢失了列标题;这些被报告为不受支持,而不是返回混乱的字段。调用 `list_cce_targets` 以查看所有已发布的平台,包括非Linux平台(`firefox`、`win2k8r2`等)。
覆盖源仓库:
```console
export CCE_REPO=owner/repo
```
## MITRE ATT&CK 映射
除了CIS/DISA STIG之外,`map_compliance` 和 `generate_playbook` 还引用了 [MITRE ATT&CK](https://attack.mitre.org) 技术(由主题区域的强化缓解,例如“ssh”→ `T1110` 暴力破解,`T1021.004` 远程服务:SSH)和(如果ATT&CK定义了)相应的缓解措施(例如 `M1032` 多因素身份验证),并附上到 attack.mitre.org 的链接。与 CIS/DISA STIG 规则编号不同,ATT&CK 技术和缓解措施 ID 是 MITRE 自己的公共目录,因此直接引用它们,而不是需要许可的基准查找。此映射是静态的(内置于 `attack.py`),而非实时获取。
## CVE数据源及其限制
- **OSV.dev** 是唯一的CVE匹配源。它在服务器端将 `{name, ecosystem, version}` 与生态系统的实际版本排序进行解析,因此匹配反映了确切的已安装版本,而不仅仅是“任何提及此软件包名称的CVE”。对于 **Debian、Ubuntu、Alpine** 来说,覆盖范围已经成熟;对于RHEL系列(AlmaLinux、Rocky)和SUSE来说,覆盖范围较薄。`check_cves` 返回一个 `warning` 字段,标记覆盖范围较薄的生态系统,如果没有生态系统映射,则返回空结果而不是猜测 - 空结果意味着“未检查”,而不是“干净”。
- **NVD** (`fetch_advisory`)仅用于丰富您已经拥有CVE ID的CVE。设置 `NVD_API_KEY` 以提高(原本较低的)未经身份验证的速率限制。
- 严重性:OSV提供原始的CVSS矢量字符串(`cvss_vector`),而非预先计算的标签,对于大多数OS软件包条目。如果源明确标记严重性,则仅填充 `severity`;否则,它为“UNKNOWN”,矢量留给您(或模型)解释,而不是猜测。
## 剧本生成
输出始终是一个完整的剧本,以文本形式呈现,并带有注释头,引用每个CVE/合规源。它绝不会被 `prescryb` 执行。请在任何地方运行之前审查它 - `ansible-playbook --syntax-check`,然后 `--check --diff`。
软件包升级任务使用目标软件包管理器的模块(`ansible.builtin.apt`/`dnf`/`zypper`/`community.general.apk`)。仅在模块支持的地方应用版本固定;Arch/pacman目标获取 `state: latest`,因为pacman不支持相同的固定语法。
## 环境变量
| 变量 | 默认值 | 目的 |
| --- | --- | --- |
| `HARDENING_COLLECTION_REPO` | `konstruktoid/ansible-collection-hardening` | GitHub `owner/repo` 查询以获取与合规映射的Ansible角色。 |
| `CCE_REPO` | `konstruktoid/cce-web` | GitHub `owner/repo` 查询以获取CCE JSON导出,由 `lookup_cce`/`list_cce_targets` 查询。 |
| `GITHUB_TOKEN` | 未设置 | 提高 `map_compliance`、`lookup_cce` 和 `list_cce_targets` 的GitHub API速率限制。 |
| `NVD_API_KEY` | 未设置 | 提高 `fetch_advisory` 的NVD API速率限制。 |
## 本项目故意不具备的功能
- 不应用剧本或以其他方式修改目标主机。
- 不接受密码作为工具参数。
- 不伪造CIS/DISA STIG规则编号。
- 不为OSV未覆盖的生态系统猜测CVE - 而是说明。