Kubernetes Security: Signing and Verifying Images with Cosign and Kyverno
Master Kubernetes security by implementing image signing and verification. Learn to use Sigstore Cosign and Kyverno to ensure supply chain security and provenance.
If you're still relying on image tags like :latest or simply trusting that the image in your registry is what you think it is, your supply chain is wide open. Attackers don't just target code; they target the delivery pipeline. By implementing Kubernetes Security through image signing, you ensure that every container running in your cluster is exactly what your CI/CD pipeline built and approved.
In this guide, we’ll use Sigstore Cosign to sign our artifacts and Kyverno as the admission controller to verify those signatures before allowing a pod to start. This is the gold standard for establishing Image Provenance in modern clusters.
The Strategy: Trust, but Verify
We're building a "deny-by-default" architecture. If an image isn't signed by our private key, Kyverno will reject the deployment. This prevents unauthorized or tampered images from reaching production. It’s a natural evolution of the Kubernetes Policy Management with Kyverno and GitOps approach, where we shift from manual audits to automated, policy-driven enforcement.
1. Signing Images with Sigstore Cosign
First, we need to generate a key pair. Cosign (version 2.0+) makes this trivial. Run these commands on your local machine or your CI runner:
Bash# Generate a key pair cosign generate-key-pair # Sign the image using the private key cosign sign --key cosign.key my-registry.com/my-app:v1.0.0
This creates a signature in your registry linked to your image digest. You’ve now established a cryptographic link between your build process and your registry. Just as we use Kubernetes Security Auditing: Automating Trivy with Admission Controllers to catch vulnerabilities, signing provides the "who" and "how" behind the image's origin.
2. Implementing Verification with Kyverno
Now that our images are signed, we need to tell Kubernetes to enforce this. We’ll deploy a ClusterPolicy in Kyverno that intercepts CREATE and UPDATE requests for Pods.
Create a file named verify-image.yaml:
YAMLapiVersion: kyverno.io/v1 kind: ClusterPolicy metadata: name: check-image-signature spec: validationFailureAction: Enforce background: false rules: - name: verify-signature match: resources: kinds: - Pod verifyImages: - imageReferences: - "my-registry.com/my-app:*" attestors: - entries: - keys: publicKeys: |- -----BEGIN PUBLIC KEY----- [YOUR_PUBLIC_KEY_HERE] -----END PUBLIC KEY-----
Apply this with kubectl apply -f verify-image.yaml. Now, if a developer tries to deploy an unsigned image—or an image signed by a different key—Kyverno will block the request immediately.
Why This Matters for Supply Chain Security
Supply Chain Security isn't just a buzzword; it's a defensive requirement. By using Cosign, you're verifying the signature at the digest level, which is immutable. Even if someone pushes a malicious image with the same tag, the signature won't match, and the deployment will fail.
Pairing this with other security layers makes your cluster significantly harder to compromise. For instance, while we secure the source of the image here, you should also be managing your network traffic using Kubernetes Networking: Implementing Zero-Trust with Cilium and Hubble to ensure that even if a container is compromised, it can't move laterally.
Pro-Tips for Production
- Key Management: Don't store your
cosign.keyin Git. Use a secret manager. Better yet, look into Cosign's support for Keyless signing using OIDC (GitHub Actions, for example), which removes the headache of managing private keys entirely. - Fail-Open vs. Fail-Closed: Start with
validationFailureAction: Auditwhile you roll this out. Once you're sure your pipeline is signing everything correctly, flip it toEnforce. - Monitoring: Use Kyverno's metrics to track how many requests are being rejected. If you see a spike, you know your pipeline is misconfigured.
Final Thoughts
Integrating Sigstore Cosign and Kyverno creates a robust gatekeeper for your cluster. You aren't just hoping your images are safe; you're proving they are. By automating these checks, you remove human error from the deployment process and ensure that Kubernetes Security is a baseline, not an afterthought. Start small, sign your core images, and scale your enforcement policy across your production namespaces.