审计报告 ~/workspace/chv-security-audit/REPORT.md(No-Go, Critical 0 / High 7 / Medium 8 / Low 5)代码层修复,mock 测试覆盖,真机动态验证一律未做、只列清单(见 docs/chv-production-readiness.md §11)。 High: - H1 egress 代码门:代理地址校验、直连显式允许+审计、 每 VM 独立 tap/mac/ip 校验、net 字段白名单;宿主防火墙 列为部署清单,代码门+防火墙缺一不可。 - H2 网关 key 移出 argv:provisioned seed 盘客内文件 /etc/chv/guest-env(0600)投递,传输层密钥进 argv 直接 ValueError;keyscan 模式密钥投递 fail-closed。 - H3 任务盘删除:stop/recycle/cleanup 删 disk.raw(保留期 0)+ 残留盘 GC,删失败审计+脏标记。 - H4 默认值改 provisioned:keyscan 只作显式 opt-in。 - H5 seed.iso 生成即 0600;宿主私钥 seed 盘建好后即删; 崩溃残留扫描 cleanup_stale_secrets。 - H6 state_dir 默认出 /tmp(~/.local/share/.../chv-vms, preflight 保 0700);api-socket 组/其它可写即 fail-fast。 - H7 tap 隔离校验:net.json 登记+stop 释放,共享即拒绝审计。 Medium:M1 shlex 远程转义;M2 清理失败即拒起(脏标记); M3 配额默认 50GB + 快照数/总量/保留期上限;M4 SHA256 必填 + BUILDINFO versions 实测记录(事前 lockfile 列清单); M5 host key/ preflight/失败审计补齐;M6 reuse 须声明单租户 项目;M7 容量计数只认连通 socket;M8 sshd 加固进 build.sh 断言。Low:L1 链接不跟随;L2 路径白名单;L3 失败审计; L4 双变量警告+字段白名单;L5 预热盘/任务盘对应关系定义。 旧测试:实验室默认值与生产默认值区分标注;行为已变的旧 测试按新语义更新(容量死 socket、快照白名单、磁盘路径 白名单、网关 argv、reuse 租户声明)。 测试:新 test_chv_secfix 39 项;旧 117 项 + 2 项新增断言 = 158 项;worker 相关 129 项;前端 vitest 9 项;cloud 全量 1588 项(skipped 4)。
102 lines
6.5 KiB
Markdown
102 lines
6.5 KiB
Markdown
# Cloud Hypervisor 客机镜像(chv-guest)——内容清单与版本化构建说明
|
||
|
||
> 本目录有清单与真实构建步骤(build.sh,补缺口轨已实做),
|
||
> 但镜像本身不在本轨内实际构建发布。原因写在前面,不藏着:
|
||
> 当前没有带 /dev/kvm 的宿主可以构建并实测 VM 镜像(生产
|
||
> 主机是 CVM、无嵌套虚拟化;本 VM 容器内同样无 /dev/kvm)。
|
||
> 构建与实测见 `docs/chv-production-readiness.md` 的“需镜像
|
||
> 构建 / 需 KVM 宿主实测”项,绝不在本轨声称镜像已建成、
|
||
> 已发布、已跑通。
|
||
|
||
## 1. 镜像定位
|
||
|
||
- 基础:Ubuntu 云镜像(与 `cloud/docker/Dockerfile` 的任务镜像
|
||
对齐能力,不是另起一套环境口径)。
|
||
- 载体:Cloud Hypervisor 直接内核启动(vmlinux)+ raw 磁盘
|
||
镜像,执行器用 `CHV_KERNEL` / `CHV_ROOTFS` 指向它们。
|
||
- 客内 host.py 位置:`/app/host.py`(与 Docker 的 `/app:ro`
|
||
同款约定,只是载体从容器只读挂载换成 VM 镜像内置代码;
|
||
代码版本 = 构建时仓库 commit,见 §3 版本化)。
|
||
- 绝不进镜像的东西:任何模型 key、系统 key、用户账号数据、
|
||
生产凭证。模型 key 由客机 cloud-init 预置的运行环境变量名
|
||
注入(与 Docker 的 `-e <名>` 同款惯例),不写进镜像层。
|
||
|
||
## 2. 内容清单(按现有 Docker 任务镜像能力对齐)
|
||
|
||
| 类别 | 内容 | 来源/版本口径 |
|
||
| --- | --- | --- |
|
||
| 语言与工具链 | Python 3.12、git(Node.js 不装:Playwright 驱动是 Python playwright,见 PLAYWRIGHT=1 分支;任务镜像 Dockerfile 里也没有 Node.js,本清单不虚构它) | 与任务镜像同款大版本,构建时钉小版本并记入构建日志 |
|
||
| 文档/图片工具 | pandoc、poppler-utils(pdftotext)、latexmk、texlive-latex-base、python-docx、openpyxl、python-pptx、PyMuPDF、Pillow | 逐项照抄 `cloud/docker/Dockerfile` 的 apt/pip 清单,不擅自加减 |
|
||
| agent 引擎 | codex、codex-code-mode-host、codex-resources/bwrap(成套,约 367M,缺 sibling 直接构建失败) | codex 0.164.0-alpha.9(与生产任务镜像一致);`CODEX_BIN_DIR` 由构建方提供,bin/ 不进仓库 |
|
||
| 浏览器 | Playwright + Chromium(浏览器自动化 MCP 用,PLAYWRIGHT=1 时才装) | Python playwright 装当时的 Chromium,未在 BUILDINFO 里钉浏览器版本——这是已知缺口,不是已钉死 |
|
||
| 客机基础 | openssh-server(SSH 通道用)、cloud-init、qemu-guest-agent(可选,宿主信息用) | sshd 只允许 key 登录,禁止密码登录——build.sh 写入 /etc/ssh/sshd_config.d/99-chv.conf 并经 sshd -t + grep 断言(feat-chv-secfix,M8,此前只是文档声称) |
|
||
| 任务代码 | codex-app-server 仓库代码置于 `/app`(host.py 入口) | 版本见 §3,不挂载宿主代码目录(VM 与宿主无共享路径) |
|
||
|
||
中文 LaTeX 说明:与 Docker 镜像同款口径——xelatex + CJK
|
||
字体会再增数百 MB,本清单不默认包含;需要时单独一版镜像,
|
||
不在本轨悄悄加。
|
||
|
||
## 3. 版本化
|
||
|
||
镜像 tag 格式(构建时三项缺一即失败,不生成无版本镜像):
|
||
|
||
```
|
||
chv-guest-<ubuntu 版本>-<codex 版本>-<仓库 commit 短 hash>
|
||
```
|
||
|
||
例如(示例格式,非已建成):`chv-guest-24.04-0.164.0-alpha.9-aebc623`。
|
||
|
||
构建产物清单(构建方必须输出,执行器用它做 preflight 之外的
|
||
版本核对,v1 执行器暂不校验 tag,见就绪清单):
|
||
|
||
- `vmlinux`(与 Ubuntu 云镜像配套的内核)
|
||
- `disk.raw`(根文件系统镜像)
|
||
- `BUILDINFO.json`:`{ubuntu, codex_version, repo_commit, built_at,
|
||
contents: [清单逐项名]}`——注意:build.sh 生成的 contents 只有
|
||
名字列表,没有逐项版本号(feat-chv-fix 纠正 §3 旧措辞);
|
||
逐项版本只留在构建日志里,未进 BUILDINFO,这是已知缺口。
|
||
|
||
## 4. 构建脚本(补缺口轨:已从骨架改成真实步骤)
|
||
|
||
见 `build.sh`:参数校验 → 下载 Ubuntu 云镜像 → qemu-img
|
||
转 raw → virt-customize 装 §2 清单、拷入 codex 成套二进制
|
||
与仓库代码到 /app、写 host key 不重生成配置 →
|
||
virt-get-kernel 取内核 → 生成并校验 BUILDINFO.json。
|
||
`./build.sh --dry-run out/` 只打印命令、不执行、不要求
|
||
KVM;全量模式在无 /dev/kvm 的机器上第一步就明确退出
|
||
(`CHV_GUEST_BUILD needs a KVM host`),绝不假装构建成功。
|
||
本轨未在真机上跑过全量模式,镜像未建成、未发布,仍属
|
||
“需 KVM 宿主实测”项。
|
||
|
||
## 5. Host key 首启注入硬性要求(补缺口轨新增)
|
||
|
||
执行器的 per-VM 预置方案(见 `cloud/chv/hostkeys.py`)能
|
||
跑通的前提是客机镜像必须满足以下全部,否则预置在真机
|
||
上跑不通,执行器会 fail-fast,不回落成弱方案:
|
||
- 装 cloud-init 且支持 NoCloud seed(seed 磁盘(CIDATA ISO,feat-chv-fix 起挂进 VmConfig
|
||
第二块只读盘)由执行器在 VM 启动前生成,含 meta-data 与 user-data);
|
||
- 首启时先应用 seed 再启动 sshd,seed 里的 user-data
|
||
把该 VM 的 host key 对写进 /etc/ssh/ 并重启 sshd;
|
||
- 镜像里已钉死 `ssh_deletekeys: false` 与
|
||
`ssh_genkeytypes: []`(build.sh 已写),首启不得无条件
|
||
重新生成 host key——重生成会使预置的 known_hosts 立即
|
||
失效,SSH 钉死直接拒绝,这是设计,不是 bug;
|
||
- sshd 只允许 key 登录,禁止密码登录(build.sh 写入
|
||
/etc/ssh/sshd_config.d/99-chv.conf:PasswordAuthentication no、
|
||
PermitRootLogin prohibit-password、ChallengeResponseAuthentication no、
|
||
KbdInteractiveAuthentication no、PubkeyAuthentication yes,并经
|
||
sshd -t + grep 断言;feat-chv-secfix,M8);
|
||
- seed 磁盘是 per-VM 敏感物,执行器在 VM 关闭/
|
||
回收时删除,镜像构建方不得把任何一把 host key 固化
|
||
进镜像(所有 VM 同 key 是安全事故)。
|
||
|
||
## 6. 与执行器的对接
|
||
|
||
- 执行器 preflight 只校验内核/镜像文件存在且可读,不校验镜像
|
||
内容版本——内容版本核对(BUILDINFO)是镜像发布流程的责任,
|
||
在就绪清单里标为“需镜像构建”项,不在本轨假装已做。
|
||
- 每任务磁盘:执行器 copy 模式下把 `disk.raw` 复制为每任务
|
||
磁盘,任务之间文件系统独立;reuse 模式仅单租户实验,preflight 拦截(须同时设 CHV_REUSE_SINGLE_TENANT_EXPERIMENT=1 并审计放行,feat-chv-fix)。
|
||
- 快照基准:`CHV_SNAPSHOT_URL` 指向的快照必须由本镜像的干净
|
||
启动状态制成(pause 后 snapshot),预热池用它做干净 VM 来源。
|