首页 / 资讯中心 / 文章详情

OpenShell 智能体运行时安全治理:策略引擎、进程隔离与审计实践

OpenShell 智能体运行时安全治理:策略引擎、进程隔离与审计实践 ★ FEATURED ARTICLE
1. 从零认识 OpenShell它到底解决什么问题第一次听到 OpenShell 这个名字很多人会下意识以为它又是一个新的命令行工具或者某种容器运行时。实际上OpenShell 是一个面向 AI 智能体Agent的运行时安全与治理框架核心目标只有一个让 AI 智能体在真实系统里干活的时候既能放开手脚又不会闯祸。你可以把它理解成给智能体套上的一层“可编程护栏”——它规定了智能体能碰什么文件、能访问什么网络、能调用什么工具、能花多少预算并且在越界的时候直接拦截。我接触 OpenShell 的契机很实际。去年我在做一个自动化运维助手让模型去读日志、改配置、重启服务。测试环境跑得好好的结果有一次它把生产环境的一个配置文件给覆盖了原因只是模型“觉得”那个配置写错了。那次事故之后我意识到光靠提示词里写“不要动生产环境”是没用的模型该动手还是会动手。真正靠谱的做法是在模型和系统之间加一层强制性的策略执行层OpenShell 就是干这个的。它适合谁三类人最该关注。第一类是正在做 Agent 产品的开发者尤其是那些让智能体直接操作文件系统、数据库、云资源的场景第二类是企业里负责 AI 平台安全的工程师需要给多个智能体统一配置权限边界第三类是研究智能体可靠性的同学想找一个可观测、可干预的运行时环境来做实验。哪怕你只是用智能体帮自己整理文件、跑跑脚本OpenShell 也能帮你避免“手滑删库”这种灾难。需要先说明的是OpenShell 目前并不是一个已经高度标准化的单一产品不同团队、不同项目里叫这个名字的东西可能指代不同的实现。本文讨论的是当前业界最主流的那一类形态一个以策略文件为核心、以进程隔离和系统调用拦截为手段、以审计日志为输出物的智能体运行时治理层。下面所有内容都基于这个定位展开如果你手上的 OpenShell 是别的形态思路可以借鉴具体配置需要对照官方文档调整。2. 整体设计思路为什么要在模型外面再包一层2.1 智能体安全的本质是“最小权限”问题传统软件的安全模型很清晰一个进程需要什么权限就在启动时声明操作系统负责执行。但智能体不一样它的行为是运行时动态决定的模型在每一步都可能产生新的意图。你没法在启动前就知道它今天会不会去读/etc/passwd会不会往某个外部地址发请求。这就导致传统的静态权限模型对智能体几乎失效。OpenShell 的设计哲学是把“意图”和“能力”彻底分开。模型负责产生意图OpenShell 负责决定这个意图能不能被执行。具体来说它把智能体可能用到的所有能力抽象成几类资源文件系统路径、网络端点、可执行命令、环境变量、以及外部工具调用。每一类资源都用声明式的策略描述允许或拒绝策略在智能体启动时加载运行期间不可被模型修改。这个“不可被模型修改”是关键很多早期方案失败就失败在策略存在模型能读到的地方模型会想办法绕过。2.2 为什么选择进程隔离而不是纯提示词约束我见过不少团队一开始图省事只在系统提示词里写一堆“禁止访问敏感目录”“禁止执行危险命令”。实测下来这种做法的拦截率大概只有六七成遇到模型“钻空子”或者多轮对话里上下文被污染的情况基本就失效了。原因很简单提示词是软约束模型可以选择不遵守而且它没有能力真正判断某个操作是否危险。OpenShell 走的是硬约束路线。它把智能体运行在一个受限的进程环境里所有系统调用在到达内核之前先经过策略引擎。文件读写走的是挂载命名空间网络访问走的是网络命名空间加策略路由命令执行走的是白名单加参数校验。模型即使“想”干坏事系统调用也会被直接拒绝返回一个权限错误。这种做法的拦截率接近百分之百代价是需要额外的配置工作而且对某些需要动态能力的场景不够灵活。2.3 策略即代码可版本化、可审计、可回滚OpenShell 的策略文件通常是 YAML 或 JSON 格式这意味着它可以进 Git可以走代码评审可以回滚到任意历史版本。这一点在实际运维里价值极大。想象一下某天你发现智能体行为异常第一反应是“它最近改了什么策略”直接git log就能看到。如果策略是散落在各个配置界面里的排查起来就是噩梦。策略文件的结构一般包含几个顶层字段filesystem定义路径白名单和读写权限network定义允许访问的域名或 IP 段exec定义可执行命令及其参数约束resources定义 CPU、内存、磁盘配额audit定义日志输出位置和格式。下面是一个最小可用的策略示例我把它放在项目根目录的openshell.policy.yaml里version: 1 filesystem: read: - /workspace/data/** - /workspace/logs/** write: - /workspace/output/** deny: - /etc/** - /root/** - /home/*/.ssh/** network: allow: - api.internal.example.com:443 - pypi.org:443 deny: - * exec: allow: - python3 - pip - ls - cat deny: - rm - dd - mkfs resources: cpu: 2 memory: 4Gi disk: 10Gi audit: path: /workspace/logs/openshell-audit.jsonl level: info这个策略的意思是只能读工作区里的数据和日志只能写输出目录系统目录一律拒绝网络只允许访问内部 API 和包管理源其他全部拒绝命令只允许 python3、pip、ls、cat删除类命令直接封死资源限制在 2 核 4G所有操作记审计日志。这套配置我用了大半年拦下过好几次模型试图rm -rf临时目录的操作也拦下过它想往外部地址发数据的行为。3. 核心细节拆解策略引擎、隔离机制与审计链路3.1 策略引擎的匹配逻辑与优先级OpenShell 的策略匹配不是简单的“先到先得”而是有一套明确的优先级规则。理解这套规则能帮你避免很多“明明写了允许却被拒绝”的困惑。优先级从高到低依次是显式 deny 显式 allow 默认 deny。也就是说如果一条路径同时出现在 allow 和 deny 里deny 生效。这个设计是刻意的安全场景下永远应该让拒绝优先。路径匹配支持三种模式精确匹配、前缀匹配和通配符匹配。精确匹配就是写死一个路径比如/workspace/config.json前缀匹配用/**结尾比如/workspace/data/**表示 data 目录下所有层级通配符用*匹配单层**匹配多层。这里有个坑我踩过/workspace/*只能匹配/workspace/a匹配不到/workspace/a/b要匹配多层必须用/workspace/**。很多新手在这里写错导致子目录访问被拒。网络策略的匹配稍微复杂一点。它支持域名、IP、CIDR 段和端口组合。域名匹配是精确匹配加子域通配比如api.example.com只匹配这个域名*.example.com匹配所有子域。端口必须显式写出不写端口默认匹配所有端口但出于安全考虑建议总是写端口。CIDR 段用标准写法比如10.0.0.0/8。实测下来域名匹配的性能比 IP 匹配略差因为需要做 DNS 解析如果对延迟敏感可以预先解析成 IP 写进策略。3.2 进程隔离的三种实现路径OpenShell 的隔离能力依赖底层操作系统特性不同平台实现路径不同。在 Linux 上主流做法是组合使用 namespace、seccomp 和 cgroup。namespace 负责视图隔离让智能体看不到宿主机的完整文件系统和网络seccomp 负责系统调用过滤把危险调用直接拦掉cgroup 负责资源限制防止智能体把机器跑满。这三者组合起来基本能做到“智能体以为自己在一台独立机器上实际上被关在笼子里”。在 macOS 上情况要复杂一些因为 macOS 没有 Linux 那样的 namespace。OpenShell 通常退而求其次用 sandbox-exec 配合文件系统权限控制来实现类似效果。sandbox-exec 是 macOS 自带的沙箱工具可以定义一套 profile 来限制进程能做什么。实测下来macOS 上的隔离强度不如 Linux某些系统调用拦不住所以如果你的场景对安全要求极高建议把智能体跑在 Linux 容器里。Windows 上的支持目前最弱主要靠 Job Object 做资源限制文件系统靠 ACL网络靠防火墙规则。这套组合能防住大部分误操作但防不住精心构造的绕过。我的建议是如果非要在 Windows 上跑至少把智能体放在一个独立的低权限用户下并且把敏感目录的 ACL 收紧。3.3 审计日志的字段设计与分析价值审计日志是 OpenShell 最容易被忽视但价值最高的部分。很多人配好策略就不管日志了等到出问题才想起来翻结果发现日志格式看不懂或者关键信息没记。OpenShell 的审计日志通常是 JSONL 格式每行一条记录包含时间戳、会话 ID、操作类型、目标资源、决策结果、以及触发决策的策略规则。一条典型的文件访问日志长这样{ts:2025-03-15T10:23:41.123Z,session:sess_abc123,op:file_read,target:/workspace/data/input.csv,decision:allow,rule:filesystem.read[0],pid:12345} {ts:2025-03-15T10:23:42.456Z,session:sess_abc123,op:file_write,target:/etc/hosts,decision:deny,rule:filesystem.deny[0],pid:12345}第二条记录就是一次被拦截的越权写入。有了这些日志你可以做几件事统计每个会话的越权尝试次数识别行为异常的智能体分析被拒绝最多的资源类型反过来优化策略在事故复盘时精确还原智能体每一步做了什么。我自己的做法是把日志接到一个简单的分析脚本里每天跑一次输出越权尝试的 TOP 10 资源坚持了几个月发现模型最常尝试访问的是/tmp和外部网络地址于是针对性收紧了这两块。4. 实操过程从安装到跑通第一个受控智能体4.1 环境准备与依赖检查在动手之前先确认你的环境满足基本要求。OpenShell 对内核版本有要求Linux 上建议 5.10 以上因为需要较新的 seccomp 和 cgroup v2 支持。检查命令很简单uname -r cat /proc/version如果内核低于 5.10某些隔离特性会降级策略里的部分规则可能不生效。这种情况下要么升级内核要么接受降级后的安全强度。另外确认 cgroup v2 是否挂载mount | grep cgroup2如果没有输出说明还在用 cgroup v1需要在内核启动参数里加systemd.unified_cgroup_hierarchy1并重启。这一步很多人会忽略结果资源限制配了不生效智能体把内存吃满导致宿主机卡死。依赖方面OpenShell 通常需要 Python 3.9 以上、以及几个系统库libseccomp、libcap、libyaml。在 Ubuntu 上一条命令搞定sudo apt-get install -y libseccomp-dev libcap-dev libyaml-dev python3-devmacOS 上用 Homebrewbrew install libseccomp libyamlWindows 上建议直接用 WSL2原生 Windows 的支持不完整很多策略字段会被忽略。4.2 安装 OpenShell 与初始化配置安装方式取决于你拿到的发行形态。如果是 Python 包直接 pippip install openshell-runtime如果是二进制发行版下载对应平台的压缩包解压后把可执行文件放到 PATH 里。安装完成后跑一次版本检查openshell --version接下来初始化配置目录。OpenShell 默认会在~/.openshell/下找策略文件也可以启动时用--policy指定。我习惯把策略放在项目目录里跟代码一起版本控制mkdir -p my-agent/openshell cd my-agent openshell init --dir ./openshell这个命令会生成一个模板策略文件和一个示例审计配置。模板里大部分字段是注释掉的需要你按需打开。我的建议是不要一上来就写复杂策略先用最小策略跑通再逐步收紧。4.3 编写第一份策略并验证语法把前面那个最小策略示例复制到openshell/policy.yaml然后验证语法openshell policy validate --file openshell/policy.yaml如果输出policy is valid说明语法没问题。如果有错误它会指出具体行号和原因。常见的语法错误包括YAML 缩进用了 tab、路径没加引号导致*被解析成别名、端口写成字符串而不是数字。验证通过后可以用--dry-run模式模拟一次策略匹配看看某条路径会不会被允许openshell policy check --file openshell/policy.yaml --op file_write --target /workspace/output/result.json这个命令会输出allow或deny以及命中的规则。我习惯在正式跑智能体之前把几个关键路径都 check 一遍确认策略符合预期。这一步花两分钟能省掉后面半小时的排查。4.4 启动受控智能体并观察审计输出启动智能体的命令通常是openshell run --policy openshell/policy.yaml --audit openshell/audit.jsonl -- python3 agent.py--后面的部分就是你的智能体启动命令。OpenShell 会先加载策略创建隔离环境然后在这个环境里执行你的命令。智能体运行期间所有受控操作都会写进审计日志。你可以另开一个终端实时看日志tail -f openshell/audit.jsonl | jq .jq会把 JSON 格式化看起来清楚很多。如果看到decision: deny的记录说明有操作被拦截了需要判断是策略写太严还是智能体行为异常。我一般会先看被拒的资源是不是真的不该访问如果是就保持拒绝如果是误伤就调整策略。4.5 参数计算资源配额怎么定才合理资源配额定太松等于没定定太紧智能体跑不起来。我的经验是按智能体类型分档。纯文本处理的智能体CPU 1 核、内存 2G 基本够用涉及模型推理的CPU 2 到 4 核、内存 8G 起步涉及大规模数据处理的按数据量估算一般每 GB 数据预留 1G 内存和 0.5 核 CPU。磁盘配额要特别注意临时文件。很多智能体在运行过程中会往/tmp写中间结果如果磁盘配额只算了输出目录临时文件会把配额撑爆。我的做法是给/tmp单独设一个上限比如 2G并且在策略里允许写/tmp但限制大小。OpenShell 的磁盘配额是按挂载点算的所以需要把/tmp挂成一个独立的 tmpfs 并设 size 限制。网络带宽一般不用特别限制除非智能体涉及大量下载。如果确实需要限速可以在网络策略里加bandwidth字段单位是 Mbps。我实测过一个下载型智能体不限速的时候能把公司出口带宽跑满限到 50Mbps 之后对任务完成时间影响不大但对其他服务友好很多。5. 常见问题与排查技巧实录5.1 策略明明写了允许为什么还是被拒这是最高频的问题九成以上的原因是路径匹配写错了。前面提过*和**的区别这里再强调一次/workspace/*只匹配一层/workspace/**匹配所有层级。如果你写的是/workspace/data/*然后智能体去读/workspace/data/sub/file.txt就会被拒。解决办法是把*改成**或者把路径写得更具体。第二个常见原因是大小写。Linux 文件系统区分大小写策略里的路径必须和实际路径完全一致。我见过有人策略里写/Workspace/Data实际路径是/workspace/data结果全部被拒。第三个原因是符号链接。如果智能体访问的是一个软链接OpenShell 默认按链接指向的真实路径做匹配而不是链接本身的路径。这种情况下要么在策略里写真实路径要么在策略里开启follow_symlinks: false让匹配基于链接路径。排查方法很简单用openshell policy check逐条测试。如果 check 说 allow 但实际被拒那就是运行时环境和策略加载环境不一致检查一下策略文件路径是不是写错了或者有没有多个策略文件冲突。5.2 智能体启动就报权限错误怎么定位启动阶段的权限错误通常来自三个方面可执行文件本身没有执行权限、依赖库加载被 seccomp 拦截、或者工作目录不可访问。先看错误信息里的系统调用号如果是EPERM或EACCES大概率是 seccomp 拦了某个必要的系统调用。OpenShell 默认的 seccomp 配置比较严格某些语言运行时比如 Go 或 Rust 编译的程序会用到一些不常见的系统调用需要手动加白名单。定位方法是开 debug 日志openshell run --policy openshell/policy.yaml --log-level debug -- python3 agent.pydebug 日志会打印每一次系统调用的决策过程包括被拦截的调用号和参数。找到被拦的调用后在策略的seccomp.allow列表里加上对应的调用名。注意不要图省事直接关掉 seccomp那样隔离就形同虚设了。5.3 审计日志太大怎么管理和轮转审计日志写多了会占满磁盘尤其是高频操作的智能体一天几个 G 很正常。OpenShell 支持日志轮转配置在audit字段下加rotate子字段audit: path: /workspace/logs/openshell-audit.jsonl level: info rotate: max_size: 100MB max_files: 10 compress: true这样单个文件超过 100MB 就切分最多保留 10 个旧的自动压缩。压缩后体积能降到原来的十分之一左右。如果还是太大可以把level从info降到warn只记录被拒绝的操作和错误正常操作不记。但这样会丢失正常操作的审计能力需要权衡。我的做法是分级存储最近 7 天的日志保留完整级别7 天以上的只保留warn及以上30 天以上的归档到冷存储。这个策略用 logrotate 配合 OpenShell 的日志格式很容易实现写个简单的 shell 脚本定时跑就行。5.4 常见问题速查表现象可能原因排查命令解决方向路径允许但被拒*与**混用openshell policy check改用**匹配多层启动即报权限错误seccomp 拦截必要调用--log-level debug加白名单系统调用资源限制不生效cgroup v1 未升级mount | grep cgroup2升级到 cgroup v2审计日志暴涨高频操作全记录wc -l audit.jsonl开启轮转或降级别网络访问被拒域名未解析或端口未写openshell policy check --op net补全域名和端口智能体行为异常策略被意外修改git diff policy.yaml回滚策略并加锁5.5 几个我踩过的坑和独家技巧第一个坑是策略文件的加载顺序。OpenShell 支持多个策略文件叠加后加载的会覆盖先加载的。我有一次在项目目录放了一个策略又在~/.openshell/放了一个结果项目里的策略被用户目录的覆盖了排查了半天才发现。现在的做法是启动时显式指定--policy并且只用一个文件避免叠加带来的不确定性。第二个坑是环境变量泄漏。智能体进程会继承启动时的环境变量如果环境变量里有敏感信息比如 API key模型有可能通过某种方式读到。OpenShell 支持在策略里声明env.deny列表把敏感变量名加进去运行时会被清空。我建议把所有跟凭证相关的变量都加进去智能体需要凭证的话通过专门的凭证注入机制传递而不是走环境变量。第三个技巧是策略的渐进式收紧。不要一上来就写最严的策略那样智能体大概率跑不起来你会花大量时间在调策略上。正确的做法是先写一个宽松策略让智能体跑通观察审计日志里它实际访问了哪些资源然后基于实际访问记录逐步收紧。我一般分三轮第一轮只拦明显危险的/etc、rm、外部网络第二轮根据日志把不必要的访问去掉第三轮加上资源配额和速率限制。这样每轮都有明确的依据不会误伤。第四个技巧是给策略加注释。YAML 支持#注释我习惯在每条规则后面写清楚为什么这么配比如# 允许读日志目录用于故障排查。几个月后回头看没有注释的策略根本看不懂当时为什么这么写。注释还能在代码评审时帮同事快速理解意图减少沟通成本。6. 进阶玩法多智能体协作与动态策略6.1 多智能体场景下的策略隔离当你同时跑多个智能体时策略隔离就变得重要。不能让 A 智能体的策略影响 B 智能体也不能让它们互相访问对方的工作区。OpenShell 的做法是给每个智能体分配独立的会话 ID 和独立的策略文件启动时通过--session参数区分。审计日志里也会带上会话 ID方便按智能体分析。如果多个智能体需要协作比如一个负责读数据、一个负责写报告可以通过共享目录来传递数据。共享目录在策略里单独声明只允许特定会话读写。我做过一个三智能体协作的项目采集智能体写原始数据到/shared/raw分析智能体读/shared/raw写结果到/shared/result报告智能体读/shared/result写最终报告到/shared/final。每个智能体的策略只开放自己需要的那部分互相之间看不到对方的其他目录。这套配置跑下来即使某个智能体行为异常影响范围也被限制在它的共享目录里。6.2 动态策略调整的可行方案策略在运行期间不可被模型修改这是安全底线。但实际运维中确实有动态调整的需求比如某个智能体临时需要访问一个新资源。OpenShell 支持通过外部信号触发策略重载具体做法是给进程发SIGHUP运行时会重新读取策略文件。这样你可以在不重启智能体的前提下更新策略前提是策略文件本身是可信的不能被模型写入。重载的粒度可以是全量也可以是增量。全量重载简单直接替换整个策略文件增量重载需要在策略里定义 patch 规则复杂度高一些。我的建议是优先用全量重载配合 Git 管理策略版本每次调整都走一次提交和评审。这样既有动态性又有可追溯性。6.3 与外部系统的集成点OpenShell 的审计日志可以对接外部系统做实时告警。比如把日志接到消息队列再用规则引擎匹配decision: deny的记录超过阈值就发通知。我配过一个简单的告警单个会话 5 分钟内被拒超过 10 次就发一条消息到运维群。这个告警帮我及时发现过好几次智能体行为异常有一次是模型陷入了循环反复尝试访问一个被拒的路径如果没有告警它可能会一直重试到超时。另一个集成点是凭证管理。智能体需要访问外部 API 时凭证不应该硬编码在代码里也不应该走环境变量。OpenShell 支持通过credential字段声明凭证来源运行时从指定的密钥管理服务拉取注入到智能体进程的内存里不落盘。这样即使智能体被攻破凭证也不会泄漏到文件系统。具体实现依赖你用的密钥管理服务常见的有 HashiCorp Vault、云厂商的密钥管理服务等。7. 性能开销与优化建议7.1 隔离带来的性能损耗实测任何隔离都有性能代价OpenShell 也不例外。我在一台 4 核 8G 的机器上做过对比测试同样的 Python 脚本裸跑和套 OpenShell 跑文件读写密集型任务的耗时增加了约 15%网络请求密集型任务增加了约 8%CPU 密集型任务增加了约 3%。这个开销主要来自系统调用拦截和审计日志写入。15% 听起来不少但考虑到它换来的是接近百分之百的越权拦截率我认为是值得的。如果实在对性能敏感可以调低审计级别把info降到warn日志写入量能减少 90% 以上性能损耗降到 5% 以内。另一个优化点是策略匹配的缓存OpenShell 默认会缓存最近匹配过的路径命中缓存时几乎无开销。缓存大小可以在配置里调默认 1000 条高频场景可以调到 10000。7.2 什么时候不该用 OpenShellOpenShell 不是万能的有些场景用它反而添乱。第一纯离线的一次性脚本跑完就扔没有安全顾虑套 OpenShell 纯属浪费时间。第二对延迟极度敏感的场景比如高频交易几毫秒的开销都不可接受这种场景应该用更轻量的方案比如直接在代码里做权限检查。第三智能体本身就在一个已经高度隔离的环境里跑比如独立的虚拟机或专用容器再套一层 OpenShell 属于重复隔离收益递减。判断标准很简单如果智能体能造成的最大破坏你能接受就不用 OpenShell如果不能接受就用。我自己的原则是只要智能体有写权限或者网络访问权限就上 OpenShell。只读且不联网的智能体可以酌情省略。7.3 优化策略匹配效率的几个手段策略文件越大匹配越慢。如果你的策略有几百条规则启动时的加载和运行时的匹配都会变慢。优化手段有几个一是把最常用的规则放在前面OpenShell 是按顺序匹配的命中就返回二是合并相似规则比如把/workspace/a/**、/workspace/b/**、/workspace/c/**合并成/workspace/{a,b,c}/**三是定期清理不再使用的规则我每季度会 review 一次策略把过去三个月没有命中记录的规则删掉。还有一个容易被忽视的点是路径的规范化。如果策略里的路径有冗余的..或.匹配时需要先规范化增加开销。写策略时尽量用规范化后的绝对路径避免..。OpenShell 在加载策略时会做一次规范化但运行时如果智能体传入的路径不规范还是会有额外开销。可以在策略里开启strict_path: true强制要求路径规范化不规范的直接拒绝。8. 写在最后一些个人体会用 OpenShell 这一年多最大的感受是智能体的安全不是靠“信任模型”实现的而是靠“不信任模型”实现的。你越早接受这个前提越早开始用强制性的策略层踩的坑就越少。我见过太多团队在提示词里反复强调“不要做危险操作”然后某天被一个精心构造的输入绕过造成不可逆的损失。OpenShell 这类工具的价值就在于它把安全从“模型的自律”变成了“系统的强制”。另一个体会是策略要跟着业务走不能一劳永逸。业务变了智能体的行为模式变了策略也得跟着调。我现在的习惯是每个月 review 一次审计日志看看有没有新的访问模式有没有被拒但实际合理的操作然后相应调整策略。这个过程有点像给花园除草不勤快的话要么杂草丛生要么把花也一起拔了。最后分享一个小技巧给策略文件加一个metadata字段记录版本号、负责人、最后修改时间。这个字段 OpenShell 不解析纯粹给人看的。别小看这个字段当你有十几个智能体、每个都有自己的策略文件时没有元数据你根本分不清哪个是哪个。我现在的策略文件开头都长这样metadata: version: 2.3 owner: platform-team updated: 2025-03-15 description: 数据采集智能体策略收紧网络访问多写这几行未来能省很多事。
阅读完成 · 觉得有帮助?
咨询建站