4. SBOM生成实战(一):对Java项目(Maven/Gradle)生成SBOM、对Python项目(pip/poetry)生成SBOM。

好,咱们直接进入正题。前面聊了那么多SBOM的理论和标准,今天终于要动手了。我个人习惯,学任何东西,先跑起来再说。你想想看,光看文档不敲命令,永远记不住。

这一章,我们聚焦两个最主流的生态:Java 和 Python。说白了,就是搞定 Maven/Gradle 和 pip/poetry 的项目。我会带着你,一行命令一行命令地生成真正的 SPDX 和 CycloneDX 格式的 SBOM。

核心目标:今天结束后,你能对自己手头的 Java 或 Python 项目,用一条命令生成一份可用的 SBOM 文件。

4.1 为什么先从这两个生态开始?

我在项目中遇到过不少团队,一上来就想搞全量扫描,结果被各种奇奇怪怪的依赖报错搞崩溃。其实,Java 和 Python 的包管理工具最成熟,社区对 SBOM 的支持也最完善。先把这两个啃下来,后面再搞 Go、JavaScript 甚至容器镜像,就顺理成章了。

嗯,这里要注意:生成 SBOM 不是目的,目的是拿到一份准确的、可被工具解析的依赖清单。所以,我们不仅要会跑命令,还要知道生成的 SBOM 里到底写了啥。

4.2 Java 项目:Maven 生成 SBOM

Maven 是 Java 生态的老大哥。我建议你直接用 CycloneDX Maven 插件,它稳定、更新快,而且生成的 CycloneDX 格式是目前最通用的。

4.2.1 安装与配置

在项目的 pom.xml 里,加入插件配置。别怕,就几行代码。

<plugin>
    <groupId>org.cyclonedx</groupId>
    <artifactId>cyclonedx-maven-plugin</artifactId>
    <version>2.7.9</version>
    <executions>
        <execution>
            <phase>package</phase>
            <goals>
                <goal>makeAggregateBom</goal>
            </goals>
        </execution>
    </executions>
</plugin>

这里我用了 makeAggregateBom 而不是 makeBom。为什么?前者会聚合所有模块的依赖,包括父子模块。如果你是多模块项目,一定要用这个。我曾经见过有人用错了,结果只生成了子模块的 SBOM,漏掉了公共依赖,排查了半天。

4.2.2 执行生成

配置好后,直接运行:

mvn package

或者,如果你只想生成 SBOM 而不想打包:

mvn cyclonedx:makeAggregateBom

命令跑完后,在 target/ 目录下会生成 bom.json 和 bom.xml 两个文件。默认是 CycloneDX 格式。

小技巧:如果你需要 SPDX 格式,可以用 mvn cyclonedx:makeAggregateBom -Dcyclonedx.outputFormat=spdx。不过我个人更推荐 CycloneDX,它对组件元数据的支持更丰富。

4.2.3 验证 SBOM 内容

打开 bom.json,你会看到类似这样的结构:

{
  "bomFormat": "CycloneDX",
  "specVersion": "1.4",
  "version": 1,
  "metadata": {
    "component": {
      "name": "my-java-app",
      "version": "1.0.0"
    }
  },
  "components": [
    {
      "type": "library",
      "name": "log4j-core",
      "version": "2.17.1",
      "purl": "pkg:maven/org.apache.logging.log4j/log4j-core@2.17.1"
    }
  ]
}

注意看 purl 字段,这是包统一资源标识符,它是 SBOM 的灵魂。有了它,安全工具才能精准定位到具体的组件版本。

4.3 Java 项目:Gradle 生成 SBOM

Gradle 用户也别急。我建议用 CycloneDX Gradle 插件,用法和 Maven 版本几乎一样。

4.3.1 配置

在 build.gradle 里添加:

plugins {
    id 'org.cyclonedx.bom' version '1.7.4'
}

4.3.2 执行

./gradlew cyclonedxBom

生成的文件在 build/reports/ 目录下,默认也是 bom.json 和 bom.xml。

