把服务器 BMC 交给 AI agent,但不把电源键交出去
2026-10-12 · rackhands 怎样读取 Dell iDRAC、HPE iLO、Lenovo XCC、Supermicro 和通用 Redfish,在需要时回退到 IPMI,并把危险操作锁在“两把钥匙加签字”之后。
问题在哪
BMC 是一台服务器权限最高的接口。告诉你风扇快坏了的那个 Redfish 端点,只要一个 POST,也能把数据库主机硬关机。把 AI agent 接进运维时,有用的是读:健康状态、传感器、硬件事件日志、固件版本。危险的能力却和读权限装在同一个账号里。直接给 agent 一个 ipmitool 或 curl,“看看风扇”和 chassis power off 之间就没有任何阻隔。
第二个问题是厂商差异。“读取硬件事件日志”在每家 BMC 上都是不同的 URL、不同的严重级别字段。让 agent 现场拼 Redfish 请求,很容易出错;大多数脚本也一样。
rackhands 是一个 Go 静态二进制,同时是 CLI 和 MCP 服务器。读操作在各厂商之间返回统一结构;所有可能让机器宕掉的操作都像金库里的保险箱:两把钥匙都转动、有人在登记簿上签字之前,箱门不开。
两把钥匙,一次只开一个箱
危险操作分成几类:power、boot、bmc-reset、firmware、virtual-media,默认全部关闭。不带 --allow 时 CLI 以退出码 3 拒绝,MCP 服务器干脆不列出这些工具,agent 根本看不到。
打开某一类需要两把相互独立的钥匙:
- 运行时钥匙
--allow power(或RACKHANDS_ALLOW),由启动进程的人决定; - 目标钥匙,即
targets.yaml里该机器的allow: [power],由维护资产清单的人决定。
两边都写了这一类才放行。目标名打错、或者没人给这台机器开过权限,都会在发出任何请求之前被拒绝。危险操作只接受一个具名目标:all、tag:prod 或多个名字都会被拒绝。批量电源操作是刻意不做的功能。
$ rackhands --allow power power db-01 force-off
PLAN power force-off db-01 (Dell PowerEdge R750, ResetType=ForceOff, currently On)
POST /redfish/v1/Systems/System.Embedded.1/Actions/ComputerSystem.Reset {"ResetType":"ForceOff"}
via redfish
Type the target name (db-01) to confirm: db-01
DONE db-01: accepted (HTTP 204)
执行计划会列出确切的方法、路径、请求体、机型和当前状态。确认方式是输入机器名,而不是按 y。脚本里用 --yes db-01,名字同样必须匹配。每一次拒绝、计划、执行和失败都追加写入 JSONL 审计日志。
MCP 确认令牌:执行的就是展示过的
agent 没法在终端里输入机器名,“模型说它问过人了”也算不上控制手段。所以在 MCP 上,危险工具分两步。不带令牌调用时,只返回 {"status":"confirmation_required","plan":…,"confirm_token":…},什么也不执行;服务器指令要求 agent 把计划展示给人并等待确认。带上令牌再次调用,才会执行。
令牌经过 HMAC 签名,有效期两分钟,只能用一次,并绑定目标、类别、动作、参数以及承载请求的协议(Redfish 或 IPMI)。agent 如果把 force-off 改成 cycle、把目标换成 db-02、或者重放昨天的令牌,都会被拒绝,拒绝本身也会写入审计日志。读工具带 readOnlyHint,危险工具带 destructiveHint,会对破坏性工具弹确认的 MCP 客户端还能再加一道闸。
推荐的部署很简单:给 agent 的配置使用 BMC 只读账号,给人用的高权限配置单独存放。两把钥匙是第二道防线,不是第一道。
会改变正确答案的厂商差异
Redfish 是标准,但每家厂商的理解都略有不同。下面这些差异都已编码进 rackhands,每一条都有 mockup 和单元测试:
| 厂商 | 差异 |
|---|---|
| Dell iDRAC 8/9 | 硬件日志是 Sel,Lifecycle 日志另算。健康状态要加上 DellSystem 子系统汇总。固件清单里有 Previous-、Available- 副本,需要隐藏。 |
| HPE iLO 4/5/6 | 健康状态在 Oem.Hpe(iLO 4 为 Oem.Hp)的 AggregateHealthStatus。IML 严重级别在 Oem.Hpe.Severity,条目不一定内联。Manager.Reset 不能带 ResetType。未设置的阈值读出来是 0。虚拟介质走 OEM 动作。 |
| Lenovo XCC/XCC2 | 日志是 PlatformLog。传感器可能只在 Sensors 集合里。每个 PATCH 都必须带 If-Match,否则 XCC 拒绝。 |
| Supermicro X11+ | 日志是 manager 下的 Log1。部分 X11 主板的虚拟介质只有 OEM 接口,rackhands 会提前报告不支持,而不是做到一半失败。 |
电源动作会映射到 BMC 在 @Redfish.AllowableValues 里声明的值,而不是假定所有 BMC 都接受 GracefulRestart。单位和严重级别统一(OK / Warning / Critical),事件时间统一为 UTC。
IPMI 回退,以及什么时候不该回退
老主板和很多家庭实验室机器只支持 IPMI 2.0。rackhands 内置纯 Go 的 lanplus 客户端(不依赖 ipmitool),支持 FRU 资产信息、阈值传感器、SEL、机箱电源、启动设备和 BMC 冷重启。同时配置 redfish: 和 ipmi: 时先走 Redfish,服务不可达或返回 404、501、503 时回退到 IPMI。遇到 401、403 绝不回退:密码错了应该去修,而不是悄悄换个协议掩盖过去。结果中会标明 via: ipmi (fallback) 和回退原因。
这周的一个教训:很多 IPMI 客户端建立 lanplus 会话前,会先向 BMC 询问支持哪些加密套件(Get Channel Cipher Suites)。有些 BMC 和某些 ipmi_sim 版本根本不回应这个命令,于是每个会话都要先卡满五次超时。现在 rackhands 直接提供几乎所有 BMC 都支持的套件 17 和 3,CI 也会断言 IPMI 会话能快速建立。
没有机架,怎么测 BMC 工具
单元测试通过一个进程内 Redfish 服务器回放各厂商 mockup(Dell R750、HPE DL380 Gen10、Lenovo SR650 V2、Supermicro X11),并记录每一次写操作,因此可以断言“这个 PATCH 带了 If-Match”或“拒绝之后什么都没发出去”。CI 再用真实二进制去跑 DMTF Redfish-Mockup-Server(加载上述 mockup 和 DMTF 的 public-rackmount1),以及通过真实 RMCP+ 会话连接 OpenIPMI ipmi_sim。MCP 服务器则通过 stdio 走完整的 计划 → 令牌 → 执行 流程。新的厂商差异一律先加 mockup,再写代码,再补测试。
上手
$ go install github.com/Blackman99/rackhands/cmd/rackhands@latest $ rackhands --host https://10.20.0.11 --user root health
也可以从 GitHub Releases 下载 Linux、macOS、Windows 的二进制。文档(英文)涵盖 targets.yaml、全部命令和 MCP 配置。如果你的 BMC 表现不同,欢迎提 issue 并附上脱敏的 Redfish 抓包。刻意不做的事情:BIOS 设置、RAID、BMC 账号管理、KVM/SOL,以及批量危险操作(见 GOAL.md)。