Agent 做运维,不给 shell。

allowops 是面向 AI agent 的开源运维网关。你在目录里定义带类型的动作,评审后签名;agent 通过 MCP 只能调用这些动作。网关逐台主机做策略判定、分批执行,并记录审计。

Claude Code→disk_usage Codex→journal_grep CLI→k8s_pods
版本 v0.1.0 · 开源 · MIT 许可 · 网关和主机端支持 Linux amd64 · 文档

接入方式

MCP 客户端allowops CLIWeb 控制台CI 发布流水线

示例目录覆盖的动作(51 个)

systemdjournaldDockerKubernetesMySQLRedisNginxJVM磁盘进程端口与连接DNS日志搜索crontab内核日志

工作原理

一个网关,挡在 agent 和主机之间。

agent、CLI 和控制台都只连网关。网关认证每个请求,按标签选择主机,对每台目标做策略判定,再分批下发。主机主动连接网关,不开放入站端口。

调用方
Claude CodeMCP
CodexMCP
allowops CLIConnect
Web 控制台HTTPS
CI发布签名目录
→
allowops 网关
:443 · TLS + ALPN
认证 · OIDC / LDAP / 服务账号
ABAC 策略判定
分批调度与失败阈值
审计哈希链
←
主机
demo-1environment=demo
demo-2environment=demo
demo-3environment=demo
demo-4未打标签
主机主动连接 · 双向 TLS
actions/docker_stop.yamlwrite
name: docker_stop
description: Stop one allowed application container.
risk: write
run_as: root
params:
  container:
    type: enum
    values: [api, app]
  grace_seconds:
    type: int
    min: 0
    max: 30
    default: 10
exec: [/usr/bin/docker, stop, --time,
       '{grace_seconds}', '{container}']
timeout: 45s
max_output: 16KB
batch_size: 1
max_failures: 1

动作目录

命令写在目录里,不在提示词里。

每个动作是一段固定的参数数组和一组带类型的参数。agent 只能填参数,不能拼命令。主机从签名目录取命令,不接受 agent 或网关传来的命令字符串。

类型参数:enum、int、string(RE2 正则)、duration、path、url。未知字段和类型错误直接拒绝。
固定 argv:只有整个元素等于 {参数名} 时才替换;以 - 开头的值被拒绝。
风险等级:read、write、dangerous 作为策略属性参与判定。
资源上限:超时、输出上限、扫描上限、批大小和失败阈值写进签名,调用方只能调小。

签名发布

主机只执行你签过名的目录。

目录在 CI 里校验、构建,用 Ed25519 签名(DSSE 信封)后发布。公钥由你分发到网关和每台主机;网关不能替主机添加或吊销公钥。

01

校验与试运行

检查字段、参数类型和路径约束;在受控的测试主机上用当前用户试运行。

allowops catalog validate ./catalog
02

构建与签名

构建产物记录 Git commit 和 UTC 版本号,私钥只放在 CI 的凭据库里。

allowops catalog sign --in catalog.json …
03

发布与验签

网关接收发布,主机 agent 和 root 辅助程序在执行前各自独立验签。

allowops catalog publish -f catalog.dsse.json

策略

每台目标主机,逐一过策略。

网关内嵌 OPA,规则是结构化数据,不是任意 Rego。拒绝优先;没有匹配或判定出错都按拒绝处理。任一目标被拒绝或数量不符,整个请求在下发前被拒绝。

同一个服务账号对 environment=demo 的三台主机发起调用。切换场景查看网关的判定。

// tools/call → disk_usage
{
  "targets": { "selector": "environment=demo" },
  "expected_count": 3,
  "reason": "巡检 demo 磁盘"
}
rules:
  - name: readers-on-demo
    effect: allow
    roles: [ops-reader]
    operations: [execute_action]
    risks: [read]
    host_labels: { environment: demo }
  - name: deny-writes-on-demo
    effect: deny
    roles: ['*']
    operations: [execute_action]
    risks: [write, dangerous]
    host_labels: { environment: demo }
demo-1environment=demoreaders-on-demo允许
demo-2environment=demoreaders-on-demo允许
demo-3environment=demoreaders-on-demo允许
{ "job_id": "job-20261022-0010", "status": "succeeded",
  "total": 3, "counts": { "succeeded": 3 },
  "output_trust": "untrusted" }
// tools/call → docker_stop
{
  "targets": { "selector": "environment=demo" },
  "expected_count": 3,
  "reason": "按用户要求停止 api 容器",
  "params": { "container": "api" }
}
rules:
  - name: readers-on-demo
    effect: allow
    roles: [ops-reader]
    operations: [execute_action]
    risks: [read]
    host_labels: { environment: demo }
  - name: deny-writes-on-demo
    effect: deny
    roles: ['*']
    operations: [execute_action]
    risks: [write, dangerous]
    host_labels: { environment: demo }
