做容器安全扫描的开发者大概都经历过这种场景:跑一次 trivy 或 grype,输出几十条甚至上百条 CVE,逐条排查后发现大部分根本打不不到你的环境——要么漏洞只在特定架构下可利用,要么依赖路径根本没走到有问题的函数。噪音太多,真正需要修的反而容易被淹没。
Docker 和 Aikido 这次集成做的事情很直接:Docker Hardened Images(DHI)内置了 VEX 文档,Aikido 扫描时自动消费这些 VEX 数据,Docker 已验证为不可利用的漏洞直接从结果里消失。
VEX 是什么,为什么它能降噪
VEX(Vulnerability Exploitability eXchange)是 CSAF 标准下的一个子规范,核心思路很简单:一个 CVE 存在 ≠ 它可利用。VEX 文档用结构化格式声明某个 CVE 在特定产品/版本/配置下的状态——under_investigation、not_affected、affected、fixed——并附上理由和详情。
对容器镜像来说,这特别有价值。基础镜像里一个 lib 的 CVE 可能只在调用某个罕见代码路径时才触发,而镜像默认配置根本不会走到那里。Docker 对 Hardened Images 做了逐 CVE 的工程验证,把结论写成 VEX 文档打包进镜像元数据。
Aikido 怎么消费 DHI 的 VEX 数据
集成的工作流:
- Aikido 对你的项目做常规漏洞扫描,检出所有 CVE。
- 扫描结果中涉及 DHI 基础镜像的 CVE,Aikido 自动查询该镜像的 VEX 文档。
- VEX 标记为
not_affected的 CVE 从报告里移除,不再出现在待处理队列。 - 开发者只看到
affected和under_investigation的条目,聚焦真正有风险的发现。
这意味着你不需要手动去 Docker Hub 查公告、不需要在 Aikido 里一条条标记 "忽略",过滤是自动且可追溯的——每条被过滤的 CVE 都有 VEX 文档背书,审计时可以回查。
实际操作:用 DHI + Aikido 跑一次低噪音扫描
下面演示如何在项目中使用 Docker Hardened Images 并配合 Aikido 扫描。前提是你已有 Aikido 账户并连接了 GitHub/GitLab 仓库。
1. 拉取 Docker Hardened Images 作为基础镜像
DHI 目前覆盖了常用官方镜像(alpine、nginx、python、node 等),标签格式与官方镜像一致,但通过 docker.io/docker 组织发布(具体命名以 Docker 官方文档为准)。以下是一个 Dockerfile 示例:
# 使用 Docker Hardened Image 作为基础镜像
FROM docker.io/docker/hardened-python:3.12-slim
WORKDIR /app
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
COPY . .
CMD ["python", "main.py"]
注意:DHI 的具体镜像名和可用标签请查阅 Docker 官方文档和 Hub 页面,上例中的
docker/hardened-python为示意格式,实际命名可能不同。构建前确认你拉取的确实是 Hardened 版本。
2. 在 Aikido 中启用 DHI VEX 过滤
Aikido 的 DHI 集成在扫描引擎层面自动生效,不需要额外配置开关。但你需要确保:
- Aikido 已连接你的代码仓库并启用了容器扫描。
- 项目 Dockerfile 中使用的是 DHI 基础镜像(而非普通官方镜像)。
# 确认本地拉取的是 Hardened Image
docker inspect docker.io/docker/hardened-python:3.12-slim \
--format '{{.RepoTags}} {{index .Config.Labels "org.opencontainers.image.source"}}'
如果镜像标签中包含 Docker Hardened 相关的元数据或 VEX 引用,说明你用的是 DHI。
3. 触发扫描并查看过滤效果
# 通过 Aikido CLI 或 API 触发扫描(以 CLI 为例)
aikido scan --repo my-org/my-project --branch main
# 查看扫描结果,关注 "filtered by VEX" 字段
aikido results list --repo my-org/my-project \
--format json | jq '.vulnerabilities[] | select(.vex_status == "not_affected") | .cve_id'
被 VEX 过滤掉的 CVE 不会出现在默认报告里,但可以通过 --include-vex-filtered 参数查看完整列表以做审计:
aikido results list --repo my-org/my-project \
--include-vex-filtered \
--format json | jq '[.vulnerabilities[] | {cve_id, vex_status, vex_reason}]'
4. 手动验证一条被过滤的 CVE
如果你对某条被标记为 not_affected 的 CVE 存疑,可以直接查看 VEX 文档:
# 从镜像元数据中提取 VEX 文档引用(示意命令,具体路径以 DHI 实际格式为准)
docker inspect docker.io/docker/hardened-python:3.12-slim \
--format '{{index .Config.Labels "com.docker.vex.document"}}'
拿到 VEX 文档 URL 后,用 csaf 工具或直接浏览器打开,查看该 CVE 的状态声明和理由。
采纳建议与边界
适合立即采用的场景:
- 你的项目直接使用 Docker 官方基础镜像(alpine、python、nginx 等),且 Docker 已提供对应的 Hardened 版本——替换成本极低,只需改 Dockerfile 的 FROM 行。
- 团队被漏洞噪音困扰,每周花大量时间排查 "不可利用" 的 CVE——VEX 自动过滤能直接减少工作量。
需要注意的边界:
- VEX 过滤只覆盖 DHI 基础镜像层面的 CVE。你在基础镜像之上自己安装的依赖(pip 包、npm 包等)的漏洞不在 VEX 覆盖范围内,仍需正常排查。
- VEX 文档反映的是 Docker 验证时的结论。如果你的应用对基础镜像做了非标准配置(比如启用了默认关闭的网络服务),原本 not_affected 的 CVE 可能变为可利用——这种情况下应自行评估,不要盲目依赖 VEX 状态。
- DHI 目前覆盖的镜像范围有限,如果你的基础镜像没有 Hardened 版本,这个集成暂时帮不到你。
快速检查清单:
- [ ] Dockerfile 的
FROM行是否已替换为对应的 Hardened Image? - [ ] Aikido 是否已连接仓库并启用容器扫描?
- [ ] 扫描结果中是否出现了
vex_status字段? - [ ] 对被过滤的 CVE,是否偶尔抽查 VEX 文档确认理由与你的实际部署一致?
- [ ] 自行安装的依赖层漏洞是否仍有人负责跟进?
这次集成解决的不是 "消灭漏洞",而是 "消灭噪音"。把不可利用的 CVE 从队列里拿掉,开发者才能把有限的时间花在真正能被打穿的地方。