2. SBOM 生成工具:Syft、Trivy 与 cdxgen 实战

聊到 SBOM 生成,很多团队第一反应是「找个工具跑一下就行」。嗯,没那么简单。不同的场景、不同的工件类型,选错工具会让你拿到一堆无效数据。我个人习惯把 SBOM 生成分成三类:容器镜像、文件系统、应用依赖。对应的,我常用三个工具——Syft、Trivy 和 cdxgen。

这一章,咱们就逐个上手。我会把每个工具的典型用法、输出格式、以及我在项目中踩过的坑都摊开来讲。

2.1 用 Syft 生成容器镜像 SBOM

Syft 是 Anchore 开源的 SBOM 生成工具。它最大的特点是快,而且对容器镜像的支持非常成熟。你想想看,一个几百 MB 的镜像,Syft 几秒钟就能把里面的包列表扒出来。

2.1.1 安装 Syft

安装方式很简单,我一般用一键脚本:

curl -sSfL https://raw.githubusercontent.com/anchore/syft/main/install.sh | sh -s -- -b /usr/local/bin

或者用 Docker 直接跑:

docker run --rm -v /var/run/docker.sock:/var/run/docker.sock anchore/syft:latest <镜像名>

2.1.2 生成容器镜像 SBOM

假设你有一个镜像 nginx:1.25,生成 SPDX 格式的 SBOM:

syft nginx:1.25 -o spdx-json > nginx-sbom.spdx.json

输出格式我常用三种:

格式 适用场景 备注
spdx-json 合规审计、工具链对接 SPDX 2.3 标准,信息最完整
cyclonedx-json 漏洞扫描、依赖分析 CycloneDX 1.5 标准,轻量
table 人工快速查看 终端直接打印,不生成文件
我的习惯: 生产环境一律用 spdx-json。为什么?因为 SPDX 标准对许可证信息的描述更细,审计时少扯皮。

2.1.3 避坑指南

我曾经在生成一个基于 Alpine 的镜像时,发现 Syft 漏掉了好几个系统包。后来排查发现,是镜像层被清理过,部分包管理器元数据丢失了。解决办法是:尽量用完整镜像,不要用 --squash 或 --no-cache 过度精简。

2.2 用 Trivy 生成文件系统 SBOM

Trivy 大家可能更熟悉它的漏洞扫描功能。但很多人不知道,Trivy 也能生成 SBOM。而且它支持文件系统扫描,这对非容器化部署的场景特别有用。

2.2.1 安装 Trivy

sudo apt-get install trivy   # Ubuntu/Debian
brew install trivy           # macOS

2.2.2 生成文件系统 SBOM

扫描一个本地项目目录,输出 CycloneDX 格式:

trivy filesystem --format cyclonedx --output result.cdx.json ./my-project

这里有个关键点:Trivy 的文件系统扫描会递归分析所有依赖文件。比如 package-lock.json、go.sum、requirements.txt 等。它不依赖包管理器,而是直接解析锁文件。

核心区别: Syft 主要面向容器镜像层,Trivy 的文件系统模式更适合裸机或虚拟机上的应用目录。两者互补,不是替代关系。

2.2.2 我遇到的一个坑

有一次扫描一个 Java 项目,Trivy 生成的 SBOM 里少了十几个依赖。查了半天,发现是 pom.xml 里用了 <optional>true</optional> 的依赖,Trivy 默认不包含。解决办法是加参数:

trivy filesystem --include-optional-deps --format cyclonedx --output result.cdx.json ./my-project

嗯,这个参数藏得比较深,文档里不太起眼。

2.3 用 cdxgen 生成应用 SBOM

cdxgen 是 OWASP CycloneDX 社区维护的工具。它专攻应用层依赖,支持的语言和包管理器非常全。我个人觉得,如果项目是微服务架构、多语言混用,cdxgen 是最顺手的选择。

2.3.1 安装 cdxgen

推荐用 npm 全局安装:

npm install -g @cyclonedx/cdxgen

或者用 Docker:

docker run --rm -v $(pwd):/app cyclonedx/cdxgen -r /app -o /app/bom.json

2.3.2 生成应用 SBOM

在项目根目录执行:

cdxgen -r -o bom.json

-r 表示递归扫描子目录。cdxgen 会自动识别项目类型,比如检测到 package.json 就用 npm 模式,检测到 go.mod 就用 Go 模式。

输出格式默认是 CycloneDX JSON。你也可以指定其他格式:

参数 输出格式 典型场景
-o bom.json CycloneDX JSON 通用,工具链兼容性好
-o bom.xml CycloneDX XML 老旧系统对接
--spec-version 1.5 指定标准版本 需要最新字段时使用

2.3.3 多语言项目的处理

我维护过一个项目,前端用 npm、后端用 Go、还有几个 Python 脚本。cdxgen 能一次性搞定:

cdxgen -r --multi-project -o bom.json

--multi-project 会把不同语言的依赖合并到一个 SBOM 里,每个语言作为一个独立的组件分组。这个功能在审计时特别方便,不用来回切换工具。

注意: cdxgen 依赖包管理器锁文件。如果项目里只有 package.json 没有 package-lock.json,生成的 SBOM 可能不准确。我建议 CI 流程里强制生成锁文件。

2.4 工具选型对比

三个工具各有侧重。我整理了一张对比表,方便你快速决策:

维度 Syft Trivy cdxgen
主要场景 容器镜像 文件系统/镜像 应用源码目录
输出标准 SPDX、CycloneDX CycloneDX、SPDX CycloneDX
语言覆盖 系统包 + 常见语言 系统包 + 常见语言 40+ 语言/包管理器
速度 极快 快 中等
典型集成 Dockerfile CI 阶段 CI/CD 扫描门禁 开发本地生成

2.5 本章知识体系

下面这张图概括了三个工具的核心定位和适用边界:

SBOM 生成工具选型框架 SBOM 生成 Syft 容器镜像层扫描 Trivy 文件系统/目录扫描 cdxgen 应用源码依赖分析 SPDX / CycloneDX 镜像层 + 系统包 CycloneDX / SPDX 锁文件 + 系统包 CycloneDX 40+ 语言依赖 适用场景:容器化部署 → 非容器化部署 → 多语言微服务 建议:CI 流水线中组合使用,覆盖全生命周期

2.6 小结

这一章我们走了三个工具的实际操作。Syft 适合容器镜像,Trivy 适合文件系统,cdxgen 适合应用源码。没有万能工具,关键是根据你的部署形态选对路子。