Verifying Kubernetes Platform Binaries Before Deployment
Required knowledge for the CKS certification.
Kubernetes binaries — kubectl, kubeadm, and kubelet — are downloaded from dl.k8s.io and deployed directly onto control plane and worker nodes. A tampered binary grants an attacker full control over every cluster operation that binary performs: a backdoored kubectl can silently exfiltrate credentials on every API call; a modified kubelet can expose container filesystems to the host. Verifying binaries before they are installed or executed is a supply chain control that closes this vector.
The Kubernetes project publishes two independent verification mechanisms for every release:
- SHA256 checksum files — a simple hash comparison that confirms the binary has not changed since it was released.
- Cosign keyless signatures — a cryptographic signature issued by the Kubernetes release pipeline via Sigstore, which additionally proves who signed the artifact and when.
Both mechanisms are supported for all official Kubernetes binaries.
1. SHA256 Checksum Verification
Issue: A downloaded binary may have been altered in transit or on the mirror host, or replaced by a compromised CDN node.
Fix: Download the corresponding .sha256 checksum file from the same dl.k8s.io source and verify the binary against it before installation.
The Kubernetes documentation states: "Download the same version of the binary and checksum."
Verify kubectl
Download the binary and its checksum file for the current stable release:
KUBE_VERSION=$(curl -L -s https://dl.k8s.io/release/stable.txt)
# Download kubectl and its SHA256 checksum (x86-64)
curl -LO "https://dl.k8s.io/release/${KUBE_VERSION}/bin/linux/amd64/kubectl"
curl -LO "https://dl.k8s.io/release/${KUBE_VERSION}/bin/linux/amd64/kubectl.sha256"
Verify the binary:
echo "$(cat kubectl.sha256) kubectl" | sha256sum --check
Expected output (pass):
kubectl: OK
Expected output (fail):
kubectl: FAILED
sha256sum: WARNING: 1 computed checksum did NOT match
If verification fails, do not install the binary. Discard both the binary and checksum file, and re-download from dl.k8s.io.
Verify kubeadm and kubelet
The same checksum URL pattern applies to all Kubernetes node binaries. Substitute kubeadm or kubelet as the binary name:
KUBE_VERSION=$(curl -L -s https://dl.k8s.io/release/stable.txt)
for BINARY in kubeadm kubelet; do
curl -LO "https://dl.k8s.io/release/${KUBE_VERSION}/bin/linux/amd64/${BINARY}"
curl -LO "https://dl.k8s.io/release/${KUBE_VERSION}/bin/linux/amd64/${BINARY}.sha256"
echo "$(cat ${BINARY}.sha256) ${BINARY}" | sha256sum --check
done
Proceed with installation only after every binary prints OK.
Verify a Pinned Version
When you need to verify a specific release rather than the current stable version, set KUBE_VERSION explicitly:
KUBE_VERSION="v1.37.0"
curl -LO "https://dl.k8s.io/release/${KUBE_VERSION}/bin/linux/amd64/kubectl"
curl -LO "https://dl.k8s.io/release/${KUBE_VERSION}/bin/linux/amd64/kubectl.sha256"
echo "$(cat kubectl.sha256) kubectl" | sha256sum --check
2. Cosign Signature Verification
The Kubernetes release pipeline uses cosign keyless signing to sign all binary artifacts. Per the official documentation: "The Kubernetes release process signs all binary artifacts (tarballs, SPDX files, standalone binaries) by using cosign's keyless signing."
Cosign signature verification is stronger than a SHA256 checksum alone: the signature is tied to a specific release identity issued by the Kubernetes release infrastructure (krel-staging@k8s-releng-prod.iam.gserviceaccount.com), so a checksum file that was itself tampered on the mirror cannot produce a valid cosign signature.
Prerequisites: Install cosign from https://docs.sigstore.dev/cosign/system_config/installation/ and curl.
Verify a Binary with Cosign
KUBE_VERSION=$(curl -L -s https://dl.k8s.io/release/stable.txt)
URL="https://dl.k8s.io/release/${KUBE_VERSION}/bin/linux/amd64"
BINARY=kubectl
# Download the binary, its cosign signature, and its certificate
for FILE in "${BINARY}" "${BINARY}.sig" "${BINARY}.cert"; do
curl -sSfL --retry 3 --retry-delay 3 "${URL}/${FILE}" -o "${FILE}"
done
# Verify the signature
cosign verify-blob "${BINARY}" \
--signature "${BINARY}.sig" \
--certificate "${BINARY}.cert" \
--certificate-identity krel-staging@k8s-releng-prod.iam.gserviceaccount.com \
--certificate-oidc-issuer https://accounts.google.com
A successful verification prints:
Verified OK
Run the same commands for kubeadm and kubelet by substituting the BINARY variable.
3. Verifying Kubernetes Container Images
Control plane components (kube-apiserver, kube-controller-manager, kube-scheduler, etcd) are distributed as container images. The Kubernetes project signs these images with cosign using the identity krel-trust@k8s-releng-prod.iam.gserviceaccount.com.
Prerequisite: jq (available at https://jqlang.github.io/jq/download/).
Verify a Single Image
cosign verify registry.k8s.io/kube-apiserver-amd64:v1.37.0 \
--certificate-identity krel-trust@k8s-releng-prod.iam.gserviceaccount.com \
--certificate-oidc-issuer https://accounts.google.com \
| jq .
Verify All Control Plane Images for the Stable Release
KUBE_VERSION=$(curl -Ls https://dl.k8s.io/release/stable.txt)
curl -Ls "https://sbom.k8s.io/${KUBE_VERSION}/release" \
| grep "SPDXID: SPDXRef-Package-registry.k8s.io" \
| grep -v sha256 | cut -d- -f3- | sed 's/-/\//' | sed 's/-v1/:v1/' \
| sort > images.txt
while IFS= read -r image; do
cosign verify "${image}" \
--certificate-identity krel-trust@k8s-releng-prod.iam.gserviceaccount.com \
--certificate-oidc-issuer https://accounts.google.com \
| jq .
done < images.txt
Pin Verified Images by Digest
After verifying an image, pin it by digest in your Pod manifest so that a future tag rewrite cannot silently substitute a different image:
containers:
- name: kube-apiserver
# Replace <digest> with the sha256 digest reported by `cosign verify` above
image: registry.k8s.io/kube-apiserver-amd64@sha256:<digest>
4. Verifying the Kubernetes SBOM
The Kubernetes project publishes a Software Bill of Materials (SBOM) for each release at sbom.k8s.io. Verifying the SBOM confirms that the full package inventory matches what the release pipeline published.
VERSION=$(curl -Ls https://dl.k8s.io/release/stable.txt)
# Download the SBOM
curl -Ls "https://sbom.k8s.io/${VERSION}/release" -o "${VERSION}.spdx"
# Verify the SHA256 sum
echo "$(curl -Ls "https://sbom.k8s.io/${VERSION}/release.sha256") ${VERSION}.spdx" | sha256sum --check
# Optionally verify the SHA512 sum as well
echo "$(curl -Ls "https://sbom.k8s.io/${VERSION}/release.sha512") ${VERSION}.spdx" | sha512sum --check
# Verify the cosign signature
curl -Ls "https://sbom.k8s.io/${VERSION}/release.sig" -o "${VERSION}.spdx.sig"
curl -Ls "https://sbom.k8s.io/${VERSION}/release.cert" -o "${VERSION}.spdx.cert"
cosign verify-blob \
--certificate "${VERSION}.spdx.cert" \
--signature "${VERSION}.spdx.sig" \
--certificate-identity krel-staging@k8s-releng-prod.iam.gserviceaccount.com \
--certificate-oidc-issuer https://accounts.google.com \
"${VERSION}.spdx"
5. What This Guide Does Not Cover
Binary verification confirms integrity at download time. It does not replace:
- Runtime integrity monitoring — a binary can be replaced after installation. Use tools such as Falco to detect unexpected binary modifications at runtime.
- Node OS hardening — securing the host filesystem and package manager to prevent post-install tampering.
- Container image scanning — verifying that image contents are free of known CVEs after their signatures are confirmed. See Trivy.
References
This article is based on information from the following official sources:
- Verify Signed Kubernetes Artifacts - Kubernetes Documentation
- Install kubectl on Linux - Kubernetes Documentation