Skip to content

feat: reusable workflow to attest plugin release artifacts #3

Description

@fzipi

What

A reusable workflow, crs-plugin-release.yaml, that attests a plugin's release artifacts with actions/attest-build-provenance, so a downloaded plugin can be verified with gh attestation verify before anything loads its rules.

Same technique as coreruleset/coreruleset#4750, which adds provenance to CRS releases, applied to the plugins — and living here so each plugin repository keeps the one line caller that crs-plugin-integration.yaml and crs-plugin-lint.yaml already established.

Why

Plugin releases carry nothing verifiable today. Sampling the two most used:

coreruleset/fake-bot-plugin                    v1.1.0: 0 uploaded assets
coreruleset/wordpress-rule-exclusions-plugin   v1.2.0: 0 uploaded assets

Only GitHub's auto-attached source archives exist, with no signature and no attestation, so anyone consuming a plugin is trusting the tag and the transport.

That is the blocker on coreruleset/modsecurity-crs-docker#470, which proposes installing plugins into the container from a CRS_PLUGINS variable. The images gpg --verify the CRS tarball against the CRS signing key; adding plugin rules to the same engine with no equivalent check would be a step down in the trust chain, and four registry entries are third-party repositories. coreruleset/plugin-registry#21 puts signing out of scope for its first iteration, which leaves a gap that provenance fills without needing a key at all.

GPG is the wrong tool for 30 repositories: it means a private key per plugin owner, or one shared key with wide distribution. Provenance attestations are keyless and tie an artifact to the workflow and commit that produced it, which is the property an installer actually wants to check.

Shape

Triggered on release: published in the calling repository:

  • take the source archives GitHub attaches to the release, as feat: attest release artifacts with build provenance coreruleset#4750 does, rather than rebuilding them — zip and tar archives embed mtimes and permissions, so an independently rebuilt copy would not match the hash of what people download
  • run actions/attest-build-provenance against them
  • permissions: { id-token: write, attestations: write, contents: read }, and nothing else

Caller, per plugin repository:

jobs:
  attest:
    uses: coreruleset/actions/.github/workflows/crs-plugin-release.yaml@v1

Open questions

  • Verification inside a container. gh attestation verify needs the gh binary, which the CRS images do not ship; cosign verify-blob-attestation is the other option and is another binary to add and keep current. Whatever #470 ends up doing has to pick one, so it is worth deciding here what the documented verification command is.
  • Rollout. 18 plugin repositories are mid-migration to the reusable workflows already. Attestation only helps a consumer once the plugins it installs have it, so the installer needs a policy for plugins that do not yet — refuse, or warn.
  • Does the registry record it? Move the plugin registry list to a different format plugin-registry#21 is designing registry.yaml. A field saying whether a plugin's releases are attested would let an installer decide before it downloads anything, instead of discovering it afterwards.
  • Scope. Provenance says which workflow built an artifact. It does not say the rules are safe, and the registry already documents that it attests range allocation and review rather than a code audit. Worth stating plainly so downstream tooling does not over-read a green check.

Refs

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions