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 里,每个语言作为一个独立的组件分组。这个功能在审计时特别方便,不用来回切换工具。
package.json 没有 package-lock.json,生成的 SBOM 可能不准确。我建议 CI 流程里强制生成锁文件。
2.4 工具选型对比
三个工具各有侧重。我整理了一张对比表,方便你快速决策:
| 维度 | Syft | Trivy | cdxgen |
|---|---|---|---|
| 主要场景 | 容器镜像 | 文件系统/镜像 | 应用源码目录 |
| 输出标准 | SPDX、CycloneDX | CycloneDX、SPDX | CycloneDX |
| 语言覆盖 | 系统包 + 常见语言 | 系统包 + 常见语言 | 40+ 语言/包管理器 |
| 速度 | 极快 | 快 | 中等 |
| 典型集成 | Dockerfile CI 阶段 | CI/CD 扫描门禁 | 开发本地生成 |
2.5 本章知识体系
下面这张图概括了三个工具的核心定位和适用边界:
2.6 小结
这一章我们走了三个工具的实际操作。Syft 适合容器镜像,Trivy 适合文件系统,cdxgen 适合应用源码。没有万能工具,关键是根据你的部署形态选对路子。