demo-1environment=demodeny-writes-on-demo拒绝
demo-2environment=demodeny-writes-on-demo拒绝
demo-3environment=demodeny-writes-on-demo拒绝
{ "reason": "JOB_DENIED", "denied_count": 3,
  "denied_hosts": ["demo-1", "demo-2", "demo-3"] }
// tools/call → disk_usage
{
  "targets": { "selector": "environment=demo" },
  "expected_count": 2,
  "reason": "巡检 demo 磁盘"
}
rules:
  - name: readers-on-demo
    effect: allow
    roles: [ops-reader]
    operations: [execute_action]
    risks: [read]
    host_labels: { environment: demo }
  - name: deny-writes-on-demo
    effect: deny
    roles: ['*']
    operations: [execute_action]
    risks: [write, dangerous]
    host_labels: { environment: demo }
demo-1environment=demoreaders-on-demo允许
demo-2environment=demoreaders-on-demo允许
demo-3environment=demoreaders-on-demo允许
{ "reason": "EXPECTED_COUNT_MISMATCH", "actual_count": 3 }
// tools/call → disk_usage
{
  "targets": { "hosts": ["demo-4"] },
  "reason": "巡检 demo 磁盘"
}
rules:
  - name: readers-on-demo
    effect: allow
    roles: [ops-reader]
    operations: [execute_action]
    risks: [read]
    host_labels: { environment: demo }
  - name: deny-writes-on-demo
    effect: deny
    roles: ['*']
    operations: [execute_action]
    risks: [write, dangerous]
    host_labels: { environment: demo }
demo-4—没有授权标签拒绝
{ "reason": "JOB_DENIED", "denied_count": 1,
  "denied_hosts": ["demo-4"] }

拒绝优先

一条 deny 规则匹配就拒绝,与 allow 规则的顺序无关。

网关管理的标签

授权标签由运维人员在网关设置。主机上报的标签只能筛选,不能授权。

数量核对

按选择器调用必须带 expected_count,实际数量不同就整体拒绝。

时间窗口与来源网段

规则可以限定时区内的时间段和来源 CIDR,读和写用不同账号。

控制台

主机、目录、job、审计,在一个控制台里查看。

控制台和 CLI、MCP 使用同一套接口和权限。下面是本地演示环境的真实截图。

概览

在线主机、运行中的 job、即将到期的目录和 token。

细节

执行之后,也有边界。

主机端脱敏

输出离开主机前先脱敏,再过滤和截断。默认规则覆盖常见密钥格式,可以自定义正则。

输出按不可信处理

MCP 结果带 output_trust: untrusted。主机输出可能含提示注入,不作为指令。

审计哈希链

审计记录判定、标识和输出哈希,不存输出正文。导出文件可以用 audit verify 校验。

主机主动连接

主机不开放入站端口。注册时固定网关 CA,之后使用双向 TLS 和短期主机证书。

低权限执行

agent 以 allowops 用户运行。需要 root 的动作经固定 sudo 规则调用 allowops-exec,执行前再次验签。

分批与失败阈值

按 batch_size 分批执行;失败数超过 max_failures 后跳过剩余主机。离线主机不排队补跑。

快速开始

在本机起一套完整演示。

Compose 演示包含网关、PostgreSQL、SeaweedFS、LDAPS 目录和两台主机。脚本在本地生成凭据,发布示例目录,并在两台主机上运行只读的 disk_usage。

$git clone https://github.com/liubing0806/allowops.git && cd allowops/deploy/compose && ./quickstart-local.sh

需要 Linux amd64、Docker Compose、Go 1.27.3、OpenSSL、Git 和带 PyYAML 的 Python 3。Kubernetes 用 Helm chart,主机安装 .deb 或 .rpm,见安装文档。

# 定义并发布目录
allowops catalog validate ./catalog
allowops catalog build --dir ./catalog --out catalog.json
allowops catalog sign --in catalog.json --out catalog.dsse.json --key "$KEY_FILE"
allowops catalog publish -f catalog.dsse.json

# 给主机设置授权标签,未打标签的主机拒绝执行
allowops hosts label demo-1 --set environment=demo

# 先试算策略,再整体替换
allowops policy test -f rules.yaml
allowops policy apply -f rules.yaml --reason '允许只读账号访问 demo'

# 在终端里运行同一个动作
allowops run disk_usage --selector environment=demo --expected-count 3 --reason '巡检磁盘'
allowops jobs output job-20261022-0010 --host demo-1 --stream stdout
在 GitHub 提问题和建议MVP 阶段接受 issue 和建议,暂不接受外部代码贡献。 →

不给 shell,只给你定义的动作。

开源(MIT)、自托管。网关、主机 agent 和 CLI 来自同一个版本。

版本 v0.1.0