Verify a release¶
How to check that the binaries, the image and the chart you install are the ones Picaporte Labs published, and where to find the list of what each one is made of (its SBOM).
What each release carries¶
Every release after 0.43.0 is signed and carries its SBOMs:
kubelatch_<version>_checksums.txt, the SHA-256 of every archive and SBOM of the release, with its signature inkubelatch_<version>_checksums.txt.sigstore.json. One signature covers every file, through their sums.kubelatch-server_<version>_sbom.cdx.jsonandkubelatch_<version>_sbom.cdx.json, the SBOMs of the server and of the CLI in CycloneDX 1.6: the Go modules built into each binary and, for the server, the npm packages of the web interface it serves, without development dependencies. Every platform builds in the same modules, so there is one SBOM per binary.- The image
ghcr.io/picaportelabs/kubelatchand the chartoci://ghcr.io/picaportelabs/charts/kubelatch, signed. The image also carries the server's SBOM as a signed attestation.
0.43.0 and older releases carry neither signatures nor SBOMs: check their downloads with the checksums file alone.
The public key¶
Releases are signed with this key. Save it as cosign.pub:
cat > cosign.pub <<'EOF'
-----BEGIN PUBLIC KEY-----
MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEIYpTAe7hLuZkNNSYfVPSxIrBSKWc
R10WGKhT2Umk9EjK1E7BafB2BqlUo6B8dn127mgMnp9jwdc6VpzX9SOg9A==
-----END PUBLIC KEY-----
EOF
Keep that copy next to your pipelines and check against it, rather than fetching the key again from the place you download the release from: whoever could replace a release there could replace the key as well. The same key is cosign.pub at the root of the public repository, for comparing once. Every signature is also recorded in Rekor, Sigstore's public transparency log.
The checks below need cosign 3 or later.
Check the binaries¶
With cosign.pub saved, download the checksums file and its signature next to the archives you downloaded, check the signature, and then each archive against the sums:
VERSION=0.44.0 # a release after 0.43.0, without the v
REL="https://github.com/picaportelabs/kubelatch/releases/download/v$VERSION"
curl -fsSLO "$REL/kubelatch_${VERSION}_checksums.txt"
curl -fsSLO "$REL/kubelatch_${VERSION}_checksums.txt.sigstore.json"
cosign verify-blob --key cosign.pub \
--bundle "kubelatch_${VERSION}_checksums.txt.sigstore.json" "kubelatch_${VERSION}_checksums.txt"
sha256sum --ignore-missing -c "kubelatch_${VERSION}_checksums.txt"
Verified OK means the checksums file is the one that was signed, and sha256sum then prints … OK for each file you have. On macOS, use shasum -a 256 --ignore-missing -c instead of sha256sum.
On a machine without internet access, add --insecure-ignore-tlog=true to cosign verify-blob: it checks the signature against the key and skips the lookup in Rekor, which needs the network.
Check the image and the chart¶
cosign verify --key cosign.pub "ghcr.io/picaportelabs/kubelatch:$VERSION"
cosign verify --key cosign.pub "ghcr.io/picaportelabs/charts/kubelatch:$VERSION"
Each command prints the signed digest (docker-manifest-digest) and fails when the tag points at anything kubelatch did not sign. The image's signature covers its index, both platforms included.
Read the SBOM¶
The SBOMs of the binaries are files of the release, covered by the signed checksums. The one attached to the image is the server's, since the image adds kubelatch-server alone to its base, gcr.io/distroless/static-debian12. To take it from the image, with its signature checked:
cosign verify-attestation --key cosign.pub --type cyclonedx "ghcr.io/picaportelabs/kubelatch:$VERSION" \
| head -n 1 | jq -r .payload | base64 -d | jq .predicate > "kubelatch-server_${VERSION}_sbom.cdx.json"
Any tool that reads CycloneDX takes it: Dependency-Track, Grype or Trivy, for example.
If a check fails¶
cosign verify-bloborcosign verifyfails: what you downloaded is not what was published, or the key is not the one on this page. Install nothing, download again from the releases, and if it fails again write tosecurity@kubelatch.com.sha256sumprintsFAILEDfor an archive: that archive is not the published one; download it again.no signatures found: on 0.43.0 or older it is expected, since they carry no signature. On a later release, install nothing and do as above.