This is unreleased documentation for Runtime Enforcer 0.11-dev.

Verifying Kubewarden Runtime Enforcer

The Kubewarden Runtime Enforcer project signs what it publishes, so that you can check that an artifact is the one the project built. For each release, the project publishes:

  • Signed container images, one per component.

  • A signed Software Bill of Materials (SBOM) and a signed provenance attestation for each image and architecture.

  • A signed Helm chart.

The signatures use Sigstore in keyless mode. The signing certificate names the GitHub Actions workflow that built the artifact. Each cosign command below passes two values:

  • --certificate-oidc-issuer: always https://token.actions.githubusercontent.com.

  • --certificate-identity-regexp: the workflow file that built the artifact.

Runtime Enforcer builds, signs and attests its images with one shared reusable workflow that lives in the kubewarden/github-actions repository. The signer identity of every image, SBOM and provenance file is:

https://github.com/kubewarden/github-actions/.github/workflows/container-release.yml@<ref>

The <ref> is the commit of the reusable workflow, not the release tag of Runtime Enforcer. For that reason the commands below match the identity with --certificate-identity-regexp, anchored to the full path of the workflow file.

That identity names the builder, not the release. The same builder signs the artifacts of every Kubewarden component. So each command also pins the caller repository and the release tag, with --certificate-github-workflow-repository and --certificate-github-workflow-ref. A signed file from another repository or another release does not pass. The flags do not bind the component. Every component of one release shares these certificate values, so a blob and its bundle from one component verify under another component’s filename. To check which image a file describes, read the subject field inside the file.

Keep the full path of the workflow file in the pattern, as the commands below do. A pattern such as https://github.com/kubewarden/* accepts an artifact from any workflow in any repository of the organization. The anchored pattern accepts only an artifact that container-release.yml built.

The examples use the release v0.10.1 and the chart version 0.2.1. Replace them with the versions that you verify.

Container images

Runtime Enforcer publishes three images, all at ghcr.io/kubewarden/runtime-enforcer/:

  • controller

  • agent

  • debugger

The shared workflow signs each single-architecture image and the multi-architecture index. To verify the controller image, run:

cosign verify \
  --certificate-oidc-issuer=https://token.actions.githubusercontent.com \
  --certificate-identity-regexp='^https://github\.com/kubewarden/github-actions/\.github/workflows/container-release\.yml@' \
  --certificate-github-workflow-repository=kubewarden/runtime-enforcer \
  --certificate-github-workflow-ref='refs/tags/v0.10.1' \
  ghcr.io/kubewarden/runtime-enforcer/controller:v0.10.1

Verification for ghcr.io/kubewarden/runtime-enforcer/controller:v0.10.1 --
The following checks were performed on each of these signatures:
  - The cosign claims were validated
  - Existence of the claims in the transparency log was verified offline
  - The code-signing certificate was verified using trusted certificate authority certificates

<snipped json>

The same command, with agent or debugger in place of controller, verifies the other two images.

Build provenance (SLSA Build L3)

The shared workflow runs actions/attest on the multi-architecture index of each image. GitHub writes the provenance from the OIDC token of the workflow job and signs it. No build step can change it. This attestation is what gives the images SLSA Build L3.

GitHub stores the attestation in the Runtime Enforcer repository and next to the image in the registry. Verify it with the GitHub CLI:

gh attestation verify oci://ghcr.io/kubewarden/runtime-enforcer/controller:v0.10.1 \
  --repo kubewarden/runtime-enforcer \
  --signer-workflow kubewarden/github-actions/.github/workflows/container-release.yml

Loaded digest sha256:... for oci://ghcr.io/kubewarden/runtime-enforcer/controller:v0.10.1
Loaded 1 attestation from GitHub API
✓ Verification succeeded!

--repo names the repository that stores the attestation. --signer-workflow names the workflow that signed it. The check fails for an attestation signed by any other workflow.

SBOM and provenance attestations

For each image and each architecture, the shared workflow extracts an SBOM in SPDX format and a provenance attestation in SLSA format. It signs each file and the release job attaches the files to the GitHub release. The names follow this pattern:

  • RuntimeEnforcer-<component>-attestation-<arch>-provenance.intoto.jsonl

  • RuntimeEnforcer-<component>-attestation-<arch>-sbom.json

These files come from the container build. They carry the layer and build-arg detail that actions/attest does not. The actions/attest attestation above is the one that carries the SLSA level.

Each file has a Sigstore bundle with the same name and the suffix .bundle.sigstore. Download the file and its bundle from the release page, then verify the provenance:

cosign verify-blob \
  --certificate-oidc-issuer=https://token.actions.githubusercontent.com \
  --certificate-identity-regexp='^https://github\.com/kubewarden/github-actions/\.github/workflows/container-release\.yml@' \
  --certificate-github-workflow-repository=kubewarden/runtime-enforcer \
  --certificate-github-workflow-ref='refs/tags/v0.10.1' \
  --bundle RuntimeEnforcer-controller-attestation-amd64-provenance.intoto.jsonl.bundle.sigstore \
  RuntimeEnforcer-controller-attestation-amd64-provenance.intoto.jsonl

