首页
/ Trivy 漏洞数据库体系解析:从公告源采集到扫描消费的多仓库工作流与数据源贡献指南

Trivy 漏洞数据库体系解析:从公告源采集到扫描消费的多仓库工作流与数据源贡献指南

2026-09-05 10:01:23作者:江焘钦

本文围绕 Trivy 漏洞数据库(Trivy DB)的运作机制展开,讲清「公告采集 → 数据库构建 → 扫描消费」这条贯穿四个仓库的完整工作流,说明原始公告为何要存放在独立的 vuln-list 仓库中,并结合 Trivy 主仓库的真实源码(如 Echo OS 的检测器、数据库客户端)深入剖析各阶段的实现细节,最后给出为 Trivy 新增漏洞公告数据源的完整实操步骤。读完本文,你将理解 Trivy DB 从上游公告到 trivy scan 结果的来龙去脉,并能按文档步骤独立为一个新系统或生态系统贡献公告数据源。

一、多仓库工作流总览

Trivy 的漏洞数据库并非单仓库构建,而是通过一套多仓库协作的工作流完成,涉及三个核心仓库与 Trivy 主仓库:

graph LR
    A[Advisory Sources] -->|vuln-list-update| B[vuln-list]
    B --> C["trivy-db<br/>(Trivy DB)"]
    C --> D["trivy<br/>(Trivy CLI)"]
    E[GitHub-managed<br/>Advisories] --> C

三个工作流阶段

  1. 公告采集(vuln-list-update 仓库)

    • 从上游公告源(API 或网页)抓取原始安全公告(advisory);
    • 将公告存入 vuln-list 仓库;
    • 通过定时任务(cron)周期性运行,保持公告时效性;
    • 如果公告本身已托管在 Git 仓库中(例如 GitHub Security Advisories),可以跳过这一步。
  2. 数据库构建(trivy-db 仓库)

    • 从 vuln-list 解析公告,或直接从 Git 托管的源(如 GitHub Security Advisories)读取;
    • 将公告转换(transform)为 Trivy 的数据库格式;
    • 同样通过 cron 周期性地发布构建好的数据库。
  3. 数据库消费(Trivy 主仓库)

    • 扫描时下载最新的漏洞数据库;
    • 利用数据库在扫描目标中检测漏洞。

这条链路的本质是「原始公告的快照库 + 格式转换器 + 消费端」三层解耦:上游公告格式再怎么变化,影响范围被隔离在采集与解析两个环节内,最终暴露给 Trivy CLI 的始终是稳定的数据库格式。

二、为什么要把公告存放在 vuln-list?

对于尚未被 Git 托管的公告源,把原始公告统一存入 vuln-list 仓库带来多重收益,这也是该仓库存在的核心原因:

  • 透明性(Transparency):可以方便地追踪公告版本之间的变更与差异;
  • Web UI:可以直接在仓库的 Web 界面上以友好的方式浏览公告内容;
  • 稳定性(Stability):缓解上游公告服务器不稳定或不可用带来的问题——即使上游宕机,vuln-list 中仍保留最近一次抓取的完整快照;
  • 可引用性(Shareability):可以为特定公告提供稳定的 URL 供引用;
  • 数据质量(Data Quality):在提交进 vuln-list 之前先校验公告数据,防止格式错误或非预期的格式变更破坏 Trivy DB 的构建;
  • 历史数据(Historical Data):当上游格式发生变化时,历史公告仍被完整保留。

需要注意的一个约束:vuln-list 仓库不接受手动贡献,直接对它的 Pull Request 不会被采纳,公告更新只能通过 vuln-list-update 的抓取脚本自动完成。这一约束正是「数据质量」保障的落点——所有进入数据库的公告都必须先经过抓取脚本的校验。

三、四个仓库的分工

vuln-list-update:抓取脚本仓库

包含从各种上游源抓取公告的脚本。每个数据源有自己独立的包,负责:

  • 从 API 或 Web 源抓取公告;
  • 校验公告格式与数据;
  • 将结果保存为 vuln-list 目录结构下的 JSON 文件。

抓取脚本的一个重要约定(见下文贡献指南):尽可能原样保存上游数据,避免预处理或修改公告字段,只做诸如 YAML 转 JSON 这类格式统一。

vuln-list:原始公告数据仓库

存放由 vuln-list-update 抓取到的原始公告,特点:

  • 包含 JSON 格式的原始公告数据;
  • 由 vuln-list-update 脚本通过 cron 自动更新;
  • 不用于手动贡献,直接 PR 不被接受;
  • 作为 trivy-db 构建漏洞数据库的数据来源。

trivy-db:解析与数据库构建仓库

包含将原始公告转换为 Trivy 数据库格式的解析器。每个数据源有自己的 vulnerability source handler,负责:

  • 从 vuln-list 读取公告文件,或直接读取 Git 托管的源(如 GitHub Security Advisories);
  • 将公告字段映射(map)到 Trivy 的 schema;
  • 将漏洞信息存入数据库。

trivy(主仓库):分析器与检测逻辑

