Files
qinglong/docs/operations/ql3-image-os-vulnerability-gate.md
T

5.8 KiB
Raw Blame History

QingLong 3.0 镜像 OS 漏洞门

本流程覆盖 control|control-ai|admin|local|worker × amd64|arm64 十个 release candidate 的 OS/base image package,不替代 npm production dependency audit、CycloneDX、BuildKit SBOM/provenance、Cosign 或 GitHub attestation。

日常检查

pnpm audit:image-os-vulnerability-policy:ql3
pnpm audit:image-release:ql3
pnpm audit:cluster-deployment:ql3

默认 exception policy 位于 deploy/containers/ql3-os-vulnerability-exceptions.json,当前必须返回:

{"schemaVersion":1,"fixture":"qinglong/image-os-vulnerability-exceptions@v1","compatible":true,"exceptionCount":0,"imageExceptionCounts":{"admin":0,"control":0,"local":0}}

真实 scan 在 QL3 CI 已有十个 native build 后执行;受保护 release 的十个 native job 各自只构建一次 OCI layout tar Trivy 直接扫描该 tar。扫描成功后才解包、审计并上传同一 OCI graphpublisher 只合并 amd64/arm64 graph,不再 build。 只有六份 artifact 和 D-236 私密 evidence job 全部成功,publisher 才会启动。scanner/DB 网络故障与漏洞命中使用相同 的失败关闭结果,但日志会区分下载错误和 finding。

Build-once 发布链

每个 control|admin|local × amd64|arm64 native job 固定执行:

  1. Buildx 用 exact Dockerfile、source revision、SBOM 与 provenance 生成 ${RUNNER_TEMP}/ql3-native/image.oci.tar
  2. Trivy 以 input 扫描该 tar,禁止 daemon/candidate tag
  3. 扫描成功后解包到 layout/repository recorder 复验 platform、source、SBOM/provenance 和全部 digest,写入 evidence.json,随后删除 tar
  4. run_id/run_attempt/image/arch 唯一命名上传 layout + evidence,保留 1 天且禁止 overwrite。

publisher 的固定顺序是:下载同一 run attempt 的两份 native artifact → 本地重验并确定性 merge → 生成最终 OS vulnerability predicate → checksum 验证 regctl → 登录 GHCR → IMAGE@DIGEST import → 读取远端 digest 比对 → Cosign/SLSA/CycloneDX/OS-vulnerability attest 与 verify → manifest/rollout verify → 最后创建 version 与完整 commit tag。 publisher 不得安装 Buildx/QEMU、运行 Dockerfile 或在 tag promotion 后追加 step。

创建短期例外

优先升级 digest-pinned Node base。只有当前没有可部署修复且风险被明确接受时,才能在 central JSON 的 exceptions 中增加一项:

{
  "id": "CVE-2026-12345",
  "images": ["admin", "control"],
  "purls": ["pkg:deb/debian/libssl3@3.0.0-1"],
  "owner": "security/platform",
  "ticket": "QLSEC-123",
  "expiresOn": "2026-08-15",
  "rationale": "Temporary exposure accepted while the fixed base image is qualified."
}

约束:

  • entries 按 id 严格升序,ID 唯一;images/purls 各自唯一且升序;
  • 只接受 CVE-*pkg:apk|deb|rpm,不能屏蔽 npm/library finding
  • expiresOn 必须晚于 UTC 当天且最多 30 天,到期当天自动失败;
  • owner、ticket、rationale 缺一不可;ticket 必须先完成独立安全复核;
  • 不得使用 ignore-unfixed=true、裸 .trivyignore、skip path、allow-all Rego 或无期限 VEX 代替本策略。

提交前执行:

node --test test/back/ql3ImageOsVulnerabilityPolicy.test.cjs
node --test test/back/ql3ClusterImageReleaseAudit.test.cjs
pnpm audit:image-os-vulnerability-policy:ql3
pnpm audit:image-release:ql3

策略生成器会为每个 image 创建临时 .trivyignore.yamlTrivy action 会把该低敏 exception view 显示在 job log。 不得在 rationale、owner 或 ticket 中写 credential、内部 URL、个人数据或 Secret。

升级 scanner 或基础镜像

  1. 阅读 Trivy 官方 release 与 security advisory,确认目标版本不在已知暴露窗口;
  2. 解析 signed/immutable action release 到完整 commit SHA,审查 composite action 的所有 nested action pin
  3. 固定 scanner exact version,禁止 latest;保持 cache false、OS-only、unfixed 不忽略;
  4. 对 Node base 的多架构 manifest digest 执行签名/来源核验;四个 production Dockerfile 的 runtime stage 必须同步更新 exact digest
  5. 更新 ADR、静态审计 expectation 与 mutation tests;执行十个 native scan 后才能发布;
  6. 修复后删除已不需要的 exceptions,不等待 expiresOn

失败恢复

  • native job 失败或 artifact 未生成:重新运行整个 release;不要手工上传 artifact 或把旧 run artifact 改名复用;
  • artifact/evidence/layout digest 不一致:视为供应链完整性失败,从 native build 重新开始,不通过重新打 tar 修复;
  • regctl checksum 或下载失败:禁止回退到未固定 binary、docker push 或先推 candidate tag
  • exact digest 已导入但证明/验证失败:不要创建 tag。保留 digest 用于调查,修复后由新 run 重建;
  • tag promotion 失败:确认目标 tag 没有指向其他 digest;不得覆盖不一致 tag来“完成”发布;
  • 清理 runner 时只删除该 job 的 ${RUNNER_TEMP}/ql3-native${RUNNER_TEMP}/native 和 merge 输出,不能删除 workspace、D-236 owner-private source 或共享 Docker/Kind 资源。

当前证据边界

仓库已证明 policy、workflow、base pin、build-once/scanned-digest merge 和 fail-closed mutation contract。本机尝试 真实 OCI attested build 时,Docker container driver 获取 BuildKit SBOM scanner 遇到网络超时并已中止,临时目录已 删除,因此没有本地 live CVE clean 结论。首次 GitHub-hosted 六矩阵成功记录和首个 evidence-backed GHCR exact-digest publish 仍属于外部 Release Gate。control/admin 的 exact Dockerfile 已在本机 arm64 成功构建并确认 10001:10001, 对应临时 image 随后已删除;这只证明 build/base pin,不替代漏洞数据库扫描。