Verified OK

And the SBOM:

cosign verify-blob \
  --certificate-oidc-issuer=https://token.actions.githubusercontent.com \
  --certificate-identity-regexp='^https://github\.com/kubewarden/github-actions/\.github/workflows/container-release\.yml@' \
  --certificate-github-workflow-repository=kubewarden/runtime-enforcer \
  --certificate-github-workflow-ref='refs/tags/v0.10.1' \
  --bundle RuntimeEnforcer-controller-attestation-amd64-sbom.json.bundle.sigstore \
  RuntimeEnforcer-controller-attestation-amd64-sbom.json

Verified OK

After the check, you can read the files. The SBOM lists the packages in the image. The provenance names the source commit, the builder, and the build parameters.

The same attestations are also attached to each image in the registry, in the format that Docker uses. The signed copies are the release assets. To read the registry copy, list the attestation manifest with crane:

crane manifest ghcr.io/kubewarden/runtime-enforcer/controller:v0.10.1 \
  | jq '.manifests[] | select(.annotations["vnd.docker.reference.type"]=="attestation-manifest")'

Then fetch the manifest by its digest and read each layer with crane blob.

Helm chart

The Runtime Enforcer chart is in the Helm repository at https://charts.kubewarden.io and, as an OCI artifact, at ghcr.io/kubewarden/charts/runtime-enforcer. The OCI copy is signed. The kubewarden/helm-charts repository builds, signs and attests the chart with its own chart-release.yml reusable workflow. The workflow packages the chart from the commit that the signature and the attestation name, so no step outside the workflow can change it.

The chart carries two cosign signature formats. Run the following two commands to verify them:

cosign verify --new-bundle-format=false \
  --certificate-oidc-issuer=https://token.actions.githubusercontent.com \
  --certificate-identity-regexp='^https://github\.com/kubewarden/helm-charts/\.github/workflows/chart-release\.yml@' \
  --certificate-github-workflow-repository=kubewarden/helm-charts \
  --certificate-github-workflow-ref='refs/heads/main' \
  ghcr.io/kubewarden/charts/runtime-enforcer:0.2.1

Verification for ghcr.io/kubewarden/charts/runtime-enforcer:0.2.1 --
The following checks were performed on each of these signatures:
  - The cosign claims were validated
  - Existence of the claims in the transparency log was verified offline
  - The code-signing certificate was verified using trusted certificate authority certificates

<snipped json>
cosign verify-attestation --new-bundle-format=true \
  --type https://sigstore.dev/cosign/sign/v1 \
  --certificate-oidc-issuer=https://token.actions.githubusercontent.com \
  --certificate-identity-regexp='^https://github\.com/kubewarden/helm-charts/\.github/workflows/chart-release\.yml@' \
  ghcr.io/kubewarden/charts/runtime-enforcer:0.2.1

The workflow also runs actions/attest on the chart. That attestation gives the chart SLSA Build L3. GitHub stores it in the kubewarden/helm-charts repository. The GitHub CLI verifies it:

gh attestation verify oci://ghcr.io/kubewarden/charts/runtime-enforcer:0.2.1 \
  --repo kubewarden/helm-charts \
  --signer-workflow kubewarden/helm-charts/.github/workflows/chart-release.yml

The workflow also attests the packaged .tgz file that the GitHub release carries. Download the file from the release page, then verify it:

gh attestation verify runtime-enforcer-0.2.1.tgz \
  --repo kubewarden/helm-charts \
  --signer-workflow kubewarden/helm-charts/.github/workflows/chart-release.yml

To list every image that the chart deploys, render it and extract the image fields:

helm template runtime-enforcer oci://ghcr.io/kubewarden/charts/runtime-enforcer \
  --version 0.2.1 \
  | yq '..|.image? | select(.)' \
  | sort -u

Verify each Runtime Enforcer image in that list as the container images section shows.

Third-party images

The chart also deploys one image that the Runtime Enforcer project does not build and does not sign:

  • otel/opentelemetry-collector-contrib, when telemetry.collectorStrategy is default.

Verify it with the method that its own project documents.

kubectl plugin

The kubectl-runtime_enforcer binaries on the release page come with a SHA-256 checksum file each, named with the suffix .sha256. The checksum lets you check that the download is complete and not corrupted:

sha256sum -c kubectl-runtime_enforcer-linux-amd64.sha256
kubectl-runtime_enforcer-linux-amd64: OK

The checksum shows that the file matches what the release page lists. It does not show who built the file. For that, the release workflow runs actions/attest on each binary. GitHub stores the attestation in the Runtime Enforcer repository. Verify it with the GitHub CLI:

gh attestation verify kubectl-runtime_enforcer-linux-amd64 \
  --repo kubewarden/runtime-enforcer

Loaded digest sha256:... for file://kubectl-runtime_enforcer-linux-amd64
Loaded 1 attestation from GitHub API
✓ Verification succeeded!

The attestation names the source commit and the workflow run that built the binary. The same command, with another file name, verifies the other binaries.