SBOM 生成工具实战:Syft 与 Trivy 的硬核用法

好,咱们直接进入正题。SBOM 不是靠嘴说出来的,得靠工具一把一把生成。这一章我带你亲手操作两个最主流的工具:Syft 和 Trivy。一个专攻容器镜像,一个擅长文件系统扫描,搭配起来基本能覆盖 90% 的场景。

我个人习惯把 Syft 放在 CI 流水线的构建阶段,Trivy 放在部署前的验收环节。为什么这么安排?往下看你就明白了。

2.1 用 Syft 生成容器镜像 SBOM

Syft 是 Anchore 家的开源工具,主打一个「快」字。你给它一个镜像,它几分钟就能吐出完整的包清单。

2.1.1 安装与基础用法

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

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

然后直接跑:

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

这条命令会拉取 nginx:1.25 镜像,分析里面的所有软件包,输出成 JSON 格式。你想想看,一个 Nginx 镜像里居然有 80 多个包——连 libc、zlib 这种底层库都给你列得清清楚楚。

小技巧: 如果你只想看某个特定类型的包,比如只看 Python 包,可以加 --select-catalogers python。我在排查一个 Flask 应用漏洞时,就用这招把无关的包过滤掉,定位速度快了一倍。

2.1.2 输出格式选择

Syft 支持多种输出格式,我列个表给你对比:

格式 适用场景 文件大小 可读性
JSON 程序解析、入库 中等 一般
SPDX JSON 合规审计、供应链共享 较大 较好
CycloneDX JSON 漏洞管理平台对接 中等 较好
Table 人工快速查看 小 最好

我个人推荐生产环境用 CycloneDX JSON。为什么?因为大部分漏洞扫描工具(包括 Trivy)都原生支持这个格式,省去转换的麻烦。

2.2 用 Trivy 生成文件系统 SBOM

Trivy 大家可能更熟悉它的漏洞扫描功能,但它也能生成 SBOM。而且它支持文件系统扫描,这对那些「不能容器化」的传统应用特别有用。

2.2.1 扫描本地目录

假设你有一个 Java 项目,目录结构是标准的 Maven 项目:

trivy filesystem --format cyclonedx --output app-sbom.json ./my-java-app

这条命令会扫描 ./my-java-app 目录下的所有文件,识别出 pom.xml 里声明的依赖,以及 lib/ 目录下的 JAR 包。我记得有一次帮客户做合规审计,他们有个 10 年历史的单体应用,就是用 Trivy 的文件系统模式扫出了 200 多个过时的库。

注意: Trivy 文件系统扫描默认不会进入 .git 目录和 node_modules(如果太大)。如果你需要扫描这些目录,得加 --scanners filesystem 参数。我曾经因为漏扫 node_modules,导致一个原型污染漏洞没被发现,后来补上的时候差点被运维同事骂死。

2.2.2 扫描容器镜像(对比 Syft)

Trivy 也能扫镜像,但和 Syft 的侧重点不同:

  • Syft:专注 SBOM 生成,速度快,格式规范,适合 CI 构建阶段。
  • Trivy:SBOM 生成 + 漏洞扫描二合一,适合验收阶段。

我通常这样搭配:Syft 在构建时生成 SBOM 并存入数据库,Trivy 在部署前拿着这个 SBOM 去查漏洞。这样既保证了 SBOM 的完整性,又避免了重复扫描。

2.3 SBOM 格式解析:JSON 与 XML

生成 SBOM 只是第一步,读懂它才是关键。咱们拿一个实际的 CycloneDX JSON 片段来拆解:

{
  "bomFormat": "CycloneDX",
  "specVersion": "1.4",
  "version": 1,
  "components": [
    {
      "type": "library",
      "name": "openssl",
      "version": "1.1.1k",
      "purl": "pkg:generic/openssl@1.1.1k",
      "licenses": [
        {
          "license": {
            "id": "OpenSSL"
          }
        }
      ],
      "supplier": {
        "name": "OpenSSL Software Foundation"
      }
    }
  ]
}

这里有几个关键字段你得记住:

  • bomFormat:格式标识,CycloneDX 或 SPDX。
  • components:组件列表,每个组件包含名称、版本、类型。
  • purl:包统一资源定位符,这是跨工具识别的关键。说白了,有了 purl,Trivy 才能知道这个包对应哪个 CVE。
  • licenses:许可证信息,合规审计时必看。

2.3.1 JSON vs XML:怎么选?

维度 JSON XML
解析速度 快(原生支持) 慢(需 DOM/SAX 解析)
可读性 好 一般(标签多)
工具支持 几乎所有语言都有库 传统工具支持好
文件大小 小 大(冗余标签)
Schema 验证 较弱 强(XSD)

我的建议是:新项目无脑选 JSON。除非你的合规部门要求必须用 XML 格式归档,否则 JSON 在性能和易用性上都完胜。

2.4 本章知识体系总览

下面这张图帮你理清 Syft 和 Trivy 在整个 SBOM 生命周期中的位置:

SBOM 生成工具工作流 SBOM 生成工具工作流 容器镜像 文件系统目录 Syft Trivy 输出格式:CycloneDX JSON / SPDX JSON / XML 漏洞扫描(Trivy) 合规审计 供应链共享 说明:Syft 侧重容器镜像的快速 SBOM 生成,Trivy 兼顾文件系统扫描与漏洞检测,两者互补使用效果最佳

2.5 避坑指南与最佳实践

最后分享几个我踩过的坑,你遇到了能少走弯路:

坑1:镜像层缓存导致 SBOM 不完整
有一次我用 Syft 扫描一个基于 Alpine 的自定义镜像,发现少了几个包。后来排查发现是 Docker 构建缓存导致的——基础镜像层没更新,Syft 只扫到了新增层。解决方案:构建时加 --no-cache 参数,或者用 syft <image> --scope all-layers 强制扫描所有层。
坑2:Trivy 文件系统扫描权限问题
扫描 /usr/lib 这种系统目录时,Trivy 可能会因为权限不足而跳过某些文件。我曾经在 CI 里用普通用户跑扫描,结果漏掉了几个系统库的漏洞。后来改成 sudo trivy filesystem 才解决。但注意,生产环境别随便给 sudo,建议用专门的扫描容器。
坑3:SBOM 格式版本不匹配
不同工具对 CycloneDX 版本的支持不一样。Syft 默认输出 1.4,但有些老版本的漏洞管理平台只认 1.2。我建议统一用 --output cyclonedx-json=1.4 指定版本,并在平台侧做好兼容性测试。