Skip to main content

Verifying Releases

Headlamp releases are signed, so you can check that what you downloaded was built by the Headlamp project and hasn't been tampered with.

Release checksums, container images, and Helm charts are signed with Sigstore keyless signing in the GitHub Actions workflows that build them, so there is no long-lived private key that could leak. Release tags are signed by the maintainer who creates the release, with their own key. The Helm chart is also signed with GPG.

Desktop app and Helm chart releases also include SLSA provenance, which records the GitHub Actions workflow, branch or tag, and commit that built them. Provenance is also stored in GitHub's attestation API, so it can be checked with the GitHub CLI.

note

Signatures for release checksums, container images, and release tags start with the first release after v0.45.0. For v0.45.0 and earlier, checksums.txt is not signed, so it only protects against corrupted downloads, not tampered ones. Provenance for desktop app and Helm chart releases starts with the first release after v0.46.0.

The cosign commands on this page need cosign v2.6.3 or later, because older versions cannot read the signature format that Headlamp releases use.

Desktop apps and binaries​

Each GitHub release includes:

  • checksums.txt: the SHA-256 checksums of the release's apps and binaries.
  • checksums.txt.sigstore.json: a Sigstore signature bundle for checksums.txt.
  • headlamp-X.Y.Z.intoto.jsonl: SLSA provenance for the files listed in checksums.txt.

To verify a download, first verify checksums.txt. It is signed by the release assets workflow running from the main branch:

cosign verify-blob checksums.txt \
--bundle checksums.txt.sigstore.json \
--certificate-identity 'https://github.com/kubernetes-sigs/headlamp/.github/workflows/push-release-assets.yml@refs/heads/main' \
--certificate-oidc-issuer https://token.actions.githubusercontent.com

Then check the files you downloaded against it:

sha256sum --check --ignore-missing checksums.txt

On macOS, use shasum -a 256 --check --ignore-missing checksums.txt. On Windows, use PowerShell (replace the file name with the one you downloaded); it prints True if the checksum matches:

$file = 'Headlamp-X.Y.Z-win-x64.exe'
$expected = (Select-String -Path checksums.txt -Pattern " $file`$").Line.Split(' ')[0]
(Get-FileHash -Algorithm SHA256 $file).Hash -eq $expected

The macOS app is also signed and notarized by Apple, so macOS verifies it at install time. The Windows installers are not yet Authenticode signed, so verify them with checksums.txt as described above.

To check the provenance of a download, which was generated by the app build workflows:

gh attestation verify Headlamp-X.Y.Z-linux-x64.AppImage \
--repo kubernetes-sigs/headlamp \
--bundle headlamp-X.Y.Z.intoto.jsonl \
--cert-identity-regex '^https://github\.com/kubernetes-sigs/headlamp/\.github/workflows/app-artifacts-(linux|mac|win)\.yml@'

The output shows the workflow and the branch or tag that it built. Without --bundle, gh fetches the provenance from GitHub instead.

Container images​

Release images at ghcr.io/headlamp-k8s/headlamp are signed when they are built from a release tag, and come with build provenance attestations:

cosign verify ghcr.io/headlamp-k8s/headlamp:vX.Y.Z \
--certificate-identity-regexp '^https://github\.com/kubernetes-sigs/headlamp/\.github/workflows/container-publish\.yml@refs/tags/v' \
--certificate-oidc-issuer https://token.actions.githubusercontent.com

The nightly image is signed by scheduled builds from main or manual builds from a selected branch. Both publish to the same nightly tag. To verify an image built from main:

cosign verify ghcr.io/headlamp-k8s/headlamp:nightly \
--certificate-identity 'https://github.com/kubernetes-sigs/headlamp/.github/workflows/nightly-build.yml@refs/heads/main' \
--certificate-oidc-issuer https://token.actions.githubusercontent.com

For a manual build from another branch, replace refs/heads/main in the certificate identity above with refs/heads/<selected-branch>.

Helm chart​

Each chart release on GitHub (headlamp-helm-X.Y.Z) includes the chart package, headlamp-X.Y.Z.tgz, a Sigstore signature bundle for it, headlamp-X.Y.Z.tgz.sigstore.json, SLSA provenance for it, headlamp-X.Y.Z.tgz.intoto.jsonl, and a GPG .prov provenance file.

note

Sigstore signatures and SLSA provenance for the chart start with the first chart release after 0.46.0.

To verify the chart with cosign, download the chart and its signature bundle, then check that it was signed by the chart release workflow running from the main branch:

helm repo add headlamp https://kubernetes-sigs.github.io/headlamp/
helm pull headlamp/headlamp --version X.Y.Z
curl -LO https://github.com/kubernetes-sigs/headlamp/releases/download/headlamp-helm-X.Y.Z/headlamp-X.Y.Z.tgz.sigstore.json
cosign verify-blob headlamp-X.Y.Z.tgz \
--bundle headlamp-X.Y.Z.tgz.sigstore.json \
--certificate-identity 'https://github.com/kubernetes-sigs/headlamp/.github/workflows/helm-chart-release.yml@refs/heads/main' \
--certificate-oidc-issuer https://token.actions.githubusercontent.com

To check the chart's provenance, which was generated by the same workflow:

gh attestation verify headlamp-X.Y.Z.tgz \
--repo kubernetes-sigs/headlamp \
--cert-identity 'https://github.com/kubernetes-sigs/headlamp/.github/workflows/helm-chart-release.yml@refs/heads/main'

The GPG signature (key fingerprint 2956 B7F7 1677 6937 0C93 730C 7264 DA7B 85D0 8A37) can be verified with Helm:

note

The public key is not currently available from public keyservers (see #5093), so the gpg --recv-keys command below fails until it is published.

gpg --keyserver hkps://keys.openpgp.org --recv-keys 2956B7F7167769370C93730C7264DA7B85D08A37
gpg --export 2956B7F7167769370C93730C7264DA7B85D08A37 > headlamp-pubring.gpg
helm repo add headlamp https://kubernetes-sigs.github.io/headlamp/
helm pull headlamp/headlamp --verify --keyring headlamp-pubring.gpg

Source code​

Release tags are signed by the maintainer who creates the release. To check a tag, open it on GitHub and look for the Verified label, which means GitHub has matched the signature to a key registered on the maintainer's GitHub account.

To check a tag locally with git tag -v, first get the public key of the maintainer who created it (shown as the tagger by git show vX.Y.Z; replace USERNAME and EMAIL below with their GitHub username and tagger email).

For SSH-signed tags:

curl -s https://api.github.com/users/USERNAME/ssh_signing_keys \
| jq -r '.[].key' | sed 's/^/EMAIL /' > allowed_signers
git -c gpg.ssh.allowedSignersFile=allowed_signers tag -v vX.Y.Z

For GPG-signed tags:

curl -s https://github.com/USERNAME.gpg | gpg --import
git tag -v vX.Y.Z