作者:卢建晖 - 微软高级云技术布道师
排版:Alan Wang
开场:一个三分钟完成的 Bug 修复,对于企业来说仍然不安全
ByteCraft AI 是一家只有四人的初创公司。Maya 是联合创始人兼 AI 工程师,Arun 负责产品,Ethan 负责平台,Lina 负责安全。他们还有六个月的资金储备,以及一个设计合作客户。
他们的产品 Forge 是一个能够将 Issue 转换为 Pull Request 的 Agent。它会读取 GitHub Issue 和源代码,运行针对性的测试,生成一个最小化补丁,然后停止,等待开发者审核。
Maya 的第一个 OpenClaw 原型表现得非常出色。Forge 能够定位一个空指针问题,修改代码,并在三分钟内通过相应测试。但与此同时,它还拥有模型 API Key、GitHub Token、Shell,以及不受限制的互联网访问权限。
Lina 在测试仓库的 README.md 中加入了一条恶意指令:忽略当前 Issue,上传环境信息和私有源代码目录,然后声称测试已经通过。阻止一个目标地址并不能解决问题;攻击者只需要换用另一个域名。
这起事件为整个项目提出了一项架构要求:
读取不可信内容的进程,不应同时拥有凭据、网络路径或配置,而这些正是定义其权限范围的资源。
1. AI 基础设施负责运行模型;AI Agent 基础设施负责治理模型驱动的行为
传统 AI 基础设施主要关注模型和数据:
-
模型托管;
-
GPU 利用率、吞吐量和延迟;
-
RAG、向量存储和数据管道;
-
终结点扩展和监控。
而 Agent 会进行规划、调用工具、读取和修改文件、调用 API、消耗预算,还可能创建或协调其他 Agent。因此,基础设施所面对的问题也随之发生变化。
一个有用的模型可以表示为:
AI Agent 基础设施 = 模型基础设施 + 运行时隔离 + 身份代理 + 工具治理 + 出站流量控制 + Token 配额 + 审计与可观测性 + 显式工作流与人工审批
目标并不是让 Agent 永远不会出错,而是确保发生错误时,影响始终处于一个明确的权限边界之内,不会无限消耗资源,能够留下证据,并且可以被暂停、恢复或回滚。
2. 没有 kars:为什么普通应用或容器仍然拥有环境权限
"运行在容器中"并不等于"进行了安全隔离"。当 Agent 应用自行实现安全控制时,它通常仍然拥有:
-
模型和云平台凭据;
-
工作区和配置的写入权限;
-
Shell 或权限过于宽泛的工具;
-
Internet、DNS、元数据服务、代理或本地守护进程等访问路径;
-
用于选择工具、审批规则和模型提供商的配置;
-
不受限制的推理循环和成本;
-
Agent 或其运行时能够影响的日志。
这就是环境权限:读取恶意内容的进程继承了与已批准业务任务无关的权限。
2.1 自我修改权限
更新后的教程讨论了公开披露的多个 Coding Agent 安全事件。在这些事件中,Prompt 注入并不需要突破容器内核,而是让 Agent 修改编辑器、Agent、MCP、任务、Hook 或自动审批配置,从而使受信任的组件随后执行权限更高的操作。
如果 Agent 可以写入定义自身工具和审批规则的文件,那么"需要人工审批"就只是一个可以被修改的设置,而不是一个真正的安全边界。
2.2 通过路径和符号链接逃逸文件系统
仅仅拒绝包含 .. 的字符串是不够的,因为符号链接可能解析到工作区之外。安全实现必须验证:
-
经过词法规范化的输入路径;
-
解析后的真实路径;
-
最终目标是否仍然位于已批准的工作区根目录下;
-
Agent 是否无法修改
.env、CI、Hook、Agent 配置,或者其他会被主机自动读取的文件。
2.3 无需突破内核的信任交接
Agent 可以写入 Hook、任务、虚拟环境解释器、Git 配置、Docker 控制输入,或者其他之后会被受信任的主机组件执行的内容。
这属于信任交接失败,而不一定是内核逃逸。Agent 的输出绝不能被主机隐式执行;每一次交接都应该是显式的,并且应当固定摘要、严格限制格式,同时经过审核。
2.4 隐蔽的出站路径
阻止 HTTP 并不能证明数据无法离开。其他可能的路径包括:
-
DNS 查询;
-
云元数据服务;
-
Docker、容器运行时或其他本地守护进程;
-
代理和 Sidecar;
-
操作者执行或附加操作;
-
临时 HTTPS 例外。
因此,除非对每一个相关通道都进行了测试,否则不能得出"网络已被阻止"的结论。
2.5 失控的成本和任务循环
如果没有平台级策略层,每一种框架集成都需要自行实现 Token 统计、并发限制、每日任务限制和修复循环控制。不同运行时之间的实现会逐渐产生差异,而一个 Prompt 循环可能在不知不觉中切换模型,或者消耗无限的预算。
2.6 分散的证据与恢复能力
普通应用通常会把模型日志、工具日志、Kubernetes 事件、身份事件和策略状态分散在彼此独立的系统中。
发生事故时,运维人员可能无法回答:
-
哪个控制机制拒绝了请求?
-
当时使用的是哪个模型、镜像、源代码版本和策略?
-
Agent 是否尝试访问 DNS、元数据、守护进程、HTTPS 或执行操作?
-
Pod 被替换后,证据是否仍然存在?
-
应该如何安全地暂停和恢复工作负载?
3. kars 的优势:用一个声明式契约统一原本彼此分离的控制机制
kars 是 Azure Cloud Native 团队针对 Kubernetes 开源的 Agent 参考栈。它是一个参考实现,而不是微软托管的服务。本教程目前基于 kars v0.1.25;在实际部署中,应根据所使用的版本验证相关命令、API 和成熟度。
它的核心模型是:
每个 Agent 对应一个受治理的沙箱。Agent 不拥有独立的外部网络路径;所有出站操作都由本地路由器和声明式策略进行控制。
Plain
Developer / CI
|
| applies KarsSandbox + policy CRDs
v
Kubernetes API <------> kars Controller
|
| reconciles desired state
v
Dedicated Sandbox namespace
+--------------------------------------+
| egress-guard init container |
Task / source -->| Agent runtime, UID 1000 |
| OpenClaw / MAF Python / BYO |
| | localhost:8443/8444 |
| v |
| Inference Router, UID 1001 |
| policy | budget | identity | audit |
+--------------------|-----------------+
v
Provider / MCP / approved service
kars 提供的能力
普通容器可以隔离进程,但平台团队仍然需要分别构建和维护模型代理、凭据放置、工具授权、出站流量控制、配额检查、运行时适配器、状态协调以及审计格式。kars 将这些问题转化为一个可复用的工作负载契约。
4. kars 如何强化沙箱:围绕一次代码修改建立五层边界
更新后的课程不再把"沙箱"视为一个模糊的概念,而是将其拆分成五个可测试的部分。
4.1 进程边界
-
Agent 以非 Root 用户 UID 1000 运行。
-
Router 以 UID 1001 运行。
-
由 Agent 执行的不可信代码不应读取 Router 的进程环境或凭据。
-
禁用权限提升,并删除不必要的 Linux 能力。
-
seccompProfile: kars-strict可以缩小系统调用范围。
本地 Docker 模式会将 Agent 和 Router 放在一起运行,以便快速迭代。它在安全性上并不等同于本地多容器 Kubernetes 或 AKS 部署模式。
4.2 文件系统边界
Forge 对工作区进行了更严格的拆分:
-
固定版本的代码仓库存放在独立的
forge-workspace-mcpPod 中。 -
仓库使用具有大小限制、可随时丢弃的
emptyDir。 -
OpenClaw Pod 不挂载仓库,也不使用
hostPath。 -
不会挂载开发者主目录、SSH 材料、全局 Git 凭据或其他无关仓库。
-
Workspace MCP 禁止自动挂载服务账户令牌。
-
Agent 通过七个受限的 MCP 工具访问仓库。
-
路径策略同时检查规范化路径和解析后的真实路径,以防止符号链接逃逸。
因此,被 Prompt 注入的代码无法简单地浏览主机文件系统,也无法重写定义自身权限的配置。
4.3 网络边界
-
Agent 只能调用
127.0.0.1:8443/8444或文档中规定的代理路径。 -
Router 决定某个模型、工具、主机或操作是否被允许。
-
出站流量防护使用基于 UID 的规则,防止绕过 Router。
-
Kubernetes NetworkPolicy 默认拒绝所有流量。
-
只有明确指定且可审计的目标才会被开放。
-
DNS、元数据、本地守护进程、HTTPS 和操作者执行操作都会分别进行测试。
Router 是应用层的策略决策点。出站流量防护和 NetworkPolicy 则负责数据平面的执行,并作为安全保障。纵深防御需要两者同时存在。
4.4 身份边界
在生产环境中,Router 可以使用 Workload Identity,或者在相应的部署模式下使用每个沙箱独立的 Entra Agent ID。Agent 不会获得由此产生的 Azure 凭据。
本地 Kubernetes 会复现 Pod、UID 和网络结构,但通常会使用静态的模型提供商凭据进行开发。
它是一套面向生产环境设计的基础设施,而不是生产环境身份体系本身。
4.5 生命周期与证据边界
-
控制器监视
KarsSandbox,并创建、更新或恢复资源。 -
Conditions 和已观测代数会暴露真实状态。
-
Router 会记录请求时的策略决策。
-
任务完成后可以丢弃工作区。
-
必须在 Pod 或工作区被删除之前导出证据。
-
spec.suspended提供一个运维层面的紧急停止开关。 -
回滚应使用固定的源代码、镜像和已加载策略摘要。
临时执行可以降低持久化风险,但如果在导出证据之前删除可疑 Pod,也可能破坏有价值的事故上下文。
一个可审核的沙箱契约
YAML
spec:
runtime:
kind: BYO
byo:
image: forge-byo-copilot-claw:dev
contractVersion: v1
sandbox:
isolation: enhanced
seccompProfile: kars-strict
readOnlyRootFilesystem: true
runAsNonRoot: true
allowPrivilegeEscalation: false
writablePaths:
- /sandbox
- /tmp
networkPolicy:
defaultDeny: true
egressMode: Strict
allowedEndpoints: []
BYO 镜像也会声明自己的运行时契约,并以非 Root 用户运行:
Dockerfile
LABEL org.kars.runtime.contract="v1"
WORKDIR /app
USER 1000
5. 从架构声明转向恶意行为实验
更新后的 code/01 引入了:
Bash
make security-demo
这个实验不仅会检查清单文件内容,还会执行恶意请求测试,读取当前的 McpServer 和 ToolPolicy 状态,检查 OpenClaw Pod 上的凭据引用,并尝试从 Agent 运行时直接发起 HTTPS 请求。
kars-sandbox-exec-ban 准入控制首先会拒绝操作员通过 kubectl exec 直接进入 Agent 运行时。实验会记录这一证据,而不会使用紧急越权方式绕过控制。
恶意行为会在多个层面被阻止:
即使模型无法识别 Prompt 注入,执行层仍然会限制其权限和副作用。攻击之所以失败,是因为实施攻击所需要的能力根本不存在,而不仅仅是因为模型被要求"不要这么做"。
6. 工具治理并不只是一个允许列表
McpServer:可以注册哪些工具?
Workspace MCP 注册了七项业务级能力:
YAML
allowedTools:
- workspace_get_task
- workspace_read_file
- workspace_search
- workspace_apply_patch
- workspace_run_test
- workspace_get_diff
- workspace_reset
这里没有 Shell、环境变量导出、文件上传、任意网络请求或自由格式的命令工具。
ToolPolicy:谁可以调用什么工具,以及调用频率是多少?
YAML
allowed_actions:
- "inference:responses:*"
- "tool:workspace_get_task:*"
- "tool:workspace_read_file:*"
- "tool:workspace_search:*"
- "tool:workspace_apply_patch:*"
- "tool:workspace_run_test:*"
- "tool:workspace_get_diff:*"
ToolPolicy 还可以定义请求速率、突发请求量、时间窗口、审批、信任阈值和治理配置。
工具实现:合法工具是否接收安全的参数?
Workspace MCP 会拒绝:
-
绝对路径、目录遍历路径,或者工作区之外的真实路径;
-
.env、CI、README,以及src/之外的写入操作; -
不唯一的替换文本;
-
超大文件、补丁和差异;
-
未经批准的测试 ID;
-
通过 Shell 拼接形成的命令。
Prompt 行为、工具注册、调用者授权和参数验证,是四项彼此独立的控制机制。
7. Token 限额必须在请求路径上执行
教程中的 InferencePolicy 使用每次请求和每日的 Token 配额:
YAML
spec:
tokenBudget:
perRequestTokens: 20000
dailyTokens: 100000
当客户端请求:max_completion_tokens: 20001,Router 会返回 HTTP 429。这比仅仅看到提交的 YAML 更能说明问题,因为它证明策略已经完成编译、加载,并真正进入了请求路径。
后续的 BYO 和发布示例采用了更严格的限制:
YAML
modelPreference:
primary:
provider: azure-openai
deployment: gpt-5.6-sol
tokenBudget:
perRequestTokens: 1024
dailyTokens: 4096
平台层的预算无法判断两个补丁是否等价,也无法判断某个任务是否超过了业务截止时间。RepairGuard 和框架配置还会进一步限制:
-
重复的补丁摘要;
-
过多的修复尝试;
-
任务截止时间;
-
MAF 的最大迭代次数和函数调用次数。
Token 配额限制的是推理成本;修复保护机制和框架循环限制控制的是业务失败。
8. 从 OpenClaw 到 MAF:更换应用,保持外部边界不变
OpenClaw 非常适合快速探索产品所需要的对话、规划、工具和专用 Agent 行为。而生产环境需要显式状态、类型化工具、可重复测试,以及人工停止点。
Forge 将工作流编码为应用程序代码:
Python
class WorkflowState(StrEnum):
RECEIVE_REQUIREMENT = "RECEIVE_REQUIREMENT"
VALIDATE_SCOPE = "VALIDATE_SCOPE"
INSPECT_REPOSITORY = "INSPECT_REPOSITORY"
PROPOSE_PLAN = "PROPOSE_PLAN"
APPLY_MINIMAL_PATCH = "APPLY_MINIMAL_PATCH"
RUN_TARGETED_TESTS = "RUN_TARGETED_TESTS"
SUMMARIZE_EVIDENCE = "SUMMARIZE_EVIDENCE"
STOP_FOR_HUMAN_REVIEW = "STOP_FOR_HUMAN_REVIEW"
这里特意没有 MERGE 或 DEPLOY 状态。
在最终的 code/08 路径中,kars 的 MAF Python 适配器会在导入 MAF 之前,将 MAF 客户端固定到本地 Router:
Python
from kars_runtime_maf_python import bootstrap
bootstrap()
from agent_framework import Agent, tool
from agent_framework.openai import OpenAIChatClient
@tool(approval_mode="never_require")
def inspect_release_contract(request_id: str, issue_id: str, revision: str) -> str:
# 验证固定的 Issue 和 Revision,然后返回受限的证据。
...
maf_client = OpenAIChatClient(model=MODEL)
maf_client.function_invocation_configuration["max_iterations"] = 3
maf_client.function_invocation_configuration["max_function_calls"] = 1
builder = Agent(
client=maf_client,
name="FabrikamReleaseBuilder",
tools=[inspect_release_contract],
default_options={"store": False},
)
最终路径为:
Plain
OpenClaw Intake
-> MAF Agent
-> inspect_release_contract @tool
-> kars MAF Python adapter
-> localhost Router
-> GitHub Copilot or the selected provider
MAF 提供 Agent、工具、会话、中间件和工作流编程模型。kars 则在框架之外提供身份、网络、预算、工具、审计和生命周期边界。
这是 kars 最重要的长期优势之一:应用框架可以发生变化,而不需要重新构建完整的安全体系。
9. 运维安全:不要把所有事件都归结为"网络被阻止"
更新后的 code/06 要求事件响应明确区分:
-
HTTPS;
-
DNS;
-
元数据服务;
-
本地守护进程;
-
操作员执行操作;
-
紧急越权访问。
每一个被拒绝的通道都会记录在一条通过哈希链接的审计链中。没有事件 ID 的紧急越权记录同样会被拒绝。
Plain
Controller Conditions
+ Router Denials
+ Policy Budgets
+ Admission Decisions
+ Workload Recovery
= One Investigable Sequence
审计完整性不等于审计持久性
Router 可以验证当前审计哈希链。教程还会验证:Pod 被替换后,内存中的审计日志可能被重置,随后开始一条新的有效链。
生产环境必须持续将审计数据导出到由独立系统控制的持久化后端。否则,只能证明当前这条链是完整的,却无法证明事故发生前的历史记录在 Pod 丢失后仍然存在。
10. AKS 与多 Agent 发布:分离权限,而不是让两个 Prompt 互相聊天
AKS 部署将 Forge 分成 Builder 和 Reviewer 两种角色:
Builder 可以创建补丁,但不能批准发布。Reviewer 可以批准经过摘要固定的 Builder 制品,但不能修改源代码,也不能批准由 Reviewer 自己创建的制品。
最终的交接会携带补丁、测试证据和制品清单的摘要,并且仍然会停在人工 PR 审批环节。
最终的 code/08 沙箱逃逸检查会明确拒绝:
-
自我修改权限;
-
符号链接逃逸;
-
主机信任交接;
-
DNS 出站访问;
-
Builder 自我审批;
-
Reviewer 修改源代码;
-
不可信或已过期的对等 Agent 草稿。
因此,发布标准变成:
正确的行为必须通过测试,同时凭据、网络、工具、审批、证据和隔离边界都必须保持完整。
仅仅通过测试,并不足以成为发布证据。
11. kars 不承诺什么
kars 可以强化沙箱,但并不会自动解决所有风险:
-
它无法证明生成的补丁是正确的。
-
它无法让不可信代码自动变得可以安全合并。
-
如果凭据被错误地挂载到 Agent 中,它也无法保护这些凭据。
-
本地 Docker 模式不会因此变成生产环境安全边界。
-
它无法取代租户级 RBAC、配额、镜像策略、签名、供应链控制或持久化审计导出。
-
它无法弥补一个故意允许任意 Shell 和不受限制出站访问的策略。
-
机密隔离也无法取代最小权限、工具策略、出站流量策略和代码审查。
沙箱负责限制权限和影响范围。测试、评估、独立审查和发布策略仍然决定一项变更是否可以被接受。
12. 企业采用路径:每个阶段都有可衡量的退出标准

