提案日期: 2026-02-04 状态: 设计阶段 优先级: 🔴 高 (安全关键)
OpenCLI 当前拥有基于权限的安全系统:
┌─────────────────────────────────────────┐
│ 当前安全架构 (仅权限控制) │
│ │
│ Client Request │
│ │ │
│ ▼ │
│ ┌──────────────┐ │
│ │ Permission │ │
│ │ Manager │ │
│ │ │ │
│ │ • auto │ ✅ 通过 │
│ │ • notify │ ✅ 通过 │
│ │ • confirm │ ⏳ 用户确认 │
│ │ • deny │ ❌ 拒绝 │
│ └──────┬───────┘ │
│ │ │
│ ▼ │
│ ┌──────────────┐ │
│ │ Daemon │ ⚠️ 所有代码在 │
│ │ Process │ 相同进程中执行 │
│ │ │ │
│ │ • 读取文件 │ 🔓 完整系统访问 │
│ │ • 执行命令 │ 🔓 无隔离 │
│ │ • 网络访问 │ 🔓 共享内存 │
│ │ • AI 调用 │ 🔓 共享文件系统 │
│ └──────────────┘ │
└─────────────────────────────────────────┘
| 风险类型 | 描述 | 影响 |
|---|---|---|
| 代码注入 | 恶意 AI 响应可能注入危险命令 | 🔴 Critical |
| 权限提升 | 任务在 daemon 权限下运行 | 🔴 Critical |
| 文件系统访问 | 完整文件系统读写权限 | 🟠 High |
| 网络滥用 | 无限制的网络访问 | 🟠 High |
| 资源耗尽 | 无限制的 CPU/内存使用 | 🟡 Medium |
| 信息泄露 | 可访问敏感数据 | 🔴 Critical |
用户: "帮我清理临时文件"
AI (恶意): "执行: rm -rf ~/*" ← 危险!
↓
Daemon 直接执行 (当前架构)
↓
用户数据全部删除 💥
用户安装第三方插件
↓
插件代码在 daemon 进程中运行
↓
插件可以:
• 读取所有文件
• 访问网络发送数据
• 修改系统设置
• 窃取凭据 💥
依赖包被攻击者控制
↓
恶意代码注入到 daemon
↓
完整系统访问权限 💥
- 隔离执行: 危险任务在隔离环境中运行
- 资源限制: CPU、内存、网络带宽限制
- 文件系统隔离: 只读或受限的文件系统访问
- 网络隔离: 可控的网络访问策略
- 快速启动: <100ms 启动时间
- 低开销: <50MB 内存开销
| 安全等级 | 执行环境 | 示例任务 |
|---|---|---|
| 🟢 Trusted | Daemon 进程 | 读取配置、查询状态、AI 聊天 |
| 🟡 Safe | Daemon 进程 | 读取文件、列出目录、搜索 |
| 🟠 Review | Daemon + 用户确认 | 写入文件、打开应用、截图 |
| 🔴 Dangerous | MicroVM 隔离 | 执行 shell 命令、安装软件、网络操作 |
| ⚫ Blocked | 拒绝执行 | 系统修改、root 操作 |
┌────────────────────────────────────────────────────────────────────┐
│ OpenCLI 安全架构 (带 MicroVM 隔离) │
│ │
│ Client Request │
│ │ │
│ ▼ │
│ ┌──────────────────────────┐ │
│ │ Daemon (主进程) │ │
│ │ │ │
│ │ ┌────────────────────┐ │ │
│ │ │ Permission Manager │ │ │
│ │ └─────────┬──────────┘ │ │
│ │ │ │ │
│ │ ▼ │ │
│ │ ┌────────────────────┐ │ │
│ │ │ Security Router │ │ │
│ │ │ │ │ │
│ │ │ 任务分类: │ │ │
│ │ │ • Trusted → 本地 │ │ │
│ │ │ • Safe → 本地 │ │ │
│ │ │ • Review → 本地 │ │ │
│ │ │ • Dangerous→ VM │◀─┼─ 新增组件 │
│ │ └─────────┬──────────┘ │ │
│ └────────────┼──────────────┘ │
│ │ │
│ ┌────────┴────────┐ │
│ │ │ │
│ ▼ ▼ │
│ ┌────────┐ ┌──────────────────────────────────────┐ │
│ │ 本地执行 │ │ MicroVM Pool (新增) │ │
│ └────────┘ │ │ │
│ │ ┌─────────────────────────────────┐ │ │
│ │ │ VM 1: 运行中 │ │ │
│ │ │ • Firecracker VMM │ │ │
│ │ │ • Alpine Linux (精简内核) │ │ │
│ │ │ • 限制: 1 CPU, 256MB RAM │ │ │
│ │ │ • 网络: 受限白名单 │ │ │
│ │ │ • FS: 只读 + 临时 tmpfs │ │ │
│ │ │ • 超时: 5 分钟 │ │ │
│ │ └─────────────────────────────────┘ │ │
│ │ │ │
│ │ ┌─────────────────────────────────┐ │ │
│ │ │ VM 2: 空闲 │ │ │
│ │ │ (预热待命) │ │ │
│ │ └─────────────────────────────────┘ │ │
│ │ │ │
│ │ ┌─────────────────────────────────┐ │ │
│ │ │ VM 3: 空闲 │ │ │
│ │ └─────────────────────────────────┘ │ │
│ └──────────────────────────────────────┘ │
└────────────────────────────────────────────────────────────────────┘
/// 安全路由器 - 决定任务执行环境
class SecurityRouter {
final PermissionManager permissionManager;
final MicroVMPool vmPool;
/// 路由任务到适当的执行环境
Future<ExecutionResult> routeTask(Task task) async {
final securityLevel = _classifyTask(task);
switch (securityLevel) {
case SecurityLevel.trusted:
case SecurityLevel.safe:
case SecurityLevel.review:
// 本地执行
return await _executeLocally(task);
case SecurityLevel.dangerous:
// MicroVM 隔离执行
return await _executeInVM(task);
case SecurityLevel.blocked:
throw SecurityException('Task blocked by security policy');
}
}
/// 分类任务安全等级
SecurityLevel _classifyTask(Task task) {
// 检查操作类型
if (task.operation == 'execute_shell_command') {
return SecurityLevel.dangerous;
}
if (task.operation == 'install_package') {
return SecurityLevel.dangerous;
}
if (task.operation.startsWith('file_write')) {
return SecurityLevel.review;
}
// 默认安全
return SecurityLevel.safe;
}
/// 在 MicroVM 中执行
Future<ExecutionResult> _executeInVM(Task task) async {
// 从池中获取 VM
final vm = await vmPool.acquireVM();
try {
// 设置超时和资源限制
final result = await vm.execute(task)
.timeout(Duration(minutes: 5));
return result;
} finally {
// 释放 VM (销毁或重置)
await vmPool.releaseVM(vm);
}
}
}/// MicroVM 池管理器
class MicroVMPool {
final int maxVMs = 5;
final int minIdleVMs = 2;
final List<MicroVM> _idleVMs = [];
final List<MicroVM> _busyVMs = [];
/// 获取可用 VM
Future<MicroVM> acquireVM() async {
// 有空闲 VM,直接返回
if (_idleVMs.isNotEmpty) {
final vm = _idleVMs.removeAt(0);
_busyVMs.add(vm);
return vm;
}
// 达到上限,等待
if (_busyVMs.length >= maxVMs) {
await _waitForAvailableVM();
return acquireVM();
}
// 创建新 VM
final vm = await _createVM();
_busyVMs.add(vm);
return vm;
}
/// 释放 VM
Future<void> releaseVM(MicroVM vm) async {
_busyVMs.remove(vm);
// 销毁 VM (安全起见,不重用)
await vm.destroy();
// 维持最小空闲数
_maintainIdleVMs();
}
/// 创建新 VM
Future<MicroVM> _createVM() async {
return await MicroVM.create(
memory: 256 * 1024 * 1024, // 256 MB
cpus: 1,
networkPolicy: NetworkPolicy.restricted,
filesystemMode: FilesystemMode.readOnlyWithTmp,
);
}
/// 预热空闲 VM
Future<void> _maintainIdleVMs() async {
while (_idleVMs.length < minIdleVMs) {
final vm = await _createVM();
_idleVMs.add(vm);
}
}
}/// MicroVM 实例
class MicroVM {
final String id;
final Process firecrackerProcess;
final String socketPath;
/// 创建 MicroVM
static Future<MicroVM> create({
required int memory,
required int cpus,
required NetworkPolicy networkPolicy,
required FilesystemMode filesystemMode,
}) async {
final id = Uuid().v4();
final socketPath = '/tmp/firecracker-$id.sock';
// 启动 Firecracker VMM
final process = await Process.start('firecracker', [
'--api-sock', socketPath,
]);
// 配置 VM
await _configureVM(socketPath, memory, cpus);
// 配置网络
await _configureNetwork(socketPath, networkPolicy);
// 配置文件系统
await _configureFilesystem(socketPath, filesystemMode);
// 启动 VM
await _startVM(socketPath);
return MicroVM(
id: id,
firecrackerProcess: process,
socketPath: socketPath,
);
}
/// 在 VM 中执行任务
Future<ExecutionResult> execute(Task task) async {
// 通过 vsock 发送任务
final result = await _sendTaskViaVsock(task);
return result;
}
/// 销毁 VM
Future<void> destroy() async {
firecrackerProcess.kill();
await File(socketPath).delete();
}
}| 方案 | 启动时间 | 内存开销 | 隔离程度 | 复杂度 | 推荐 |
|---|---|---|---|---|---|
| Firecracker | 125ms | 5MB | ⭐⭐⭐⭐⭐ | 中 | ✅ 首选 |
| gVisor | 50ms | 20MB | ⭐⭐⭐⭐ | 低 | 🟡 备选 |
| Docker | 500ms | 100MB | ⭐⭐⭐ | 低 | ❌ 不推荐 |
| Kata Containers | 300ms | 120MB | ⭐⭐⭐⭐⭐ | 高 | ❌ 过重 |
- AWS 开源: 成熟、生产级别
- 极快启动: <125ms 启动时间
- 极低开销: 5MB 内存开销
- 强隔离: 硬件虚拟化 (KVM)
- 良好文档: 丰富的文档和示例
┌──────────────────────────────────────────┐
│ Host Machine (OpenCLI Daemon) │
│ │
│ ┌────────────────────────────────────┐ │
│ │ Firecracker VMM Process │ │
│ │ │ │
│ │ ┌──────────────────────────────┐ │ │
│ │ │ MicroVM (Guest) │ │ │
│ │ │ │ │ │
│ │ │ • Alpine Linux (20MB) │ │ │
│ │ │ • OpenCLI Task Runner │ │ │
│ │ │ • vsock 通信 │ │ │
│ │ │ │ │ │
│ │ │ 资源限制: │ │ │
│ │ │ • 1 vCPU │ │ │
│ │ │ • 256 MB RAM │ │ │
│ │ │ • 10 MB/s 网络 │ │ │
│ │ │ • 只读 rootfs │ │ │
│ │ │ • 临时 tmpfs (100MB) │ │ │
│ │ └──────────────────────────────┘ │ │
│ └────────────────────────────────────┘ │
│ │
│ 通信: vsock (虚拟socket) │
│ • CID: 3 (guest) │
│ • Port: 8000 │
└──────────────────────────────────────────┘
- 安装 Firecracker 依赖 (KVM, Linux 4.14+)
- 创建 Alpine Linux rootfs 镜像
- 实现 Firecracker API 客户端
- 创建基本的 VM 启动/停止脚本
- 实现
MicroVMPool类 - 实现 VM 生命周期管理
- 实现预热和重用策略
- 添加监控和日志
- 实现 vsock 通信层
- 定义任务序列化格式
- 实现结果回传机制
- 添加超时和错误处理
- 实现
SecurityRouter类 - 定义任务分类规则
- 实现安全等级评估
- 添加配置和策略管理
- 实现本地执行路径
- 实现 VM 执行路径
- 添加执行环境选择逻辑
- 实现降级和回退机制
- 创建 Guest Agent (Dart/Go)
- 实现任务接收和解析
- 实现命令执行
- 实现结果收集
- 实现文件系统访问限制
- 实现网络访问白名单
- 实现资源使用监控
- 实现超时强制终止
- VM 创建和销毁测试
- 任务执行测试
- 错误处理测试
- 性能基准测试
- 隔离验证测试
- 逃逸攻击测试
- 资源限制测试
- 恶意输入测试
- 启动时间优化
- 内存使用优化
- 并发性能优化
- 监控和告警
- 架构文档
- 部署指南
- 安全策略文档
- 故障排查指南
security:
# 启用 MicroVM 隔离
microvm_enabled: true
# MicroVM 配置
microvm:
# Firecracker 路径
firecracker_path: /usr/local/bin/firecracker
# 内核镜像
kernel_image: /opt/opencli/firecracker/vmlinux
# rootfs 镜像
rootfs_image: /opt/opencli/firecracker/rootfs.ext4
# VM 池配置
pool:
min_idle: 2
max_total: 10
idle_timeout: 300 # 5 分钟
# 资源限制
resources:
memory_mb: 256
vcpu_count: 1
network_bandwidth_mbps: 10
disk_quota_mb: 100
# 超时
timeouts:
boot_timeout: 5
task_timeout: 300 # 5 分钟
shutdown_timeout: 10
# 任务分类规则
task_classification:
dangerous_operations:
- execute_shell_command
- install_package
- system_modify
- network_request
- file_delete
review_operations:
- file_write
- file_create
- open_application
- take_screenshot
safe_operations:
- file_read
- file_list
- system_info
- search| 阶段 | 时间 | 说明 |
|---|---|---|
| Firecracker 启动 | ~20ms | VMM 进程启动 |
| VM 配置 | ~30ms | API 调用配置 |
| 内核启动 | ~50ms | Linux 内核启动 |
| Guest Agent | ~25ms | Agent 初始化 |
| 总计 | ~125ms | 用户可接受 |
| 资源 | 每个 VM | 5 个 VM | 说明 |
|---|---|---|---|
| 内存 | 256 MB | 1.28 GB | Guest + 开销 |
| VMM 内存 | 5 MB | 25 MB | Firecracker 进程 |
| CPU | 1 vCPU | 5 vCPU | 限制使用 |
| 磁盘 | 50 MB | 250 MB | rootfs + tmp |
| 操作类型 | 本地执行 | VM 执行 | 开销 |
|---|---|---|---|
| 简单命令 | 10ms | 150ms | +1400% |
| 文件操作 | 5ms | 130ms | +2500% |
| 网络请求 | 200ms | 350ms | +75% |
| AI 调用 | 1000ms | 1150ms | +15% |
结论: 对于危险操作,150ms 开销是可接受的安全代价。
✅ 进程隔离: 完全独立的内核和用户空间 ✅ 内存隔离: 硬件级别的内存保护 ✅ 文件系统隔离: 只读 rootfs + 临时 tmpfs ✅ 网络隔离: 白名单防火墙规则 ✅ 资源限制: CPU/内存/磁盘/网络配额 ✅ 时间限制: 强制超时和终止
┌──────────────────────────────────────────┐
│ Host System (Trusted) │
│ │
│ ┌────────────────────────────────────┐ │
│ │ OpenCLI Daemon │ │
│ │ • 完整文件系统访问 │ │
│ │ • 网络访问 │ │
│ │ • 系统调用 │ │
│ └────────────────────────────────────┘ │
│ │
│ │ KVM 硬件虚拟化边界 │
│ ▼ │
│ │
│ ┌────────────────────────────────────┐ │
│ │ MicroVM (Untrusted) │ │
│ │ │ │
│ │ ❌ 无法访问 host 文件系统 │ │
│ │ ❌ 无法访问 host 进程 │ │
│ │ ❌ 无法访问 host 网络 │ │
│ │ ✅ 只能通过 vsock 通信 │ │
│ │ ✅ 受限的 CPU/内存 │ │
│ │ ✅ 临时文件系统 (销毁后清除) │ │
│ └────────────────────────────────────┘ │
└──────────────────────────────────────────┘
用户: "显示当前目录的文件"
OpenCLI:
1. 分类: Safe → 本地执行
2. 执行: ls -la
3. 返回结果
执行时间: ~10ms
用户: "安装 npm 包 lodash"
OpenCLI:
1. 分类: Dangerous → MicroVM 隔离
2. 请求用户确认
3. 获取 VM (125ms 启动)
4. 执行: npm install lodash
5. 返回结果
6. 销毁 VM
执行时间: ~3s (安全优先)
// 自动路由任务
final result = await securityRouter.routeTask(Task(
operation: 'execute_shell_command',
params: {
'command': 'curl https://api.example.com',
},
));
// MicroVM 会自动处理:
// 1. 检测到 dangerous 操作
// 2. 获取或创建 VM
// 3. 隔离执行
// 4. 收集结果
// 5. 清理资源问题: Firecracker 只支持 Linux + KVM
解决方案:
┌─────────────────────────────────────────┐
│ 平台适配策略 │
│ │
│ • Linux (x86_64) → Firecracker ✅ │
│ • macOS (Intel/M1) → gVisor 🟡 │
│ • Windows → WSL2 + KVM 🟡 │
│ • 不支持的平台 → 降级到本地 ⚠️ │
└─────────────────────────────────────────┘
问题: 125ms 启动时间影响用户体验
解决方案:
- 预热 VM 池 (维持 2-3 个空闲 VM)
- 异步执行 + 进度通知
- 批量任务共享 VM
问题: VM 需要访问用户文件
解决方案:
1. 只读挂载特定目录
/workspace → /mnt/workspace (ro)
2. 通过 vsock 传输小文件
<1MB: 直接传输
>1MB: 挂载只读
3. 结果通过 vsock 返回
- ✅ 默认禁用 MicroVM
- ✅ 通过配置启用
- ✅ 仅 shell 命令使用 MicroVM
- ✅ 收集性能数据
- ✅ 默认启用 (可降级)
- ✅ 扩展到更多危险操作
- ✅ 优化启动时间
- ✅ 生产监控
- ✅ 强制启用 (安全要求)
- ✅ 所有危险操作隔离
- ✅ 性能优化完成
- ✅ 安全审计通过
| 阶段 | 工作量 | 说明 |
|---|---|---|
| 基础设施 | 2-3 周 | Firecracker 集成 |
| Security Router | 1-2 周 | 路由和分类 |
| Guest Agent | 1 周 | VM 内任务执行 |
| 测试 | 1 周 | 功能和安全测试 |
| 部署 | 1 周 | 优化和文档 |
| 总计 | 6-8 周 | 1-2 名工程师 |
| 资源 | 成本 | 说明 |
|---|---|---|
| CPU | 低 | VM 空闲时几乎无开销 |
| 内存 | ~1-2 GB | 5 个 VM 池 |
| 磁盘 | ~500 MB | rootfs + 日志 |
| 总计 | 可接受 | 现代机器完全支持 |
| 指标 | 改进 |
|---|---|
| 代码注入风险 | 🔴 High → 🟢 Low |
| 权限提升风险 | 🔴 Critical → 🟢 Low |
| 数据泄露风险 | 🟠 High → 🟡 Medium |
| 系统破坏风险 | 🔴 Critical → 🟢 Low |
- ✅ 安心运行第三方插件
- ✅ 信任 AI 生成的命令
- ✅ 企业级安全合规
- ✅ 透明的安全策略
- AWS Lambda - 使用 Firecracker
- Fly.io - 使用 Firecracker
- CloudFlare Workers - 使用 V8 Isolates
理由:
- 🔴 当前风险高: 所有代码在 daemon 进程中运行
- ✅ 技术成熟: Firecracker 生产级别,AWS 验证
- ✅ 性能可接受: 125ms 启动,对用户影响小
- ✅ 成本合理: 6-8 周开发,1-2 GB 内存
- ✅ 安全提升明显: 多个关键风险降低到 Low
现在 ──────────────────────────────▶ 3个月后
│ │
│ Phase 1: 基础设施 (3周) │
│ ↓ │
│ Phase 2: 路由器 (2周) │
│ ↓ │
│ Phase 3: Guest Agent (1周) │
│ ↓ │
│ Phase 4: 测试 (1周) │
│ ↓ │
│ Phase 5: 部署 (1周) │
│ │
└────────────────────────────────────┘
6-8周开发周期
文档版本: 1.0 下次审查: 2026-03-04 负责人: 安全团队