Building Secure OCI Image Pipelines with Cosign and Kyverno Enforcement
Learn how to secure your software supply chain by cryptographically signing OCI container images with Cosign and enforcing runtime verification using Kyverno in Kubernetes.
Summary
- Cryptographic image signing guarantees software integrity and trusted origin across distributed environments.
- Cosign simplifies key generation and validation without the complexity of heavy traditional PKI infrastructures.
- Runtime admission policies immediately block the execution of tampered or unverified container images.
- Automated continuous integration reduces human error by embedding signatures directly into the build pipeline.
- Cluster security failure observability prevents production incidents before workloads are scaled.
The Trust Challenge in Container Images
In modern software development, containers have standardized how we package applications and their dependencies. The OCI format, standing for Open Container Initiative (an open specification dictating how container images and runtimes must operate), has become the universal industry standard. However, the fact that an image runs successfully does not guarantee that it is trustworthy or that it has not been modified by an attacker along the path between the private registry and the production cluster. In practice, this means trusting any image tag blindly is equivalent to receiving a sealed package in the mail without knowing who sent it or whether the contents were compromised.
To solve this problem, modern engineering turns to cryptographic signing. Much like signing a physical contract with a notarized signature or using a digital key to validate a banking transaction, container signing uses advanced mathematics to attest to two vital properties: who built the image and whether it suffered any alteration after the build. When we introduce tools like Cosign into the workflow, we transform the deployment process into a mathematically verifiable operation, eliminating exclusive reliance on repository access credentials.
Understanding Cryptographic Signing with Cosign
Cosign is a tool developed by the cloud-native community that simplifies the signing, verification, and storage of OCI artifacts. Unlike legacy solutions that require the complex management of X.509 certificates and traditional certificate authorities, Cosign operates simply through asymmetric key pairs or using OIDC-based identities, which stands for OpenID Connect (an authentication protocol allowing identity verification through trusted providers like Google or GitHub). In practice, the private key remains restricted to the secure CI environment, while the public key is distributed to the servers responsible for verification.
When a developer triggers a build, the pipeline runs automated tests, builds the image, and immediately uses Cosign to sign the cryptographic hash of the image stored in the registry. This signature is pushed to the same container registry as an associated artifact, creating an inseparable link between the binary and the proof of authenticity. If an attacker alters a single byte of the image inside the repository, the resulting hash changes immediately, invalidating the signature and causing the image to be rejected by any subsequent verification system.
Ensuring Cluster Security with Kyverno
Signing images is only the first step in a robust security strategy. The second step, equally critical, occurs the moment the cluster attempts to run that image. This is where Kyverno enters, a native Kubernetes policy engine that acts as a strict doorman for your environment. Kubernetes is the container orchestrator managing where and how applications run, and Kyverno intercepts all pod creation requests to check if they comply with organizational compliance criteria.
In practice, we configure Kyverno to require that any image attempting to run in the cluster possesses a valid signature issued by the company's trusted key. If a developer tries to deploy an unsigned image or one signed by an unknown key, Kyverno rejects the request instantly, preventing unaudited code from touching the compute nodes. This mechanism operates transparently and declaratively, allowing security teams to define complex rules using simple YAML without writing scripts in obscure languages.
Implementing the Automated Pipeline Workflow
To put this architecture into practice, we need to integrate image generation and signing directly into our continuous integration pipeline, such as GitHub Actions or GitLab CI. The procedure involves compiling code, pushing the image to the OCI registry, and immediately signing the resulting artifact before the pipeline finishes. Below, we visualize the core steps executed by the automation system to ensure no image is promoted without prior validation:
- Code is tested and compiled within an isolated build environment.
- The resulting image is pushed to the private OCI registry using temporary credentials.
- Cosign is triggered using the private key stored securely within repository secrets.
- The cryptographic signature is generated and pushed to the same image registry.
- The Kubernetes manifest is updated to reference the image and its immutable tag.
Using immutable tags, such as the image's SHA-256 hash instead of mutable tags like 'latest', is a fundamental requirement to prevent tag-spoofing attacks. When pointing to a specific hash, we have the absolute guarantee that the code running in production is precisely the one that passed security tests and received the cryptographic signature.
Validating Images at Runtime with Declarative Policies
With images properly signed in the registry, the next step is configuring Kyverno in the Kubernetes cluster to enforce this validation. We create an admission policy, known in Kyverno vocabulary as a ClusterPolicy, which intercepts any attempt to create Pod resources. The configuration file instructs Kyverno to internally query Cosign to verify that the image possesses a valid signature linked to our official public key. Below, we examine the conceptual structure of this validation rule enforced directly by the policy engine:
apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
name: verify-image-signatures
spec:
validationFailureAction: Enforce
rules:
- name: check-cosign-signature
match:
any:
- resources:
kinds:
- Pod
verifyImages:
- imageReferences:
- "registry.company.com/*"
attestors:
- count: 1
entries:
- keys:
publicKeys: "-----BEGIN PUBLIC KEY-----\n...-----\n-----\n"
This configuration block ensures enforcement mode is active, actively blocking any attempt to run unsigned code. If a violation is attempted, the cluster operator receives a descriptive error detailing that the image signature failed cryptographic checks, keeping the attack surface rigorously controlled.
Final Considerations and Next Steps
Building secure OCI image pipelines using Cosign signing and runtime verification with Kyverno represents a significant leap in the security maturity of any modern Kubernetes-based infrastructure. By replacing blind trust in repositories with mathematical guarantees and automated policies, organizations protect their systems against sophisticated supply chain attacks. Although it requires initial setup effort and cultural shift in build processes, return on investment translates to operational resilience, regulatory compliance, and peace of mind knowing only authenticated and audited code inhabits the production environment.