4. SBOM实战
好,咱们进入SBOM的实战环节。说实话,SBOM这个概念在圈子里喊了好几年,但真正动手做的人,其实没那么多。我见过不少团队,安全策略写得天花乱坠,结果一问SBOM怎么生成,全员沉默。嗯,今天咱们就把这事落地。
这一章,我会带你走完三个关键动作:用syft给容器镜像生成SBOM、用cyclonedx-maven-plugin给Java项目生成SBOM,以及SBOM的验证与签名。说白了,就是让你从“听说过”变成“能干出来”。
4.1 使用syft生成容器镜像SBOM
先聊容器镜像。你想想看,一个生产环境的镜像里,可能塞了几百个系统包、几十个应用依赖。哪个版本有漏洞?哪个库该升级?没有SBOM,你就是在黑盒里猜。
我个人习惯用syft来做这件事。它轻量、快,而且支持多种输出格式,包括CycloneDX和SPDX。安装很简单,一行命令搞定:
# macOS / Linux
curl -sSfL https://raw.githubusercontent.com/anchore/syft/main/install.sh | sh -s -- -b /usr/local/bin
# 或者用 Docker 直接跑
docker run -v /var/run/docker.sock:/var/run/docker.sock anchore/syft:latest <镜像名>
生成SBOM的命令也特别直白。比如我要分析一个nginx镜像:
syft nginx:latest -o cyclonedx-json > nginx-sbom.json
这里我指定了-o cyclonedx-json,输出标准的CycloneDX格式。为什么选这个?因为CycloneDX是目前供应链安全领域最主流的格式,很多工具都认它。
syft nginx:latest 不加参数,它会以表格形式打印到终端。我在做快速排查时经常这么用。
跑完之后,你会得到一个JSON文件。打开看看,里面包含了镜像里每一个组件的名称、版本、类型、许可证等信息。嗯,这就是你的“软件物料清单”。
我曾经在一个客户的CI流水线里集成syft,每次构建完镜像自动生成SBOM并归档。后来有一次漏洞爆发,他们半小时内就定位到了受影响的镜像版本。你说这值不值?
4.2 使用cyclonedx-maven-plugin生成Java项目SBOM
容器镜像搞定了,那Java项目呢?Java生态的依赖管理本来就复杂,Maven的pom.xml里层层传递依赖,一不小心就引入一堆你不知道的包。
这里我推荐cyclonedx-maven-plugin。它是CycloneDX官方维护的Maven插件,能直接解析你的项目依赖,生成标准的SBOM。
配置方式很简单,在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>
然后执行:
mvn package
插件会在target/目录下生成一个bom.json文件。你也可以单独运行:
mvn org.cyclonedx:cyclonedx-maven-plugin:makeAggregateBom
这里有个细节要注意:makeAggregateBom会聚合所有模块的依赖,适合多模块项目。如果你的项目是单模块,用makeBom也行。
provided或test,插件默认会排除它们。如果你需要包含所有依赖,记得加参数:-Dcyclonedx.includeTestScope=true。
生成的SBOM长什么样?大概是这样:
{
"bomFormat": "CycloneDX",
"specVersion": "1.4",
"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 SBOM的验证与签名
SBOM生成了,然后呢?直接扔给安全团队?别急,这里有个关键问题:你怎么保证这份SBOM是完整的、没被篡改过的?
你想想看,如果攻击者偷偷改了你的SBOM,把有漏洞的组件版本改成安全的版本,那你后续的漏洞扫描就全废了。所以,签名和验证是必须的。
我一般用cosign来做这件事。cosign是Sigstore项目的一部分,支持对容器镜像、文件、SBOM等进行签名。操作起来也不复杂。
首先,安装cosign:
# macOS
brew install cosign
# Linux
curl -O -L "https://github.com/sigstore/cosign/releases/latest/download/cosign-linux-amd64"
chmod +x cosign-linux-amd64
sudo mv cosign-linux-amd64 /usr/local/bin/cosign
然后,生成一个密钥对(或者用OIDC身份认证,我个人习惯用密钥对):
cosign generate-key-pair
这会生成cosign.key(私钥)和cosign.pub(公钥)。私钥一定要保管好,别往代码仓库里传。
接下来,对SBOM文件签名:
cosign sign-blob --key cosign.key nginx-sbom.json > nginx-sbom.json.sig
这会生成一个签名文件nginx-sbom.json.sig。验证的时候,用公钥:
cosign verify-blob --key cosign.pub --signature nginx-sbom.json.sig nginx-sbom.json
如果输出Verified OK,说明SBOM没被改过。嗯,就是这么简单。
我还见过一种做法,是把签名信息直接嵌入SBOM文件本身。CycloneDX格式支持在signature字段里存放签名数据。这样你只需要一个文件,就能同时包含物料清单和签名信息。不过,我个人觉得分开存放更灵活,看你的场景。
小结
这一章的内容,说白了就是三件事:生成SBOM、生成SBOM、保护SBOM。容器镜像用syft,Java项目用cyclonedx-maven-plugin,最后用cosign签名验证。每一步都不复杂,但串联起来,就是一条完整的供应链安全防线。
我记得有一次在客户现场,他们被审计要求提供所有生产环境的SBOM。我帮他们搭了一套自动化流水线,每天凌晨自动扫描所有镜像和项目,生成SBOM并签名归档。审计那天,客户直接把归档目录甩过去,半小时就过了。嗯,这就是实战的价值。