mirror of
https://github.com/whyour/qinglong.git
synced 2026-09-20 16:07:11 +08:00
99 lines
7.2 KiB
Markdown
99 lines
7.2 KiB
Markdown
# ADR-0254:Digest 固定的跨架构 OS 漏洞发布门
|
||
|
||
> ADR-0255 supersedes 本 ADR 决策 5 中 release candidate 到 publisher 的传输方式:release 现在 build once、扫描
|
||
> exact OCI layout tar,并按同一 audited digest 发布。本 ADR 的 base pin、Trivy pin、OS-only gate 与例外治理继续有效。
|
||
|
||
- 状态:Accepted(base pin、策略审计器、CI/release 接线与负向测试已实现;联网六矩阵扫描记录待取得)
|
||
- 日期:2026-08-01
|
||
- 关联 RFC:QL-RFC-0001 D-14、D-61、D-128、D-186、D-236、D-237
|
||
- 关联 ADR:ADR-0128、ADR-0195、ADR-0196、ADR-0253
|
||
|
||
## 背景
|
||
|
||
QingLong 3.0 已对 npm production graph 执行 high/critical advisory gate,但这不覆盖 Debian/base image OS package。
|
||
同时 control/admin Dockerfile 仍通过可覆盖的 `ARG NODE_IMAGE` 引用 tag,而 local image 已固定多架构 digest;即使
|
||
对某次本地 build 扫描通过,后续 build 也可能解析到另一份基础镜像。
|
||
|
||
Trivy 官方在 2026-03 披露过 action/tag 与部分二进制发布渠道被篡改的供应链事件,并明确要求 action 使用完整
|
||
commit SHA。D-237 不能用 movable `@v0.x` 或 `latest` 引入一个拥有 workflow 执行能力的 scanner。
|
||
|
||
## 决策
|
||
|
||
1. control、control-ai、admin、local、worker 的 dependency/build stage 固定
|
||
`node:24.18.0-bookworm-slim@sha256:6f7b03f7c2c8e2e784dcf9295400527b9b1270fd37b7e9a7285cf83b6951452d`,最终 runtime stage 固定更小的
|
||
`node:24.18.0-alpine3.23@sha256:595398b0081eacda8e1c4c5b97b76cd1020e4d58a8ebcb4843b9bca1e79e7436`。
|
||
control/admin 删除 `ARG NODE_IMAGE`,所有 runtime base 都不得由 build arg 覆盖;四个 Dockerfile 继续拥有独立应用闭包和
|
||
最终 image digest。构建与运行基座分离,避免把编译工具链和 Bookworm 的 Perl/util-linux/ncurses 包带入低配设备与集群运行镜像。
|
||
2. scanner 固定为 Trivy `v0.70.0`,GitHub Action 固定完整 commit
|
||
`ed142fd0673e97e23eac54620cfb913e5ce36c25`(action `v0.36.0`)。禁止 tag、`master`、`latest`、
|
||
`continue-on-error` 和 scanner cache;网络、release asset 或 vulnerability DB 不可用均失败关闭。
|
||
3. 只扫描 `vuln-type=os`、`scanners=vuln`、severity `HIGH,CRITICAL`,`ignore-unfixed=false`、exit code 1。
|
||
npm/library advisory 继续由既有 production dependency audit 独立负责,不能用 OS 例外隐藏应用依赖漏洞。
|
||
4. `.github/workflows/ql3-ci.yml` 复用已经存在的 native build:control、control-ai、admin、local、worker
|
||
各 amd64+arm64,共十个真实本地 image。每个 build 后生成 image-scoped ignore view 并执行 Trivy。
|
||
5. release workflow 增加独立只读 `os-vulnerability` 十矩阵 job,在发布前用 exact Dockerfile、base digest、lock 和
|
||
source revision 构建 native candidate。`publish` 必须同时依赖 D-236 private evidence 与全部 OS scan 成功,
|
||
才能获得 GHCR/OIDC/attestation 写权限。scan job 不读取 D-236 私密 source,不参与签名或 publish。
|
||
6. 唯一例外事实源为 `deploy/containers/ql3-os-vulnerability-exceptions.json`。顶层和每条 entry 都是 exact shape;
|
||
每条必须包含唯一且排序的 CVE、非空且排序的 `admin|control|local` image 集合、非空且排序的
|
||
`pkg:apk|deb|rpm` purl、owner、ticket、20–512 字理由和未来到期日。
|
||
7. 例外最多 128 条,单条例外最长 30 天;到期当天即无效。策略审计器为每个 image 生成临时 `0600`、no-replace
|
||
`.trivyignore.yaml`,映射为 Trivy 官方 `id+purls+expired_at+statement`。不得直接维护 `.trivyignore`、全局 CVE ID、
|
||
path skip、Rego allow-all、VEX bypass 或无期限 exception。
|
||
8. 当前 production policy 为 `exceptions=[]`。新增例外必须先关联安全 ticket、指定责任 owner、确认 package purl 与
|
||
受影响 image、设置最短到期日,并通过变异测试;修复 base 后立即删除,不等待到期。
|
||
9. scanner、生成器、策略和 workflow 都是 repository/release-time 工具,不新增 workspace package、第三方 runtime
|
||
dependency、migration、daemon、controller、timer、watcher、listener、Pool 或 Profile 常驻资源。
|
||
|
||
## 失败与恢复
|
||
|
||
- base digest/tag/action/version 漂移:静态审计失败,先审查上游 release 与签名,再显式更新 ADR/测试;
|
||
- scanner 或 DB 下载失败:CI/release 失败,不回退到旧 DB、不跳过扫描;
|
||
- HIGH/CRITICAL 命中且无例外:升级基础镜像/OS package;只有短期无法修复时才按本 ADR 添加 exception;
|
||
- exception 到期、超过 30 天、缺 owner/ticket/rationale、使用 library purl 或 image scope 为空:policy gate 失败;
|
||
- 一个架构构建/扫描失败:整个 `os-vulnerability` matrix 不满足,三个 publisher 都不得启动;
|
||
- 本地临时 scanner 下载超时:只能记录“未取得本地 live scan”,不能把静态契约或 checksum 预检记为漏洞通过。
|
||
|
||
## 被拒绝的替代方案
|
||
|
||
### 发布后扫描 GHCR digest
|
||
|
||
拒绝。HIGH/CRITICAL 被发现前 tag/manifest 已进入 registry;发布前 native candidate scan 才能阻止写入。
|
||
|
||
### 只扫描 amd64
|
||
|
||
拒绝。多架构 base 的 OS package/config 可能不同,amd64 结果不能证明 arm64 路由器/节点镜像。
|
||
|
||
### `ignore-unfixed=true`
|
||
|
||
拒绝。它把所有无修复漏洞变成隐式永久例外;D-237 要求每个例外有 scope、owner、ticket、理由和到期日。
|
||
|
||
### 直接提交 `.trivyignore.yaml`
|
||
|
||
拒绝。Trivy 的 `statement` 不参与过滤,且原生 schema 不要求 owner、ticket、最长周期或 image scope;仓库级严格
|
||
策略生成 image-specific view 可以补足这些治理约束。
|
||
|
||
### 用 action tag 或 scanner `latest`
|
||
|
||
拒绝。上游供应链事故已证明 tag 可被重写;完整 action commit 与 exact scanner version 是最低可接受边界。
|
||
|
||
## 验证
|
||
|
||
- OS exception policy 8/8:empty、image scope、purl、owner/ticket/rationale、expired/same-day/>30 天、排序/重复、
|
||
`0600` no-replace 与 exact CLI;
|
||
- image release contract 34/34:新增覆盖 CI/release action pin、六矩阵、publish dependency、unfixed、OS-only、
|
||
cache 与既有签名/SBOM/provenance 门;
|
||
- Cluster deployment 31/31,包含 control/admin mutable/overridable base 负向测试;
|
||
- 2026-08-22 CI 的 Bookworm runtime 扫描在 amd64/arm64 同时发现 30 个 HIGH/CRITICAL;同版 Trixie Slim 为 51 个,
|
||
Debian 13 distroless 为 1 个无修复 HIGH。固定的 Alpine 3.23 multiarch digest 使用同一 Trivy 0.70.0 与同一数据库扫描,
|
||
amd64/arm64 均为 0 HIGH/CRITICAL,且 Node 版本仍为 24.18.0;完整十镜像远端扫描仍是合并门;
|
||
- `audit:image-release:ql3` 返回 Trivy 0.70.0、exact action commit、amd64/arm64、OS-only、HIGH/CRITICAL、
|
||
`ignoreUnfixed=false`、maximum exception 30 days;
|
||
- 当前 policy `exceptionCount=0`;workspace 保持 19 个 package,无新增 runtime dependency。
|
||
|
||
## 上游依据
|
||
|
||
- Trivy filtering 与 YAML `id/purls/expired_at/statement`:<https://trivy.dev/docs/latest/configuration/filtering/>;
|
||
- Trivy ecosystem supply-chain advisory:<https://github.com/aquasecurity/trivy/security/advisories/GHSA-69fq-xp46-6x23>;
|
||
- Trivy Action v0.36.0:<https://github.com/aquasecurity/trivy-action/releases/tag/v0.36.0>。
|