微软 Execution Containers 正式可用:Agent 不能做自己的安全权威

·阅读约9分钟·Evergreen Tools Team

微软于 2026 年 10 月 7 日把 Microsoft Execution Containers(MXC)推向正式可用。微软公告里有一句话值得读两遍:Agent 不能做自己的安全权威。整件事的意思就在这一句里。MXC 是一个策略驱动的执行层,面向你没有写、也无法完全预测的代码——模型输出、插件、工具、Agent 的 harness,乃至整个 Agent。开发者和管理员声明可以使用哪些文件与网络目的地,Windows 再挑选合适的容器在运行时执行这些声明。

机房里的机架服务器

边界必须放在你不信任的那个工作负载之外

MXC 到底是什么

MXC 是一个面向不可信或动态生成负载的策略驱动执行层。在 Agent 场景里,你可以选择「contained」的范围:模型生成的输出、插件、工具、Agent harness,或者整个 Agent。这个范围由你来定。微软明确说,目标是限制 Agent 工作负载能访问什么,也就是在出事时把影响范围封顶,而不是假装不会出事。它现在是正式可用(GA)而不是预览,所以设计上的假设变了:这是要在生产里配置的东西,不是拿来试试的东西。

# mxc-policy.yaml - declare the boundary, do not hope for good behaviour.
# MXC is policy-driven: the developer or IT admin names the resources,
# and the platform picks a container that enforces the policy at runtime.
version: 1
agent: invoice-triage
filesystem:
  read:
    - C:\work\inbox\**          # the only place inputs live
  write:
    - C:\work\outbox\**
  deny:
    - C:\Users\**\AppData\**   # credential stores, browser profiles
    - C:\Windows\**
network:
  allow:
    - https://api.internal.example.com    # the one API it needs
  deny: ['*']                             # default deny, not default allow
process:
  allow_spawn: false                       # no sub-processes, no shells

三根柱子:隔离、身份、可管理

微软把问题拆成三块,而只有一块是容器。Containment 限制 Agent 能访问什么、能做什么;Identity 把 Agent 的行为与人的行为区分开,Windows 很快就会让 Microsoft Entra 来做这件事——这点很关键,因为一个继承了人类凭据的 Agent,正是你读到的审计事故里一半的根因;Manageability 给组织提供治理访问与监控活动的工具,把 Microsoft Agent 365 的管控扩展到设备上的本地 Agent,让 IT 能管理 MXC 容器、下发策略、监视 Agent 的行为。只有隔离没有监控,那就是一堵没有摄像头的墙。

# An agent cannot be its own security authority: the check must sit
# outside the agent's code path, in the layer that calls the tool.
import os, pathlib

ALLOWED_DIRS = {pathlib.Path(r'C:\work\inbox'), pathlib.Path(r'C:\work\outbox')}

def guarded_write(path: str, data: str, policy: dict) -> None:
    p = pathlib.Path(path).resolve()
    if not any(p.is_relative_to(d) for d in ALLOWED_DIRS):
        raise PermissionError(f'policy deny: {p} is outside the declared roots')
    if any(p.match(pat.replace('\\', '/')) for pat in policy['filesystem']['deny']):
        raise PermissionError(f'policy deny: {p} matched a deny rule')
    p.write_text(data, encoding='utf-8')

# The model never sees this function. That is the point.
锁与加密概念图

策略在运行时执行,而不是在评审时

为什么 Agent 不能自己监管自己

如果由 Agent 来决定自己的动作是否被允许,那你拥有的不是控制,而是建议。被测对象恰恰就是被信任程度不明的这个负载,它不能同时当裁判。所以真正有用的工程问题不是「把 Agent 放进容器」,而是「强制执行的决定发生在哪里,这个负载能不能碰到它」。MXC 的答案是:把决定搬进操作系统,放在 Agent 代码路径之外。任何 Agent 能修改、能绕过、能讨价还价的策略,都只是装饰。检验方法很简单:在最糟糕的那一天,模型的输出能不能改掉管它的那条规则?

# Roll out in one team before you roll out to the fleet.
# Effective policy is the only policy that counts.
ANIMALS = 'invoices'
mxc canary --policy mxc-policy.yaml --tag canary --percent 5
mxc policy show --agent invoice-triage --effective   # what Windows will enforce
mxc policy diff --agent invoice-triage --effective --declared

# Look for the two failure modes that hurt:
#   declared_but_not_enforced  -> a false sense of safety
#   enforced_but_not_declared  -> a surprise outage waiting to happen

