3、SBOM实战:在CI/CD中集成SBOM生成、SBOM版本管理
说实话,很多团队做供应链安全,第一步就卡在「我们连自己用了哪些组件都不清楚」。SBOM(软件物料清单)就是解决这个问题的。但光生成一份SBOM没用,你得把它嵌入到开发流程里,让它跟着版本走,每次构建都自动更新。
这一章,我就带你走一遍实战流程。从工具选型到CI/CD集成,再到版本管理策略,咱们一步到位。
3.1 选对工具:SBOM生成器怎么挑?
市面上SBOM生成工具不少,我挑几个主流的说说我的使用感受。
| 工具 | 支持格式 | 语言覆盖 | 我的评价 |
|---|---|---|---|
| Syft | CycloneDX, SPDX | Java, Python, Go, JS, Rust 等 | 速度快,社区活跃,我主力用这个 |
| Trivy | CycloneDX, SPDX | 同上,还能扫容器镜像 | SBOM + 漏洞扫描二合一,省事 |
| CycloneDX CLI | CycloneDX | 通过插件扩展 | 官方出品,格式最标准 |
| Microsoft SBOM Tool | SPDX | .NET, JS, 其他 | 微软生态友好,但社区较小 |
我个人习惯用 Syft。为什么?因为它够轻量,生成一份Java项目的SBOM只需要几秒钟。而且它输出的是标准CycloneDX格式,后续对接漏洞库很方便。
3.2 在CI/CD里集成SBOM生成
好了,工具选好了。下一步就是把它塞进你的CI/CD流水线。我以GitHub Actions为例,给你看看我是怎么做的。
核心思路很简单:每次构建成功后,自动生成一份SBOM,然后把它作为构建产物保存下来。
3.2.1 一个可用的GitHub Actions示例
name: Generate SBOM
on:
push:
branches: [main, release/*]
pull_request:
branches: [main]
jobs:
sbom:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Generate SBOM with Syft
uses: anchore/sbom-action@v0
with:
path: ./
format: cyclonedx-json
output-file: sbom.cdx.json
- name: Upload SBOM as artifact
uses: actions/upload-artifact@v4
with:
name: sbom-${{ github.sha }}
path: sbom.cdx.json
这段代码干了三件事:
- 检出代码
- 用Syft扫描当前目录,生成CycloneDX格式的SBOM
- 把SBOM文件上传为构建产物,文件名带上commit SHA
你看,就这么简单。但这里有个坑——我建议你只在主干分支和release分支上生成SBOM。每个PR都生成的话,你的artifact存储会爆炸。我之前在一个大项目里这么干过,一个月下来存储费用涨了三倍……后来改成只在合并到main时生成,问题就解决了。
3.3 SBOM版本管理:别让SBOM变成一堆乱文件
SBOM生成出来了,但怎么管理?总不能每个版本都手动下载吧?
我见过最糟糕的做法:把SBOM文件扔到一个共享文件夹里,文件名写「sbom_final_v3_真的最终版.json」。嗯,你懂的,这迟早会乱套。
正确的做法是:让SBOM和你的软件版本一一对应。
3.3.1 版本关联策略
| 软件版本 | SBOM标识 | 存储位置 |
|---|---|---|
| v1.2.3 | sbom-v1.2.3.cdx.json | Release Artifacts |
| v1.2.4-rc.1 | sbom-v1.2.4-rc.1.cdx.json | Release Artifacts |
| main分支最新 | sbom-{commit-sha}.cdx.json | CI Artifacts(保留30天) |
说白了,就是用版本号或commit SHA作为SBOM的文件名。这样你拿到一个软件版本,就能立刻找到它对应的SBOM。
3.3.2 集中存储与检索
如果项目多了,光靠CI的artifact存储就不够了。我建议搭建一个SBOM集中管理平台。你可以用现成的,比如:
- Dependency-Track:开源,支持SBOM上传、漏洞分析、策略管理
- GitHub Dependency Graph:如果你用GitHub,它能自动识别SBOM
- 自建对象存储:比如MinIO,按版本目录存放
我个人推荐Dependency-Track。它有一个API,你可以在CI/CD里直接上传SBOM:
curl -X POST "https://dt.example.com/api/v1/bom" \
-H "X-Api-Key: $DEPENDENCY_TRACK_API_KEY" \
-H "Content-Type: multipart/form-data" \
-F "project=my-app" \
-F "version=v1.2.3" \
-F "bom=@sbom.cdx.json"
这样,每次构建完成后,SBOM自动上传到Dependency-Track。你可以在上面查看每个版本的组件清单、漏洞信息,甚至设置策略——比如「不允许使用GPL协议的组件」。
3.4 一张图看懂SBOM在CI/CD中的流转
说了这么多,我画张图帮你理清整个流程。
这张图展示了SBOM从生成到归档的完整路径。核心就两点:生成自动化和版本关联。做到这两点,你的SBOM管理就基本合格了。
3.5 避坑指南:我踩过的几个坑
最后,分享几个我实际项目中遇到的坑,你遇到了可以少走弯路。
- SBOM文件太大? 一个大型Java项目,SBOM可能有几千行。别用默认的XML格式,换成JSON或CycloneDX的压缩格式,文件体积能减少70%。
- 生成时间太长? Syft默认会扫描所有文件。如果你项目里有node_modules或vendor目录,记得加排除规则。我一般只扫描编译后的产物,比如JAR包或Docker镜像。
- 版本号对不上? 我遇到过最头疼的问题:SBOM里记录的组件版本和实际运行的不一致。后来发现是构建缓存搞的鬼。解决办法:每次生成SBOM前,强制清理缓存,或者基于构建产物(比如Docker镜像)来生成。
好了,这一章的内容就这些。SBOM集成到CI/CD,说白了就是「自动化生成 + 版本关联 + 集中管理」。你把这三点做到位,供应链安全的第一步就站稳了。