关于 sbom-supply-chain
sbom-supply-chain 是面向软件构建与发布团队的技能,涵盖 SBOM 生成、漏洞检查和制品验证。它还介绍制品签名与证明,以及供应链策略执行。
主要功能
- 01生成 CycloneDX 和 SPDX SBOM
- 02根据 SBOM 匹配漏洞
- 03使用 cosign 签署制品
- 04附加 SBOM 和来源证明
- 05执行验证策略
适用场景
- 01为镜像和应用构建生成 SBOM
- 02部署前检查依赖项
- 03要求制品签名和来源证明
- 04准备安全审查及 SLSA 要求
安装
复制下面的命令,在终端中运行。
$
npx skills add https:/ / github.com/ bagelhole/ devops-security-agent-skills --skill sbom-supply-chain安装后在 Claude Code 中输入/sbom-supply-chain确认已加载。
详细介绍
SBOM 与供应链安全
通过可复现的元数据和验证门禁提升发布可信度。
何时使用此技能
在以下情况下使用此技能:
- 为容器镜像或应用构建生成 SBOM
- 部署前验证依赖项
- 强制执行签名制品和来源证明策略
- 准备 SOC2、ISO 27001 或客户安全审查
- 实施 SLSA 框架要求
- 响应供应链漏洞(例如 Log4Shell 事件)
前置条件
- 已安装
syft,用于生成 SBOM - 已安装
cdxgen,用于生成 CycloneDX SBOM - 使用
grype对照 SBOM 匹配漏洞 - 使用
cosignv2+ 进行签名和证明 - 支持 OCI 制品的容器镜像仓库
- 具有 OIDC 身份、用于无密钥签名的 CI/CD 流水线
SBOM 格式
CycloneDX 与 SPDX 对比
comparison:
cyclonedx:
standard: "OWASP CycloneDX"
focus: "Application security, vulnerability tracking"
formats: ["JSON", "XML", "Protocol Buffers"]
strengths:
- Vulnerability references (VEX support)
- Service and API dependency tracking
- Hardware BOM support
best_for: "Security-focused SBOM, vulnerability management"
spdx:
standard: "Linux Foundation SPDX (ISO/IEC 5962:2021)"
focus: "License compliance, legal review"
formats: ["JSON", "RDF/XML", "Tag-Value", "YAML"]
strengths:
- ISO standard
- License expression language
- Relationship modeling
best_for: "License compliance, regulatory requirements"
使用 Syft 生成 SBOM
# Generate SBOM for a container image (CycloneDX JSON)
syft ghcr.io/acme/api:v1.2.3 -o cyclonedx-json > sbom-cyclonedx.json
# Generate SBOM in SPDX format
syft ghcr.io/acme/api:v1.2.3 -o spdx-json > sbom-spdx.json
# Generate SBOM from a local directory (source code)
syft dir:. -o cyclonedx-json > sbom-source.json
# Generate SBOM from a Dockerfile/built image
syft docker:my-local-image:latest -o cyclonedx-json > sbom-local.json
# Generate SBOM for a specific package ecosystem
syft dir:. --catalogers python -o cyclonedx-json > sbom-python.json
# Include file hashes for deeper analysis
syft ghcr.io/acme/api:v1.2.3 -o cyclonedx-json --file-metadata > sbom-with-hashes.json
# Multiple output formats simultaneously
syft ghcr.io/acme/api:v1.2.3 \
-o cyclonedx-json=sbom-cdx.json \
-o spdx-json=sbom-spdx.json \
-o table=sbom-summary.txt
使用 cdxgen 生成 SBOM
# Install cdxgen
npm install -g @cyclonedx/cdxgen
# Generate CycloneDX SBOM for a project directory
cdxgen -o sbom.json .
# Specify project type
cdxgen -t python -o sbom-python.json .
cdxgen -t java -o sbom-java.json .
cdxgen -t node -o sbom-node.json .
cdxgen -t go -o sbom-go.json .
# Generate SBOM with evidence (call stacks, file occurrences)
cdxgen --evidence -o sbom-with-evidence.json .
# Generate for a container image
cdxgen -t docker -o sbom-container.json ghcr.io/acme/api:v1.2.3
# Generate with deep analysis (slower but more accurate)
cdxgen --deep -o sbom-deep.json .
# Output in different formats
cdxgen -o sbom.xml --format xml .
漏洞匹配
# Scan SBOM for vulnerabilities with Grype
grype sbom:sbom-cyclonedx.json
# Fail on critical/high vulnerabilities
grype sbom:sbom-cyclonedx.json --fail-on high
# Output as JSON for CI processing
grype sbom:sbom-cyclonedx.json -o json > vulnerability-report.json
# Scan container image directly
grype ghcr.io/acme/api:v1.2.3
# Use Trivy with SBOM input
trivy sbom sbom-cyclonedx.json
# Trivy scan with severity filter
trivy sbom sbom-cyclonedx.json --severity CRITICAL,HIGH --exit-code 1
Cosign 签名和证明
镜像签名
# Keyless signing (recommended - uses OIDC identity from CI)
cosign sign ghcr.io/acme/api@sha256:abc123...
# Sign with a key pair
cosign generate-key-pair
cosign sign --key cosign.key ghcr.io/acme/api@sha256:abc123...
# Verify keyless signature
cosign verify \
--certificate-identity=https://github.com/acme/api/.github/workflows/build.yml@refs/heads/main \
--certificate-oidc-issuer=https://token.actions.githubusercontent.com \
ghcr.io/acme/api@sha256:abc123...
# Verify with key
cosign verify --key cosign.pub ghcr.io/acme/api@sha256:abc123...
SBOM 证明
# Attach SBOM as an in-toto attestation to a container image
cosign attest --predicate sbom-cyclonedx.json \
--type cyclonedx \
ghcr.io/acme/api@sha256:abc123...
# Attach SPDX SBOM
cosign attest --predicate sbom-spdx.json \
--type spdx \
ghcr.io/acme/api@sha256:abc123...
# Verify SBOM attestation
cosign verify-attestation \
--type cyclonedx \
--certificate-identity=https://github.com/acme/api/.github/workflows/build.yml@refs/heads/main \
--certificate-oidc-issuer=https://token.actions.githubusercontent.com \
ghcr.io/acme/api@sha256:abc123...
# Extract the SBOM from attestation
cosign verify-attestation --type cyclonedx \
--certificate-identity=... --certificate-oidc-issuer=... \
ghcr.io/acme/api@sha256:abc123... | jq -r '.payload' | base64 -d | jq '.predicate'
In-toto 来源证明
# Create a custom provenance attestation
cat > provenance.json << 'EOF'
{
"buildType": "https://github.com/acme/build-system@v1",
"builder": {
"id": "https://github.com/acme/api/.github/workflows/build.yml@refs/heads/main"
},
"invocation": {
"configSource": {
"uri": "git+https://github.com/acme/api@refs/heads/main",
"digest": { "sha1": "abc123def456" },
"entryPoint": ".github/workflows/build.yml"
}
},
"metadata": {
"buildStartedOn": "2025-01-15T10:00:00Z",
"buildFinishedOn": "2025-01-15T10:05:00Z",
"completeness": {
"parameters": true,
"environment": true,
"materials": true
}
},
"materials": [
{
"uri": "git+https://github.com/acme/api@refs/heads/main",
"digest": { "sha1": "abc123def456" }
},
{
"uri": "pkg:docker/[email protected]",
"digest": { "sha256": "def456..." }
}
]
}
EOF
# Attach provenance attestation
cosign attest --predicate provenance.json \
--type slsaprovenance \
ghcr.io/acme/api@sha256:abc123...
CI/CD 流水线集成
# .github/workflows/sbom-supply-chain.yml
name: Build with SBOM and Signing
on:
push:
tags: ['v*']
permissions:
contents: read
packages: write
id-token: write # Required for keyless signing
jobs:
build-sign-attest:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Login to GHCR
uses: docker/login-action@v3
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Build and push image
id: build
uses: docker/build-push-action@v5
with:
push: true
tags: ghcr.io/${{ github.repository }}:${{ github.ref_name }}
- name: Install tools
run: |
curl -sSfL https://raw.githubusercontent.com/anchore/syft/main/install.sh | sh -s -- -b /usr/local/bin
curl -sSfL https://raw.githubusercontent.com/anchore/grype/main/install.sh | sh -s -- -b /usr/local/bin
- name: Generate SBOM
run: |
syft ghcr.io/${{ github.repository }}@${{ steps.build.outputs.digest }} \
-o cyclonedx-json=sbom-cdx.json \
-o spdx-json=sbom-spdx.json
- name: Scan SBOM for vulnerabilities
run: |
grype sbom:sbom-cdx.json --fail-on critical -o json > vuln-report.json
- name: Install cosign
uses: sigstore/cosign-installer@v3
- name: Sign image (keyless)
run: |
cosign sign ghcr.io/${{ github.repository }}@${{ steps.build.outputs.digest }}
- name: Attach SBOM attestation
run: |
cosign attest --predicate sbom-cdx.json \
--type cyclonedx \
ghcr.io/${{ github.repository }}@${{ steps.build.outputs.digest }}
- name: Upload artifacts
uses: actions/upload-artifact@v4
with:
name: sbom-and-reports
path: |
sbom-cdx.json
sbom-spdx.json
vuln-report.json
策略执行
Kyverno 策略:要求镜像已签名且包含 SBOM
apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
name: require-signed-images-with-sbom
spec:
validationFailureAction: Enforce
webhookTimeoutSeconds: 30
rules:
- name: verify-signature
match:
any:
- resources:
kinds: ["Pod"]
verifyImages:
- imageReferences: ["ghcr.io/acme/*"]
attestors:
- entries:
- keyless:
subject: "https://github.com/acme/*"
issuer: "https://token.actions.githubusercontent.com"
rekor:
url: "https://rekor.sigstore.dev"
attestations:
- type: cyclonedx
conditions:
- all:
- key: "{{ components[].name }}"
operator: AllNotIn
value: ["log4j-core"]
OPA 策略:部署前验证 SBOM
package sbom.verify
import rego.v1
default allow := false
allow if {
sbom_present
no_critical_vulns
signed_by_ci
}
sbom_present if {
input.attestations.cyclonedx != null
count(input.attestations.cyclonedx.components) > 0
}
no_critical_vulns if {
not any_critical
}
any_critical if {
some vuln in input.vulnerability_report.matches
vuln.vulnerability.severity == "Critical"
vuln.vulnerability.fix.state == "fixed"
}
signed_by_ci if {
input.signature.issuer == "https://token.actions.githubusercontent.com"
startswith(input.signature.subject, "https://github.com/acme/")
}
故障排除
| 问题 | 原因 | 解决方案 |
|---|---|---|
| Syft 遗漏依赖项 | 不支持的包管理器或格式 | 查看 syft catalogers 列表;使用 cdxgen 进行更深入的分析;向上游项目贡献 |
| Cosign 签名失败,提示“no identity token” | CI 中缺少 OIDC 提供方 | 确保 GitHub Actions 中具有 id-token: write 权限;检查 OIDC 提供方配置 |
| Grype 报告误报 | 包版本检测不正确 | 验证 SBOM 准确性;向 grype GitHub 仓库报告;为已确认的误报添加忽略规则 |
| SBOM 证明过大 | 镜像较大且依赖项众多 | 压缩 SBOM;使用 SPDX 紧凑格式;考虑按层拆分 |
| 准入控制器中的验证失败 | 身份或颁发者 URL 错误 | 检查 --certificate-identity 和 --certificate-oidc-issuer 的准确值 |
| cdxgen 生成的 SBOM 为空 | 未检测到项目类型 | 使用 -t 显式指定类型;确保清单文件(package.json 等)存在 |
最佳实践
- 同时生成 CycloneDX 和 SPDX 格式的 SBOM,以实现最大兼容性
- 使用无密钥签名(Sigstore/Fulcio)为所有发布制品签名
- 将 SBOM 作为 in-toto 证明附加到容器镜像
- 在 CI 中扫描 SBOM 中的漏洞,并在发现严重问题时阻止流程
- 存档每次发布的 SBOM,以用于审计和事件响应
- 在准入控制器(Kyverno、OPA)中强制执行签名验证
- 持续监控已存储的 SBOM 中是否出现新的 CVE
- 在每条构建流水线中加入 SBOM 生成,而不仅限于发布流程
- 跟踪 SBOM 完整性指标(已捕获依赖项的百分比)
- 建立 VEX(漏洞可利用性交换)流程来处理误报
相关技能
- dependency-scanning - 库漏洞分类
- container-scanning - 容器 CVE 扫描
- policy-as-code - 策略执行
- model-supply-chain-security - ML 制品可信度
评论
支持 Markdown