云原生供应链安全:SBOM、SLSA 与 Sigstore 实战
SolarWinds、Log4Shell、XZ Utils 后门……供应链攻击的破坏力已经有目共睹。2025 年,软件供应链安全从”最佳实践”变成了合规刚需。
威胁模型
供应链攻击的常见入口:
开发者机器 → 源代码仓库 → CI/CD 系统 → 制品仓库 → 生产环境
↑ ↑ ↑ ↑
凭证泄露 恶意 PR 构建注入 镜像篡改
防御思路:每个环节都要验证,不信任任何中间节点。
SBOM:软件物料清单
SBOM 记录软件的所有依赖,是供应链安全的基础。
生成 SBOM
# 使用 Syft 生成容器镜像的 SBOM
syft my-app:latest -o spdx-json > sbom.spdx.json
# 生成 CycloneDX 格式(更多工具支持)
syft my-app:latest -o cyclonedx-json > sbom.cdx.json
# 扫描 SBOM 中的漏洞
grype sbom:sbom.spdx.json
在 GitLab CI 中自动生成
generate-sbom:
stage: build
image: anchore/syft:latest
script:
- syft $IMAGE_TAG -o spdx-json > sbom.spdx.json
- syft $IMAGE_TAG -o cyclonedx-json > sbom.cdx.json
artifacts:
paths:
- sbom.spdx.json
- sbom.cdx.json
expire_in: 1 year # SBOM 需要长期保存
Sigstore/Cosign:镜像签名
Cosign 是 Sigstore 项目的核心工具,用于容器镜像的签名和验证。
签名镜像
# 生成密钥对
cosign generate-key-pair
# 签名镜像(推送到 registry 旁边)
cosign sign --key cosign.key my-registry/my-app:v1.0.0
# 验证签名
cosign verify --key cosign.pub my-registry/my-app:v1.0.0
无密钥签名(Keyless,推荐)
利用 OIDC 身份(GitHub Actions、GitLab CI)签名,无需管理私钥:
# GitHub Actions 示例
- name: Sign container image
uses: sigstore/cosign-installer@v3
- name: Sign the image
run: |
cosign sign --yes \
--rekor-url https://rekor.sigstore.dev \
${{ env.IMAGE_TAG }}
env:
COSIGN_EXPERIMENTAL: 1
在 K8s 中强制验证签名
使用 Kyverno 策略,拒绝未签名的镜像:
apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
name: verify-image-signature
spec:
validationFailureAction: Enforce
rules:
- name: check-image-signature
match:
any:
- resources:
kinds: [Pod]
namespaces: [production]
verifyImages:
- imageReferences:
- "my-registry/*"
attestors:
- count: 1
entries:
- keyless:
subject: "https://github.com/my-org/my-repo/.github/workflows/*"
issuer: "https://token.actions.githubusercontent.com"
SLSA:构建可信度框架
SLSA(Supply chain Levels for Software Artifacts)定义了四个安全级别:
| 级别 | 要求 | 防御 |
|---|---|---|
| L1 | 有构建记录 | 基本溯源 |
| L2 | 托管构建服务 | 防止开发者篡改 |
| L3 | 强化构建平台 | 防止构建系统被攻击 |
| L4 | 两人审查 + 密封构建 | 最高级别保护 |
生成 SLSA Provenance
# GitHub Actions:使用官方 SLSA generator
jobs:
build:
outputs:
image: ${{ steps.build.outputs.image }}
digest: ${{ steps.build.outputs.digest }}
steps:
- name: Build and push
id: build
uses: docker/build-push-action@v5
with:
push: true
tags: ${{ env.IMAGE_TAG }}
provenance:
needs: build
uses: slsa-framework/slsa-github-generator/.github/workflows/generator_container_slsa3.yml@v2
with:
image: ${{ needs.build.outputs.image }}
digest: ${{ needs.build.outputs.digest }}
secrets:
registry-username: ${{ secrets.REGISTRY_USER }}
registry-password: ${{ secrets.REGISTRY_PASSWORD }}
验证 Provenance
# 验证镜像的 SLSA provenance
slsa-verifier verify-image my-registry/my-app:v1.0.0 \
--source-uri github.com/my-org/my-repo \
--source-tag v1.0.0
完整的安全流水线
# .gitlab-ci.yml 安全增强版
stages:
- build
- sign
- attest
- verify
build-image:
stage: build
script:
- docker build -t $IMAGE_TAG .
- docker push $IMAGE_TAG
- syft $IMAGE_TAG -o cyclonedx-json > sbom.cdx.json
artifacts:
paths: [sbom.cdx.json]
sign-image:
stage: sign
script:
# 签名镜像
- cosign sign --key $COSIGN_KEY $IMAGE_TAG
# 将 SBOM 附加到镜像
- cosign attest --key $COSIGN_KEY \
--predicate sbom.cdx.json \
--type cyclonedx \
$IMAGE_TAG
verify-before-deploy:
stage: verify
script:
# 部署前验证签名
- cosign verify --key $COSIGN_PUB $IMAGE_TAG
# 验证 SBOM 中无高危漏洞
- grype sbom:sbom.cdx.json --fail-on high
供应链安全不是一次性工作,而是需要嵌入到每个开发和部署环节的持续实践。从 SBOM 开始,逐步推进到签名验证和 SLSA 合规,是最务实的路径。