| Tested on | Rocky Linux 10.2 (Red Quartz) workstation |
|---|---|
| Package | cosign 2.4.1kubectl v1.36.3 (verified download) |
| Applies to | Ubuntu, Debian, Kali Linux, Linux Mint, Pop!_OS, Raspberry Pi OS, elementary OS, Zorin OS, Parrot OS, MX Linux, RHEL, Rocky Linux, AlmaLinux, Oracle Linux, CentOS Stream, Fedora Kubernetes cluster |
| Cert prep | CKS |
| Privilege | Normal user for download and verification; sudo to install binaries under /usr/local/bin |
| Scope | Resolve and record a Kubernetes release version, verify kubectl checksums and Cosign signatures, validate a signed control-plane image and release SPDX SBOM, demonstrate common failure modes, and build a repeatable verification workflow. Does not cover signing your own application images, building Kubernetes from source, private registry configuration, vulnerability scanning, or CI/CD promotion pipelines. |
| Related guides | Kubernetes CIS benchmark with kube-bench Kubernetes PKI and certificates |
Before you copy kubectl into /usr/local/bin or roll out a new control-plane image, confirm the bytes match the official release and were signed by Kubernetes release engineering. This walkthrough verifies one standalone binary, one release SPDX SBOM, and one signed kube-apiserver image for Kubernetes v1.36.3 on linux/amd64.
dl.k8s.io, sbom.k8s.io, and registry.k8s.io. It does not teach Cosign for your own application images, run Trivy or other vulnerability scanners, or configure private registries. For workload signing workflows, see Cosign sign and verify container images.
Understand the verification layers
Supply-chain checks stack from fast integrity tests to publisher identity and immutable image references:
| Verification | Question answered |
|---|---|
| Checksum | Do these bytes match the published file? |
| Signature | Was the artifact signed by the expected identity? |
| Digest | Is this the exact immutable container image? |
| SBOM | What components does this release declare? |
A matching SHA256 hash tells you the file on disk equals the hash file you downloaded. It does not independently prove who published the binary—an attacker who replaces both files on a mirror defeats checksum-only checks. Cosign signature verification pins the certificate identity and OIDC issuer Kubernetes documents for release engineering.
Select an official release
Record the resolved version before you download anything. Do not silently follow stable.txt in automation; write down the exact tag you validated.
For this lab I pin:
| Field | Value |
|---|---|
| Kubernetes version | v1.36.3 |
| Operating system | linux |
| CPU architecture | amd64 |
| Release channel | Official GA from dl.k8s.io |
| Binary base URL | https://dl.k8s.io/release/v1.36.3/bin/linux/amd64 |
| SBOM URL | https://sbom.k8s.io/v1.36.3/release |
| Control-plane image | registry.k8s.io/kube-apiserver-amd64:v1.36.3 |
Create a clean working directory so verification files stay beside the artifact they describe:
mkdir -p ~/k8s-verify && cd ~/k8s-verify
export VERSION=v1.36.3
export URL="https://dl.k8s.io/release/${VERSION}/bin/linux/amd64"Install Cosign on the workstation
Binary and SBOM signature checks use Cosign. Install a current release before you download Kubernetes artifacts:
curl -sSfL "https://github.com/sigstore/cosign/releases/download/v2.4.1/cosign-linux-amd64" -o cosign
chmod +x cosign
sudo mv cosign /usr/local/bin/cosignConfirm the client version:
cosign versionGitVersion: v2.4.1
GitCommit: 9a4cfe1aae777984c07ce373d97a65428bbff734
Platform: linux/amd64Cosign 2.4.x matches the flags used in the current Kubernetes release documentation.
Download the binary and verification files
Download kubectl plus the sidecar files Kubernetes publishes for signature verification. Do not execute the binary until checksum and signature checks pass.
export BINARY=kubectl
curl -sSfL "${URL}/${BINARY}" -o "${BINARY}"Fetch the checksum and Cosign certificate bundle:
curl -sSfL "${URL}/${BINARY}.sha256" -o "${BINARY}.sha256"
curl -sSfL "${URL}/${BINARY}.sig" -o "${BINARY}.sig"
curl -sSfL "${URL}/${BINARY}.cert" -o "${BINARY}.cert"List the files and read the published hash:
ls -l kubectl kubectl.sha256 kubectl.sig kubectl.cert
cat kubectl.sha256-rw-r--r--. 1 user user 59556002 Jul 28 03:09 kubectl
-rw-r--r--. 1 user user 1508 Jul 28 03:09 kubectl.cert
-rw-r--r--. 1 user user 64 Jul 28 03:09 kubectl.sha256
-rw-r--r--. 1 user user 96 Jul 28 03:09 kubectl.sig
ebbd080e7c2e275093b55915722043257eb24004363e20acb3c4d71919f88336The .sha256 file contains only the hex digest. The .sig and .cert files feed cosign verify-blob in the next sections.
Verify the checksum
Format the hash line as digest filename before you run sha256sum --check:
echo "$(cat kubectl.sha256) kubectl" | sha256sum --check -kubectl: OKWhen the bytes match, sha256sum prints OK and exits zero.
To see what a tampered file looks like, append one byte and rerun the same check:
echo "X" >> kubectl
echo "$(cat kubectl.sha256) kubectl" | sha256sum --check -kubectl: FAILED
sha256sum: WARNING: 1 computed checksum did NOT matchRestore the good copy from your download cache or re-fetch the binary before you continue—signature verification will fail on a modified file.
curl -sSfL "${URL}/kubectl" -o kubectlVerify the binary signature
Kubernetes signs release binaries with Cosign keyless signatures. Pin the certificate identity and OIDC issuer from the verify signed artifacts task documentation:
- Certificate identity:
[email protected] - OIDC issuer:
https://accounts.google.com
Run cosign verify-blob against the untouched binary:
cosign verify-blob kubectl \
--certificate kubectl.cert \
--signature kubectl.sig \
--certificate-identity [email protected] \
--certificate-oidc-issuer https://accounts.google.comVerified OKVerified OK means the signature matches the blob and the certificate subject matches the identity you pinned.
Inspect the verified binary
After checksum and signature checks succeed, confirm the artifact is the executable you expect:
file kubectlkubectl: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), statically linked, Go BuildID=..., strippedMake it executable and read the client version:
chmod +x kubectl
./kubectl version --clientClient Version: v1.36.3
Kustomize Version: v5.8.1Install only after these checks pass:
sudo install -o root -g root -m 0755 kubectl /usr/local/bin/kubectlVerify a Kubernetes container image
Control-plane images use a different certificate identity than binaries:
- Certificate identity:
[email protected] - OIDC issuer:
https://accounts.google.com
Verify the signed kube-apiserver image for the same release:
cosign verify registry.k8s.io/kube-apiserver-amd64:v1.36.3 \
--certificate-identity [email protected] \
--certificate-oidc-issuer https://accounts.google.comCosign prints a JSON payload on success. The docker-manifest-digest field is the immutable digest to record:
Verification for registry.k8s.io/kube-apiserver-amd64:v1.36.3 --
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
...
"docker-manifest-digest":"sha256:9ab60d55c6fce46d71ff56b9196529c8afd34700ea9be1a444b8b60f8cf14b34"
...
"Subject":"[email protected]"Store that digest in your install record. When you deploy, prefer the digest form:
registry.k8s.io/kube-apiserver-amd64@sha256:9ab60d55c6fce46d71ff56b9196529c8afd34700ea9be1a444b8b60f8cf14b34Your container runtime may also show a config digest after crictl pull; the manifest digest from Cosign is what you pin for reproducible promotion.
Verify the Kubernetes SBOM
Kubernetes publishes a signed SPDX SBOM per release. Download the document and its verification files:
export SBOM_URL="https://sbom.k8s.io/${VERSION}/release"
curl -sSfL "${SBOM_URL}" -o sbom-release
curl -sSfL "${SBOM_URL}.sha256" -o sbom-release.sha256
curl -sSfL "${SBOM_URL}.sha512" -o sbom-release.sha512
curl -sSfL "${SBOM_URL}.sig" -o sbom-release.sig
curl -sSfL "${SBOM_URL}.cert" -o sbom-release.certVerify the SHA256 checksum:
echo "$(cat sbom-release.sha256) sbom-release" | sha256sum --check -sbom-release: OKVerify the SPDX signature with the same binary identity as kubectl:
cosign verify-blob sbom-release \
--certificate sbom-release.cert \
--signature sbom-release.sig \
--certificate-identity [email protected] \
--certificate-oidc-issuer https://accounts.google.comVerified OKInspect release metadata at the top of the SPDX file:
head -8 sbom-releaseSPDXVersion: SPDX-2.3
DataLicense: CC0-1.0
SPDXID: SPDXRef-DOCUMENT
DocumentName: Kubernetes Release v1.36.3
DocumentNamespace: https://sbom.k8s.io/v1.36.3/release
ExternalDocumentRef:DocumentRef-kubernetes-v1.36.3 https://sbom.k8s.io/v1.36.3/source SHA1: 88a3eb05437b148a79bdbcfc1ea4f1d804ca1292
Creator: Organization: Kubernetes Release Engineering
Creator: Tool: bom-v0.21.1Archive the verified SPDX file, checksum output, and Cosign transcript with your cluster upgrade ticket.
Test failure conditions
Deliberately break one control at a time so you recognize real errors in automation.
Modified binary or wrong checksum
Appending bytes to kubectl makes sha256sum --check report FAILED as shown earlier. Re-download before signature checks.
Wrong signer identity
Pinning the wrong email makes Cosign reject the certificate:
cosign verify-blob kubectl \
--certificate kubectl.cert \
--signature kubectl.sig \
--certificate-identity [email protected] \
--certificate-oidc-issuer https://accounts.google.comError: none of the expected identities matched what was in the certificate, got subjects [[email protected]] with issuer https://accounts.google.comThe message names the subject actually present in the certificate—compare it to the value in Kubernetes documentation.
Wrong OIDC issuer
An incorrect issuer also fails verification:
cosign verify-blob kubectl \
--certificate kubectl.cert \
--signature kubectl.sig \
--certificate-identity [email protected] \
--certificate-oidc-issuer https://evil.example.comError: searching log query: ... verifying signature: invalid signature when validating ASN.1 encoded signatureTreat any non-zero exit from cosign verify or verify-blob as a hard stop.
Unsigned or wrong image
Public images outside the Kubernetes release pipeline carry no matching signature:
cosign verify docker.io/library/nginx:latest \
--certificate-identity [email protected] \
--certificate-oidc-issuer https://accounts.google.comError: no signatures foundDeploying by digest still requires that you verified that digest. Pulling sha256:9ab60d55... after validating v1.36.3 is sound; substituting a different digest without re-verification is not.
Build a verification workflow
The diagram below is the repeatable order of operations for install or upgrade evidence:
Resolve the version explicitly, download artifacts and sidecars together, verify checksum then signature, confirm architecture and client version, install or deploy, and store digests plus Cosign output. Automate the same sequence in CI with pinned identities—not only on the admin laptop.
Troubleshooting
| Symptom | Likely cause | Fix |
|---|---|---|
sha256sum: no properly formatted checksum lines found |
.sha256 file contains only the hex digest |
Pipe echo "$(cat file.sha256) filename" | sha256sum --check - |
Verified OK missing after verify-blob |
Binary modified or wrong .sig/.cert pair |
Re-download binary and sidecars; do not run a tampered binary |
| Identity mismatch error from Cosign | Wrong --certificate-identity for artifact type |
Use krel-staging@... for binaries and SBOM; krel-trust@... for images |
no signatures found on image verify |
Image is not part of the signed Kubernetes release set | Confirm repository name and tag; do not expect signatures on arbitrary public images |
| Cosign cannot reach transparency log | Offline host or firewall | Use documented offline verification flags from Cosign and Kubernetes docs when air-gapped |
What's Next
- Kubernetes RBAC with Examples
- Kubernetes ServiceAccounts with Examples
- Harden Kubernetes API Server Access
References
- Download Kubernetes — official binary locations
- Cosign documentation — Sigstore project
- Kubernetes SBOM — release engineering artifacts
Summary
You walked through the full release verification stack for Kubernetes v1.36.3: checksum integrity on kubectl, Cosign keyless signatures that pin [email protected] for binaries and SBOMs, and [email protected] for the signed kube-apiserver-amd64 image. Recording the resolved version, manifest digest, and verification transcripts gives you evidence for audits and incident response.
The distinction that trips many teams is checksum versus signature. SHA256 catches corrupted or casually swapped files but does not prove publisher identity on its own. Cosign ties the artifact to the release engineering service accounts Kubernetes documents, which is what you want before binaries land on admin hosts or images enter a production registry mirror.
Run the failure demos once so automation alerts look familiar—identity mismatch, bad issuer, and no signatures found should halt promotion immediately. For where supply-chain controls sit in the broader security model, see Kubernetes security architecture. When you move from verifying upstream releases to signing your own workload images, continue with Cosign sign and verify container images.

