3. SBOM生成工具(一):使用Syft生成容器镜像与文件系统的SBOM

聊到SBOM生成,Syft是我个人最常用的工具之一。它轻量、快速,而且对容器镜像和文件系统都支持得很好。说白了,它就是一把瑞士军刀——你给它一个镜像或目录,它就能把里面的软件包清单给你扒得清清楚楚。

我记得第一次在项目里用Syft,是因为客户要求交付一份完整的依赖清单。当时手动去数镜像里的包,差点没把我累死。后来发现Syft几秒钟就能搞定,嗯,从那以后我就再也没手动数过包了。

3.1 Syft是什么?它能做什么?

Syft是一个用Go语言编写的CLI工具,专门用来从容器镜像和文件系统中生成SBOM。它支持多种输出格式,包括SPDX、CycloneDX和Syft自己的JSON格式。

你想想看,一个容器镜像里可能装了上百个软件包,有操作系统层的(比如glibc、openssl),也有应用层的(比如Python的requests库、Node.js的express框架)。Syft能把这些包全部识别出来,并且告诉你它们的版本号、许可证信息、来源等等。

核心能力一览:

  • 从容器镜像(Docker、OCI)中提取软件包清单
  • 从本地文件系统或目录中提取软件包清单
  • 支持多种包管理器:dpkg、rpm、apk、pip、npm、gem、cargo等
  • 输出格式:SPDX 2.2/2.3、CycloneDX 1.4/1.5、JSON、表格式
  • 支持与Grype集成进行漏洞扫描

3.2 安装Syft

安装Syft非常简单。我个人习惯用脚本安装,几秒钟就搞定。

# 使用安装脚本(推荐)
curl -sSfL https://raw.githubusercontent.com/anchore/syft/main/install.sh | sh -s -- -b /usr/local/bin

# 或者用Homebrew(macOS/Linux)
brew install syft

# 或者用Docker直接运行
docker run -v /var/run/docker.sock:/var/run/docker.sock anchore/syft:latest

我曾经在CI流水线里踩过一个坑——直接用Docker方式运行Syft,结果发现它访问不到本地的镜像缓存。后来我加上了-v /var/run/docker.sock:/var/run/docker.sock挂载,问题就解决了。嗯,这里要注意,如果你用Docker方式运行,一定要挂载Docker socket,否则Syft只能扫描远程仓库的镜像。

3.3 生成容器镜像的SBOM

这是Syft最常用的场景。你只需要给它一个镜像名称或ID,它就能自动拉取并分析。

# 扫描本地镜像
syft nginx:latest

# 扫描远程仓库的镜像(会自动拉取)
syft docker.io/library/alpine:3.18

# 指定输出格式为SPDX JSON
syft nginx:latest -o spdx-json=sbom.nginx.spdx.json

# 指定输出格式为CycloneDX XML
syft nginx:latest -o cyclonedx-xml=sbom.nginx.cdx.xml

我个人习惯用SPDX格式,因为它在开源社区里接受度更高。不过如果你的客户要求用CycloneDX,Syft也支持得很好。

小技巧:如果你只想看摘要,不加-o参数,Syft默认会输出一个漂亮的表格。我经常用这个来快速检查镜像里装了哪些包。

3.4 生成文件系统的SBOM

除了容器镜像,Syft也能扫描本地文件系统。这个功能在分析构建产物或解压后的文件系统时特别有用。

# 扫描当前目录
syft dir:.

# 扫描指定目录
syft dir:/path/to/your/project

# 扫描解压后的rootfs
syft dir:/path/to/rootfs -o spdx-json=sbom.rootfs.spdx.json

我记得有一次,客户给了一个tar包,里面是嵌入式设备的文件系统。我先把tar解压,然后用syft dir:扫描,几秒钟就生成了完整的SBOM。要是手动去翻,估计得花半天。

3.5 理解Syft的输出

Syft的输出结构很清晰。我们以SPDX格式为例,看看里面都包含了什么。

{
  "spdxVersion": "SPDX-2.3",
  "dataLicense": "CC0-1.0",
  "SPDXID": "SPDXRef-DOCUMENT",
  "name": "nginx:latest",
  "packages": [
    {
      "name": "libcrypto3",
      "versionInfo": "3.0.9-r4",
      "SPDXID": "SPDXRef-1a2b3c4d",
      "supplier": "Organization: Alpine Linux",
      "licenseConcluded": "OpenSSL",
      "externalRefs": [
        {
          "referenceCategory": "SECURITY",
          "referenceType": "cpe23Type",
          "referenceLocator": "cpe:2.3:a:alpine:libcrypto:3.0.9-r4:*:*:*:*:*:*:*"
        }
      ]
    }
  ]
}

