产物签名与供应链出处(SLSA)
签构建产物并附出处元数据、使消费者可验产物由预期管道从预期源构建——非攻击者注入。
为什么
满未签产物的注册表是无强信任边界——任何看起来对的产物(同名同版)被信、能推到注册表的攻击者(经泄令牌、typosquat 包或依赖混淆攻击)可注入恶意产物消费者拉跑。产物签名闭此隙: 构建管道用开发者永不持的键签产物(经 OIDC 无键签名)、消费者拉前验签。出处更进一步: 附签证明记录确切哪个源提交、哪个工作流、哪些建输入产生产物——故消费者可验不仅'这签了吗'而是'这从我预期的源、我预期的管道建的吗'。这是 SLSA 框架(软件产物验证供应链级别): 每级加控制(L1: 出处存在、L2: 托管构建、L3: 不可伪出处)。成本几分钟管道设;益处是消除已成最常见向量危害开源生态的整类供应链攻击。
何时使用
发产物(容器、npm 包、二进制)给他人或其他系统消费时——仅内部产物可从 L1 始、公开产物应目标 L3。
如何做
1. CI 工作流中启 OIDC - GitHub Actions 给每 job 发 OIDC 令牌;无长期密钥管 - 工作流加 permissions: id-token: write 2. 用无键签名签产物(Sigstore / cosign) - cosign sign --keyless <image>——用临时键签、证书绑 OIDC 身份 - 签名存注册表产物旁 3. 用构建 action 生成出处 - 用 slsa-framework/slsa-github-generator 产出出处证明 - 证明记录: 源仓、提交 SHA、工作流路径、建输入 - 作 cosign 证明附到产物 4. 消费侧验证 - cosign verify --certificate-identity <workflow-ref> <image> - cosign verify-attestation --predicate-type slsaprovenance <image> - 部署管道中验证为门控: 验失败则部署中止 5. 渐进 SLSA 级 - L1: 出处存在(生 成器产它) - L2: 构建托管(GitHub Actions 为托管构建器) - L3: 出处不可伪(构建器隔离不可篡) - 每级为构建平台属性、非额外代码写
示例
# .github/workflows/release.yml — 无键签名 + 出处
name: release
on:
push:
tags: ["v*"]
permissions:
contents: read
id-token: write # 无键签名所需
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- run: docker build -t ghcr.io/$ORG/app:$GITHUB_REF_NAME .
- run: docker push ghcr.io/$ORG/app:$GITHUB_REF_NAME
# 无键签(无密钥管)
- uses: sigstore/cosign-installer@v3
- run: cosign sign --yes ghcr.io/$ORG/app:$GITHUB_REF_NAME
provenance:
needs: build
uses: slsa-framework/slsa-github-generator/.github/workflows/[email protected]
with:
image: ghcr.io/$ORG/app:$GITHUB_REF_NAME
# 消费者(部署管道)拉前验证:
# cosign verify --certificate-identity-regexp 'github.com/$ORG/.github/workflows/release.yml' \
# ghcr.io/$ORG/app:v1.2.3常见问题
- ⚠用存为 CI 密钥的长期键签——密钥为单点故障: 若泄(CI 密钥常泄)、攻击者可作你项目签任意产物、签名不供信任。
- ⚠签产物但消费侧不验——签名存注册表但每部署拉不验、故无签恶意产物被拉跑、签名白费。
- ⚠生成出处但不查源提交——消费者验'有出处证明吗'非'出处匹配我预期源吗'、故能从恶意 fork 触发工作流的攻击者为恶意产物产有效出处。
- ⚠把 SLSA 级当复选框非属性——声称 L3 但未用隔离不可伪构建器、故出处技术上存在但可伪、供应链保证为虚。
最佳实践
- ✓用无键签名(cosign sign --keyless 经 OIDC)故无长期键泄——签证书绑工作流身份仅该运行有效。
- ✓使验证为部署门控: 部署管道跑 cosign verify 失败则中止——这把签名从副作用变强控制。
- ✓消费侧验全出处(源仓、提交 SHA、工作流 ref)非仅签名存在——这防攻击者替换产有效签恶意产物的恶意源。
- ✓用构建平台的 SLSA 生成器 action(它免费产不可伪 L3 出处)非手写出处——框架已解难问题。