避坑指南:我曾经在 Gradle 6.x 版本上遇到过插件不兼容的问题。如果你用的是老版本 Gradle,记得先升级到 7.0 以上,或者指定兼容的插件版本。否则,生成的 SBOM 可能会缺少传递性依赖。

4.4 Python 项目:pip 生成 SBOM

Python 的情况稍微复杂一点。pip 本身不直接生成 SBOM,但我们可以借助 cyclonedx-bom 这个工具。

4.4.1 安装工具

pip install cyclonedx-bom

4.4.2 生成 SBOM

假设你的项目已经生成了 requirements.txt:

cyclonedx-py -i requirements.txt -o bom.json

如果你用的是 pipenv,可以这样:

cyclonedx-py -p -o bom.json

这里 -p 参数表示从 Pipfile.lock 读取依赖。

4.4.3 一个重要的细节

嗯,这里要注意:pip 生成的 SBOM 质量,完全取决于你的 requirements.txt 是否准确。如果你只是随便 pip freeze > requirements.txt,里面可能包含了大量全局环境的包,而不是项目真正需要的。我建议你始终使用虚拟环境,并且只导出项目依赖。

最佳实践:在 CI/CD 中,每次构建前都重新生成 requirements.txt,确保 SBOM 与当前构建的代码一致。

4.5 Python 项目:Poetry 生成 SBOM

Poetry 用户就幸福多了。它原生支持导出 SBOM,而且格式更规范。

4.5.1 生成 CycloneDX 格式

poetry export --format cyclonedx --output bom.json

4.5.2 生成 SPDX 格式

poetry export --format spdx --output bom.spdx.json

你看,一行命令搞定。Poetry 的 poetry.lock 文件本身就包含了精确的版本和依赖树,所以生成的 SBOM 非常可靠。

个人经验:如果你在团队里推广 SBOM,我建议优先推荐 Poetry。它把依赖管理和 SBOM 生成整合得很好,减少了出错的环节。我在一个 50 人的 Python 团队里推过,反馈非常好。

4.6 知识体系:SBOM 生成流程总览

为了让你更直观地理解整个流程,我画了一张图。它展示了从项目源码到最终 SBOM 文件的完整路径。

SBOM 生成流程总览 项目源码 包管理工具 SBOM 生成器 SBOM 文件 关键说明: • 项目源码通过包管理工具(Maven/Gradle/pip/Poetry)解析依赖树 • SBOM 生成器读取依赖信息,转换为标准格式(CycloneDX/SPDX) • 最终输出 JSON 或 XML 格式的 SBOM 文件,包含所有组件和元数据 • 整个过程应在 CI/CD 流水线中自动化执行,确保每次构建都有对应的 SBOM

4.7 工具对比与选择建议

为了帮你快速决策,我整理了一个对比表。你可以根据自己项目的实际情况选择。

生态 工具 推荐格式 生成速度 依赖完整性
Java (Maven) cyclonedx-maven-plugin CycloneDX 快 高(含传递依赖)
Java (Gradle) cyclonedx-gradle-plugin CycloneDX 快 高(含传递依赖)
Python (pip) cyclonedx-bom CycloneDX 中 中(依赖 requirements.txt 质量)
Python (Poetry) poetry export CycloneDX / SPDX 快 高(基于 lock 文件)

重要提醒:无论你用哪个工具,生成 SBOM 后一定要做一次完整性校验。我见过太多人跑完命令就不管了,结果 SBOM 里缺了关键依赖。最简单的办法:用 jq 或 python 解析生成的 JSON,统计组件数量,再和项目实际依赖数对比一下。

4.8 实战小结

好了,今天的内容就到这里。你学会了:

  • 对 Maven 项目,用 cyclonedx-maven-plugin 生成 SBOM
  • 对 Gradle 项目,用 cyclonedx-gradle-plugin 生成 SBOM
  • 对 pip 项目,用 cyclonedx-bom 工具生成 SBOM
  • 对 Poetry 项目,用 poetry export 直接导出 SBOM