你想想看,每个包都有唯一的SPDXID、版本号、供应商、许可证信息,还有CPE(通用平台枚举)标识。这些信息在后续做漏洞关联分析时特别重要。

注意:Syft生成的CPE不一定100%准确。我曾经遇到过它把某个包的CPE写错了,导致漏洞扫描时漏报。建议在关键项目里,手动核对一下关键包的CPE信息。

3.6 Syft的包检测机制

Syft是怎么知道镜像里装了哪些包的?它主要靠两种方式:

  • 包管理器数据库:比如Debian系的/var/lib/dpkg/status、Red Hat系的/var/lib/rpm、Alpine的/lib/apk/db/installed。Syft会读取这些数据库文件,提取已安装的包信息。
  • 文件指纹匹配:对于没有包管理器的场景(比如Go二进制、Java JAR包),Syft会通过文件路径、哈希值、元数据等特征来识别。

我个人建议,如果你要扫描的镜像比较特殊(比如用了多阶段构建,最终阶段没有包管理器),可以先用syft packages命令看看它到底识别出了哪些包。如果发现漏了,可以考虑用--source-version参数指定包管理器的版本。

3.7 实战:从镜像到SBOM的完整流程

下面是一个完整的实战示例,从拉取镜像到生成SBOM,再到简单的分析。

# 1. 拉取一个常用的镜像
docker pull node:18-alpine

# 2. 生成SPDX格式的SBOM
syft node:18-alpine -o spdx-json=sbom.node18.spdx.json

# 3. 查看SBOM中的包数量
cat sbom.node18.spdx.json | jq '.packages | length'

# 4. 查看所有包的名称和版本
cat sbom.node18.spdx.json | jq '.packages[] | {name: .name, version: .versionInfo}'

我记得第一次跑这个流程时,发现node:18-alpine这个镜像里居然有120多个包。大部分是Alpine的基础库,比如musl、libcrypto、zlib等。嗯,这就是为什么容器镜像也要做SBOM——你以为只装了一个Node.js,实际上底层依赖了一堆东西。

3.8 Syft的常用参数速查

参数 说明 示例
-o 指定输出格式和文件路径 -o spdx-json=sbom.json
--scope 扫描范围:all-layers(所有层)或 squashed(合并层) --scope all-layers
--exclude 排除匹配的文件或目录 --exclude '/usr/share/doc/**'
--platform 指定目标平台(如 linux/arm64) --platform linux/arm64
-v 显示详细日志,方便调试 -v

避坑指南:我曾经在扫描多架构镜像时忘了加--platform参数,结果Syft默认拉取了当前架构的镜像,导致生成的SBOM和实际部署的镜像不一致。如果你在CI里构建多架构镜像,一定要显式指定平台。

3.9 Syft的局限性

没有工具是完美的,Syft也有它的短板:

  • 对自编译二进制支持有限:如果你镜像里有自己编译的Go或C++程序,Syft可能识别不出来。它主要依赖包管理器和已知的文件指纹。
  • 许可证信息可能不准确:Syft从包管理器里读取的许可证信息,有时候和实际使用的许可证不一致。我建议在合规审计时,还是以官方文档为准。
  • 大镜像扫描较慢:如果镜像有几十层,Syft需要逐层分析,速度会慢一些。不过对于大多数场景,几秒钟到一分钟内都能搞定。

你想想看,Syft虽然不能解决所有问题,但作为SBOM生成的起点,它已经足够好了。后续我们可以用Grype做漏洞关联,用Trivy做更全面的扫描——这些我们后面会讲到。

3.10 本章小结

Syft是一个简单但强大的SBOM生成工具。它能从容器镜像和文件系统中提取软件包清单,支持多种输出格式,而且和Grype无缝集成。我个人建议,每个DevSecOps工程师都应该把Syft加入自己的工具箱。

嗯,这里要记住:SBOM不是目的,而是手段。生成SBOM只是第一步,后续的漏洞关联分析、许可证合规检查、供应链风险管理才是真正创造价值的地方。

Syft SBOM生成流程 输入源 容器镜像 文件系统/目录 OCI归档/tar包 Syft分析引擎 包管理器数据库解析 文件指纹匹配 输出格式:SPDX / CycloneDX / JSON / 表格 SBOM 文件 支持与Grype集成 进行漏洞关联分析