ARTICLE DETAIL

资讯详情

深耕编程入门与网站建设的一线实战洞察。

Packer SLSA 溯源 CI 参考工作流:provenance 后处理器与 GitHub Actions 无密钥签名实战

Packer SLSA 溯源 CI 参考工作流:provenance 后处理器与 GitHub Actions 无密钥签名实战 Packer SLSA 溯源 CI 参考工作流provenance 后处理器与 GitHub Actions 无密钥签名实战【免费下载链接】packerPacker is a tool for creating identical machine images for multiple platforms from a single source configuration.项目地址: https://gitcode.com/gh_mirrors/pa/packer本文围绕 Packer 仓库 examples/ci/README.md 中提供的两份可直接复制使用的 CI 参考工作流展开系统讲解如何用 Packer 的provenance后处理器在 GitHub Actions 中生成 SLSA Provenance v1 溯源声明并分别以「L2 无密钥keyless签名」和「L3 兼容的委托签名」两种模式落地。读完本文你将掌握SLSA 构建等级中 Packer 的职责边界、provenance后处理器的完整配置参数、packer verify-attestation的策略校验用法以及两份可直接迁移到自建项目.github/workflows/的完整 CI 工作流。文档定位参考工作流而非仓库自用 CIexamples/ci/目录下的工作流是复制粘贴型参考模板用于配合 Packer 的provenance后处理器产出 SLSA 溯源声明。需要特别强调的是这些工作流并未接入当前仓库自身的 CI而是面向所有使用 Packer 构建镜像的第三方项目。使用时需要将它们复制到你自己项目的.github/workflows/目录并适配模板路径、构建产物路径等具体内容。目录包含三份文件examples/ci/README.md本文讲解的主文档说明 SLSA 等级定位与两份工作流的分工examples/ci/github-actions-l2-keyless.ymlL2 模式Packer 使用工作流的 OIDC 身份无密钥签名溯源声明、上传 Rekor 透明日志并用packer verify-attestation验证签名声明examples/ci/github-actions-l3-delegated.ymlL3 兼容模式构建 job 只负责构建并发布摘要digest溯源生成与签名委托给隔离的可复用工作流使构建步骤无法触达签名材料。SLSA 构建等级与 Packer 的职责边界主文档给出了一张关键表格明确了 SLSA Build 等级大多属于构建平台的属性而非构建工具的属性。Packer 是工具因此它的作用范围是SLSA 构建等级要求Packer 的角色Packer 提供的能力L1溯源存在且被分发完全由 Packer 承担溯源生成L2溯源由托管平台签名Packer 通过 CI OIDC 身份签名CI 中的无密钥签名L3加固平台构建步骤无法触达签名密钥平台属性Packer 与之兼容委托签名模式L4—SLSA v1.0 中未定义—结论很清晰Packer 生成 SLSA Provenance v1自身即可达到构建 L1当运行在托管 CI 且启用无密钥签名时达到 L2。L3 是构建平台的属性要求签名密钥对构建步骤不可达。Packer 单独无法赋予 L3但文档提供的委托签名模式与 L3 平台兼容。这一点在源码中也能印证provenance 后处理器输出的是 SLSA v1 谓词predicate其谓词类型常量SLSAProvenanceV1PredicateType https://slsa.dev/provenance/v1定义在 internal/provenance/predicate.go默认构建类型为https://packer.io/buildtypes/hcl2/v1默认本地 builder ID 为https://packer.io/local-build。工作流一L2 无密钥签名github-actions-l2-keyless.yml这份工作流对应 SLSA 构建 L2Packer 以 GitHub Actions 工作流自身的 OIDC 身份Fulcio对溯源声明进行无密钥签名并把签名记录进 Rekor 透明日志从而产出由托管平台生成的、已签名且可透明审计的溯源。值得注意文档明确警告该模式本身不赋予 L3——构建 job 仍可触达临时的签名材料L3 兼容模式请看第二份工作流。工作流骨架与权限声明name: build-and-sign-provenance on: push: tags: - v* permissions: contents: read # Required so Packers keyless signing can request an OIDC token from GitHub # and exchange it with Fulcio for a short-lived signing certificate. id-token: writeid-token: write是启用无密钥签名的关键它允许 Packer 向 GitHub 请求 OIDC token再与 Fulcio 交换短时签名证书。如果省略该权限Packer 将无法获取环境 OIDC 身份。关键环境变量验证时用于固定身份env: # Must match the workflows OIDC identity so verification can pin it. KEYLESS_IDENTITY: https://github.com/${{ github.repository }}/.github/workflows/build-and-sign-provenance.yml${{ github.ref }} KEYLESS_OIDC_ISSUER: https://token.actions.githubusercontent.comKEYLESS_IDENTITY必须与工作流自身的 OIDC 身份精确匹配验证时才能将签名证书锁定到该身份KEYLESS_OIDC_ISSUER是 GitHub Actions 的 OIDC 颁发者。构建与签名步骤steps: - name: Checkout uses: actions/checkoutv4 - name: Install Packer uses: hashicorp/setup-packermain with: version: latest - name: Initialize plugins run: packer init . - name: Build and sign run: | packer build \ -var keyless_identity${KEYLESS_IDENTITY} \ -var keyless_oidc_issuer${KEYLESS_OIDC_ISSUER} \ .工作流注释里特别解释了一个重要的 HCL 限制Packer 的env()函数只能出现在变量的default中绝不能内联写在 block 里因此这里用-var把身份信息传入而不是在模板中直接调用env()。对应的模板需要声明两个输入变量与一个无密钥 provenance 后处理器variable keyless_identity { type string } variable keyless_oidc_issuer { type string } post-processor provenance { signing_mode keyless upload_tlog true keyless_identity var.keyless_identity keyless_oidc_issuer var.keyless_oidc_issuer }Packer 会自动从 GitHub Actions 的ACTIONS_ID_TOKEN_REQUEST_URL/ACTIONS_ID_TOKEN_REQUEST_TOKEN环境变量中拾取环境 OIDC token前提是授予了上面的id-token: write权限。这一点在 internal/attestation/sign_keyless.go 的resolveAmbientIDToken中有完整实现它依次尝试SIGSTORE_ID_TOKEN、CI_JOB_JWT_V2、CI_JOB_JWT最后通过resolveGitHubActionsIDToken从ACTIONS_ID_TOKEN_REQUEST_URL请求 tokenaudience 缺省为sigstore。验证签名声明- name: Verify attestation run: | for att in *.provenance.json; do packer verify-attestation \ -signing-modekeyless \ -bundle${att%.json}.sigstore.json \ -require-rekor \ -require-timestamp \ -keyless-identity${KEYLESS_IDENTITY} \ -keyless-oidc-issuer${KEYLESS_OIDC_ISSUER} \ -predicate-typehttps://slsa.dev/provenance/v1 \ ${att} done这里循环遍历所有*.provenance.json声明文件配合*.sigstore.json侧车文件Sigstore bundle做 Rekor 支撑的透明性校验。各参数含义与 command/verify_attestation.go 中packer verify-attestation的帮助文本一致-signing-modekeyless指定无密钥验证模式支持key、kms、keyless可自动探测-bundle*.sigstore.json提供 Sigstore bundle用于 Rekor 或时间戳验证-require-rekor要求基于 bundle 完成 Rekor 透明日志验证-require-timestamp要求可信观察者时间戳Rekor 集成时间或 RFC3161 时间戳证据-keyless-identity/-keyless-oidc-issuer期望的无密钥签名身份与 OIDC 颁发者-predicate-type期望的谓词类型这里固定为 SLSA Provenance v1。上传溯源产物- name: Upload provenance artifacts uses: actions/upload-artifactv4 with: name: provenance path: | *.provenance.json *.sigstore.json*.provenance.json是溯源声明本体*.sigstore.json是签名 bundle 侧车。当upload_tlog true时bundle 中会携带 Rekor 透明性证据供上述-require-rekor校验使用见 post-processor/provenance/post-processor.go 中侧车路径的生成逻辑以.json结尾的声明文件其 bundle 路径为去掉.json后缀后追加.sigstore.json。工作流二L3 兼容的委托签名github-actions-l3-delegated.yml这份工作流对应 SLSA 构建 L3 兼容模式构建 job 只负责构建产物并发布其摘要溯源生成与签名被委托给一个隔离的、可复用的工作流SLSA GitHub generator在构建步骤无法影响或触达的独立 job 中运行。这种隔离正是 L3 的要求——签名材料对构建不可达。文档再次强调Packer 本身不赋予 L3它只负责产出产物L3 属性由平台隔离签名方提供。name: build-and-delegate-provenance on: push: tags: - v* permissions: contents: read jobs: build: runs-on: ubuntu-latest outputs: digest: ${{ steps.hash.outputs.digest }} steps: - name: Checkout uses: actions/checkoutv4 - name: Install Packer uses: hashicorp/setup-packermain with: version: latest - name: Initialize plugins run: packer init . # Build only. Do NOT sign here: signing in the build job would defeat the # isolation that the delegated signer provides. - name: Build artifact run: packer build . # Emit a base64-encoded subject digest for the delegated generator. - name: Compute artifact digest id: hash run: | # Adjust the artifact path to match your build output. echo digest$(sha256sum output/image.qcow2 | base64 -w0) ${GITHUB_OUTPUT}构建 job 中明确不做签名——在构建 job 内签名会破坏委托签名方提供的隔离性。它只计算产物摘要并以 base64 编码输出注意output/image.qcow2需要替换为你实际的构建产物路径。委托 job 则使用 SLSA GitHub generatorprovenance: needs: [build] permissions: actions: read id-token: write contents: write uses: slsa-framework/slsa-github-generator/.github/workflows/generator_generic_slsa3.ymlv2.0.0 with: base64-subjects: ${{ needs.build.outputs.digest }}该 job 在构建步骤无法触达的独立 job 中生成并签名 SLSA 溯源——这是 L3 属性的来源。文档注释提醒实际使用中应将可复用工作流固定到已发布 tag示例中为v2.0.0。provenance 后处理器源码级解读两份工作流都依赖provenance后处理器其实现位于 post-processor/provenance/post-processor.go配套文档为 post-processor/provenance/README.md。它支持三类能力富集了源码控制与 CI 元数据的 SLSA 溯源声明SBOM 侧车文件与 SBOM 溯源声明可配置签名方与验证方的可选 DSSE 签名默认signing_mode none输出未签名 JSON 声明。核心配置参数源码中Config结构体post-processor.go完整定义了以下参数与工作流直接相关的有参数含义默认值signing_mode签名模式none默认未签名 JSON、key本地 PEM 密钥、kmsKMS/Vault URI、keylessSigstore Fulciononekeyless_identity期望的签名身份如工作流 refkeyless 模式必填—keyless_oidc_issuer期望的 OIDC 颁发者如https://token.actions.githubusercontent.comkeyless 模式必填—upload_tlog是否将 keyless 签名上传 Rekor 透明日志并产出携带透明性证据的 Sigstore bundlefalsefulcio_urlkeyless 签名使用的 Fulcio CA 地址https://fulcio.sigstore.devrekor_urlupload_tlog启用时的 Rekor 透明日志地址https://rekor.sigstore.devtrusted_root_path用于固定 keyless 验证的 Sigstore trusted-root JSON不设置则拉取公共 Sigstore 根—build_type溯源谓词中记录的 SLSAbuildTypeURIhttps://packer.io/buildtypes/hcl2/v1template产出产物的 Packer 模板路径记为外部参数—only_builds产物来源的构建列表记为外部参数—user_variables额外的用户变量记为外部参数敏感变量会被脱敏—source_uri覆盖自动探测的源码仓库 URI自动探测sbom/sbom_format/sbom_scan_path/sbom_scope/sbom_exclude是否同时生成 SBOM 及相应配置关 /cyclonedx/ 自动 /squashed/ 无这些默认值在Configure方法中于解码之后统一应用post-processor.go。keyless 模式还要求keyless_identity与keyless_oidc_issuer非空、不允许设置verifier覆盖验证严格绑定身份与颁发者策略详见signingBackendConfigpost-processor.go。输出文件与签名流程writeAttestationpost-processor.go展示了完整流程未签名模式none直接输出格式化 JSON 声明文件*.provenance.json签名模式先构造签名后端对 in-toto 负载进行规范化MarshalPayload后签名keyless 模式走buildSigstoreBundleForSigner产出 DSSE envelope 与 Sigstore bundle*.sigstore.jsonupload_tlogtrue时 bundle 携带 Rekor 证据签名后立即用验证方做VerifyEnvelope自检再原子写入文件atomicWriteFile先写临时文件再 rename防止并行构建时输出交错或崩溃留下损坏声明。DSSE envelope 的结构payloadType/payload/signatures其中 keyless 签名在signatures[0].cert携带 Fulcio 证书定义于 internal/attestation/dsse.go。谓词内容SLSA 谓词由 internal/provenance/predicate.go 的BuildSLSAPredicate构造buildDefinition记录buildType、外部参数模板、onlyBuilds、用户变量、内部参数Packer 版本、构建名、构建器类型与已解析依赖源码仓库 URI 摘要runDetails记录 builder ID默认https://packer.io/local-build与 Packer 版本、调用 ID 及起止时间。源码仓库由 Git 信息或 CI 环境变量自动探测可用source_uri覆盖post-processor.go。从零接入的完整步骤将上述参考工作流落到自己的项目可以按以下步骤操作复制工作流把 github-actions-l2-keyless.yml或 github-actions-l3-delegated.yml复制到你项目的.github/workflows/目录准备模板在 Packer 模板中声明keyless_identity、keyless_oidc_issuer两个变量并添加post-processor provenance块L2 模式L3 模式无需签名后处理器但需要调整sha256sum中的产物路径打 tag 触发两个工作流都监听v*格式的 tag 推送检查权限L2 模式必须保留id-token: writeL3 模式的委托 job 需要actions: read、id-token: write、contents: write消费产物从 workflow 的provenanceartifact 中取回*.provenance.json与*.sigstore.json离线可用packer verify-attestation -signing-modekeyless -bundle... -require-rekor -require-timestamp -keyless-identity... -keyless-oidc-issuer... -predicate-typehttps://slsa.dev/provenance/v1 声明文件重复验证。常见问题与注意事项env()的位置限制env()只能写在变量default中不能内联在 block 里因此工作流统一用-var传值L2 不等于 L3L2 模式下构建 job 仍能触达临时签名材料只有将签名委托给隔离平台如 L3 工作流才满足 L3 要求固定可复用工作流版本L3 委托的slsa-github-generator应固定到已发布 tag而非长期跟随分支身份字符串必须精确匹配keyless_identity与工作流 OIDC 身份不一致会导致验证失败验证命令中的期望值与签名时的实际值必须一致产物路径按需调整两份工作流中的产物路径如output/image.qcow2都需要替换为真实构建输出敏感变量脱敏provenance 谓词中记录的用户变量会依据packer_sensitive_variables自动脱敏为[sensitive value redacted]见 post-processor.go避免密钥泄露进溯源声明。这两份参考工作流为 Packer 用户提供了一条从「生成溯源」到「无密钥签名、透明审计、平台级隔离」的渐进路径先用 L2 模式快速获得已签名的可验证溯源再在需要更高供应链保证时切换到 L3 委托模式把签名材料彻底隔离在加固平台之内。【免费下载链接】packerPacker is a tool for creating identical machine images for multiple platforms from a single source configuration.项目地址: https://gitcode.com/gh_mirrors/pa/packer创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表