Trivy 主仓库中承担漏洞数据库「消费端」角色,包含:

  • OS 与软件包分析器:检测目标中安装了什么(pkg/fanal/analyzer/ 下的分析器体系);
  • 漏洞检测逻辑:拿检测结果与数据库中的公告做匹配(pkg/detector/ 下的检测器体系)。

四、源码级剖析:Trivy 主仓库如何消费漏洞数据库

4.1 数据库下载:OCI Artifact 拉取模型

文档中提到「扫描时下载最新漏洞数据库」。在源码中,这一过程由 pkg/db/db.go 中的 Client 实现,关键事实:

  • 数据库以 OCI artifact 的形式发布,媒体类型常量定义为 application/vnd.aquasec.trivy.db.layer.v1.tar+gzippkg/db/db.go#L26);
  • 默认拉取仓库有两个:GitHub Container Registry 的 ghcr.io/aquasecurity/trivy-db:<schema-version> 和 GCR 镜像 mirror.gcr.io/aquasec/trivy-db:<schema-version>,标签就是数据库 schema 版本号(pkg/db/db.go#L29-L36)。这解释了为什么 trivy-db 的产物要按 schema 版本打标签发布——消费端按当前 CLI 支持的 schema 版本精确选取;
  • 本地数据库以 BoltDB 只读方式打开(Init 中强制 ReadOnly: true,见 pkg/db/db.go#L43-L46),扫描过程绝不修改数据库文件。

NeedsUpdate 方法(pkg/db/db.go#L105-L161)实现了文档隐含的「何时重新下载」决策逻辑,值得注意的边界行为:

  • 本地缺少 trivy.dbmetadata.json 任一文件时,判定需要下载,且此时不允许 --skip-db-update(首次运行必须能拿到数据库);
  • 本地 DB schema 高于当前 CLI 支持的版本时,直接报错要求升级 Trivy;
  • 本地 schema 与 CLI 不一致时,触发重新下载;
  • --skip-db-update 场景下会额外校验本地 schema 是否匹配,不匹配则报错,防止离线环境用错版本数据库;
  • 新鲜度判断有两道门:当前时间早于 NextUpdate,或数据库在最近一小时内下载过,则跳过更新(isNewDBpkg/db/db.go#L172-L184)。

这正是贡献指南中测试命令 trivy image --skip-db-update --cache-dir ... 能生效的底层机制:它绕过拉取,直接使用本地构建的数据库。

4.2 检测器如何读取数据库:以 Echo OS 为例

文档中「Add Vulnerability Advisory Source」一节以 Echo OS 支持为完整示例(涉及三个仓库的联动 PR)。在主仓库中,该示例的落地代码是 pkg/detector/ospkg/echo/echo.go,它是理解「trivy-db 解析结果如何被消费」的最佳入口:

  • Scanner 持有一个 echoDb.VulnSrc,它来自 trivy-db 仓库的 pkg/vulnsrc/echo 包(见 echo.go#L19-L27)——也就是说,trivy-db 仓库产出的不仅是数据库文件,还有按数据源划分的 Go 读取接口,Trivy 主仓库通过 import 这些 vulnsrc 包来读库;
  • Detect 方法对每个已安装的包调用 s.vs.Get(db.GetParams{PkgName: pkg.SrcName}) 取出该包的所有公告,再用 go-deb-version 比较已安装版本与 FixedVersion:只有安装版本小于修复版本时才记为漏洞(echo.go#L29-L78);
  • 严重级别(Severity)取自公告本身,来源标记为 vulnerability.Echo,说明严重级别由上游公告源提供而非 Trivy 重新评定(echo.go#L58-L63);
  • 两个针对滚动发行版的特殊设计值得注意:IsSupportedVersion 恒返回 true,因为 Echo 是滚动发行版、没有固定版本,无需版本支持性检查;FilterPackages 不过滤任何包,因为 Echo 的公告 feed 不绑定基础 OS 厂商,Trivy 构建并修补了 Debian 根本没有的软件包,按仓库类别过滤包反而可能漏报(echo.go#L80-L90)。

这体现了一个通用模式:不同数据源的检测器可以有不同的包过滤策略与版本判断策略,而读取数据库的入口形态(vulnsrc + Get)保持一致。语言生态(npm、Go module 等)的检测同样走 pkg/detector/library/ 下的 driver 抽象:Detect 按包类型找到对应 driver 后逐个包查询漏洞,见 pkg/detector/library/detect.go#L14-L26

4.3 OS 分析器:检测「这是哪个操作系统」

贡献指南要求「在 pkg/fanal/analyzer/os/ 下添加 OS 分析器来检测新 OS」。主仓库中 pkg/fanal/analyzer/os/ 下按发行版家族组织了分析器(alpine、amazonlinux、debian、redhatbase、ubuntu 等,以及基于 /etc/os-release 的通用 release 分析器)。以 Echo OS 为例,它没有单独的目录,其发行版识别落在基于 os-release 文件的 pkg/fanal/analyzer/os/release/release.go 中(该文件包含对 echo 发行版的处理)。从源码结构看,对于通过 /etc/os-release 即可识别的发行版,复用 release 分析器即可,无需新建独立分析器;而 Alpine、Debian、RedHat 这类有专有包管理元数据的发行版则需要各自的分析器解析 apk/dpkg/rpm 等来源。

五、实操指南:为 Trivy 新增一个漏洞公告数据源

以下内容继承自 Add Vulnerability Advisory Source 指南,并对照主仓库结构说明验证点。

5.1 前置条件

开始之前确认三件事:

  1. 已识别上游公告源及其 API/数据格式;
  2. 已确认该数据源尚不存在于 Trivy 中;
  3. 已在 Trivy 仓库中创建 discussion 或 issue 讨论新增事宜。

5.2 三仓库联动改动

步骤 1:在 vuln-list-update 添加抓取脚本

若公告源已托管在 Git 仓库(如 GitHub、GitLab)中可跳过此步。核心任务:

  • 从上游 API 或源抓取公告;
  • 校验公告格式与数据;
  • 按 vuln-list 的目录结构将公告保存为 JSON 文件;
  • 尽量原样存储上游数据:避免预处理或修改公告字段,原始数据按上游提供的样子保存(YAML 转 JSON 这类格式统一可以接受);
  • 包含所有必要元数据(CVE ID、受影响版本、严重级别等)。

步骤 2:在 trivy-db 添加解析器

  • pkg/vulnsrc/ 下创建新的 vulnerability source;
  • 实现公告解析逻辑;
  • 将公告字段映射到 Trivy 的漏洞 schema;
  • 正确处

理版本范围与受影响软件包;

  • 如有 CVE 映射则一并存储;
  • 为解析器添加单元测试。

这个 pkg/vulnsrc/<source> 包正是 4.2 节中 Trivy 检测器所 import 的读取接口来源,两侧的接口约定由此闭合。

步骤 3:在 Trivy 主仓库添加 OS/生态支持

  • pkg/fanal/analyzer/os/ 添加 OS 分析器以检测该系统(如 4.3 节所述,能复用 release 分析器的发行版可不新建目录);
  • pkg/detector/ospkg/ 下实现该系统的漏洞检测逻辑(参考 pkg/detector/ospkg/echo/echo.go 的结构:实现 DetectIsSupportedVersionFilterPackages 等接口);
  • 添加带测试数据的集成测试(主仓库 integration/testdata/ 下有大量以 <os>.json.golden 命名的 golden 文件约定可循);
  • 更新文档以纳入新数据源。

完整示例:Echo OS 支持的三处联动

Echo OS 支持通过三个协调的 PR 完成:

  1. vuln-list-update:从 Echo 的公告接口(advisory.echohq.com/data.json)抓取公告;
  2. trivy-db:解析 Echo 公告并存入数据库;
  3. Trivy:检测 Echo OS 并扫描其漏洞。

这组联动 PR 是新增任何数据源时最好的参照实现。

5.3 分仓库验证流程

验证 vuln-list-update

先抓取全部既有公告(构建数据库所必需),再单独测试新数据源:

cd vuln-list-update
go run main.go -vuln-list-dir /path/to/vuln-list

# 只抓取你的目标源
go run main.go -target your-source -vuln-list-dir /path/to/vuln-list

确认公告被正确写入 vuln-list 目录后即可进入下一步。

验证 trivy-db

cd trivy-db
make db-build CACHE_DIR=/path/to/cache

注意 CACHE_DIR 应指向 vuln-list 目录的父目录:例如 vuln-list 位于 /tmp/test/vuln-list,则设 CACHE_DIR=/tmp/test。构建无报错且包含你的公告后,可以用 BoltDB 查看工具(如 boltwiz)检查产物:

boltwiz out/trivy.db

验证 Trivy

# 构建 Trivy
mage build

# 使用本地数据库扫描
./trivy image --skip-db-update --cache-dir /path/to/cache your-test-image

确认新数据源的漏洞被正确检出。该流程之所以可行,正是因为 4.1 节描述的 --skip-db-update 校验逻辑允许在 schema 匹配的本地数据库上跳过下载。

5.4 遇到问题时

  1. 查阅现有数据源的参照实现(如 Echo 的三仓库代码);
  2. 在 Trivy 仓库发起 discussion 寻求帮助。

六、小结

Trivy 漏洞数据库体系的设计核心是「采集、存储、转换、消费」四段式解耦:vuln-list-update 负责带校验的周期性抓取,vuln-list 提供透明、稳定、可追溯的原始公告快照,trivy-db 将公告映射进按 schema 版本管理的 BoltDB 数据库并以 OCI artifact 发布,Trivy CLI 在扫描时按 schema 精确拉取、只读打开并与分析器结果做匹配。为这套体系贡献新数据源的工作,就是在这四个环节分别补齐抓取脚本、解析器(vulnsrc)与 OS 分析器/检测器,并用文中给出的分仓库验证命令逐段打通。理解 pkg/db/db.go 的更新决策逻辑与 pkg/detector/ospkg/echo/echo.go 的检测器模式,是阅读或扩展 Trivy 漏洞数据链路的两个最佳切入点。

登录后查看全文
热门项目推荐
相关项目推荐