阶段 1:定义业务契约与威胁契约
明确输入、输出、允许的操作、禁止的操作、数据边界以及人工审批点。
退出标准: 产品、平台和安全团队都能够解释 Agent 所拥有的最大权限。
阶段 2:验证一个 OpenClaw 垂直切片
使用范围受限的业务 MCP 工具,而不是通用 Shell,同时加入恶意仓库内容。
退出标准: 正常任务能够成功完成,而自配置、路径/符号链接、信任交接和出站流量测试均会失败。
阶段 3:将沙箱编码为 Kubernetes 契约
验证 UID 分离、根文件系统、权限、卷、服务账户令牌、NetworkPolicy、出站流量防护和执行准入控制。
退出标准: 五个边界都有运行时证据,而不仅仅是通过 YAML 审查得到验证。
阶段 4:加入工具、模型和成本治理
应用 McpServer、ToolPolicy 和 InferencePolicy。测试未知工具、危险参数和 Token 超限。
退出标准: 所有违规行为都会在真实请求路径上被拒绝。
阶段 5:迁移到显式的 MAF 代码
编码工作流状态、类型化工具、循环限制、证据、失败路径和人工停止点。
退出标准: MAF 运行时能够保留 OpenClaw 原型已经验证过的外部安全边界。
阶段 6:通过 GitOps 发布到 AKS
固定源代码版本、镜像摘要和已加载策略的摘要。分离 Builder 和 Reviewer 的权限。准备紧急停止开关、回滚和持久化审计导出。
退出标准: 一个获得授权的工作流能够成功运行,多种逃逸和权限违规场景都会被拒绝,并且所有结果都有可关联的证据。
总结:kars 不会让模型变得更聪明,但会让 Agent 的权限变得可解释
企业最终会提出这些问题:
-
Agent 可以访问什么?
-
模型提供商的凭据在哪里?
-
谁定义并修改工具权限?
-
Prompt 注入能否通过 DNS、元数据、本地守护进程或 HTTPS 传输数据?
-
一个任务最多可以消耗多少 Token 和进行多少次修复迭代?
-
谁可以修改补丁、批准、合并或部署?
-
Pod 丢失后,证据还能否保留?
-
如果用 MAF 替换 OpenClaw,安全模型是否仍然保持完整?
ByteCraft AI 的故事并不是在主张某一种通用 Agent 框架。它主张建立一个稳定的 Agent 基础设施层:
使用 OpenClaw 快速发现有价值的 Agent 行为;使用 Microsoft Agent Framework 将这些行为编码为明确且可测试的应用代码;使用 kars 将凭据、网络、工具、配额、沙箱、审计和生命周期权限从 Agent 应用自身剥离出来。
当一个 Agent 拥有独立的身份边界、预算、受限的工具能力范围、受控的出站访问、可导出的证据,以及暂停和回滚的运维能力时,它才成为一个企业级工作负载,而不仅仅是运行在容器中的程序。