比提示词活得更久的策略

提示词天天在变,策略应该有意地变、经过评审地变。把边界写成声明式策略而不是写在提示词里的指令,才能让它熬过一次模型替换、一次框架升级、一次新工具接入。实际的形状就是一个 mxc-policy.yaml:读这些目录、写那些目录、只能访问这一个 API、默认拒绝其余、不派生子进程。它读起来像一份防火墙规则集,因为它本来就是。推论是:策略从此需要版本管理、需要评审、需要 diff——而 diff 恰恰是价值最大的地方。

# Reconstruct what happened after the fact. Without this, a containment
# boundary is a claim, not a control.
import json, time

def audit(record, decision, reason):
    return json.dumps({
        'ts':        time.strftime('%Y-%m-%dT%H:%M:%S%z'),
        'agent':     record['agent'],
        'tool':      record['tool'],
        'target':    record['target'],      # file path or network destination
        'decision':  decision,              # allow | deny
        'reason':    reason,                # which rule fired
        'policy_rev': record['policy_rev'], # policy version in force at the time
    }, ensure_ascii=False)

# Log policy_rev on every call. A deny you cannot explain is a deny
# nobody will trust, and an unused policy is worse than no policy.
笔记本屏幕上的代码

先声明策略,再拿真实工具调用去测

隔离解决不了什么

MXC 不会告诉你 Agent 挑的文件对不对,只告诉你它有没有权限。它也拦不住一次提示词注入——模型被说服去外泄一份它本来就有权访问的文档,这个调用在策略内,意图在策略外。它不替代密钥管理,因为一个被隔离、但手里拿着有效 API Key 的 Agent,照样能把你的额度烧掉。它治不好一个本来就过大的工具面。如果你把策略声明下去却从不验证它真的被执行了,它也帮不了你——这是所有控制系统里最常见的失败模式。

# Measure the gap between the tool surface you think the agent has
# and the tool surface it actually exercises in production.
from collections import Counter

def policy_coverage(audit_rows, declared_rules):
    used = Counter(r['tool'] for r in audit_rows)
    denied = sum(1 for r in audit_rows if r['decision'] == 'deny')
    uncovered = [t for t in used if not any(t in rule for rule in declared_rules)]
    return {
        'distinct_tools_used': len(used),
        'deny_rate': round(denied / max(len(audit_rows), 1), 4),
        'tools_with_no_rule': uncovered,   # tighten these first
    }

# A deny rate near zero in week one usually means the boundary is too
# loose, not that the agent is well behaved.

不会把你半夜叫起来的上线顺序

先在一个团队的一个 Agent 上、用低流量开始,并且在收紧策略之前先读拒绝日志。定期比对「声明策略」与「生效策略」,因为这两者会漂移。给每一次工具调用都打上工具名、目标、决定、以及当时生效的策略版本,否则将来你永远解释不清某一次拒绝。如果第一周拒绝率几乎为零,把它当作「边界太松」的证据,而不是「Agent 很乖」的证据。另外留一个不需要 Agent 配合就能生效的开关,因为你需要它的那一天,恰恰就是它不配合的那一天。

📌 常见问题 FAQ

Microsoft Execution Containers(MXC)是什么?

它是面向不可信或动态生成负载的策略驱动执行层,自 2026 年 10 月 7 日起正式可用。开发者与 IT 管理员声明 Agent 可以使用的资源,MXC 用合适的容器在运行时执行这些策略。

MXC 能隔离哪些东西?

模型生成的输出、插件、工具、Agent harness,或者整个 Agent。微软把目标描述为限制 Agent 工作负载能访问什么,从而在出错时把影响封顶。

这和「直接把 Agent 跑在容器里」有什么区别?

容器回答的是「负载跑在哪里」,MXC 回答的是「它能碰到什么、谁来做决定」。强制执行的决定放在 Agent 之外,Agent 不能做自己的安全权威——这是微软明确写出的设计原则。

还需要密钥管理吗?

需要。隔离限制的是可达范围,不是消费能力。一个被隔离但持有有效 API Key 的 Agent 依然能消耗该 Key 的额度。把凭据排除在被隔离负载的文件系统之外,优先使用短时效、窄范围的令牌。

最常见的部署错误是什么?

把策略声明下去就假定它会生效。要定期比对声明策略与生效策略,在每次工具调用上记录策略版本,并把第一周异常低的拒绝率当作边界太松的信号。