Cosign’s primary value isn’t just signing images; it’s about making that signing process a seamless, integrated part of your CI/CD workflow, turning a manual security step into an automated policy enforcement point.

Let’s see Cosign in action within a Tekton pipeline. Imagine a simple pipeline that builds a Go application, pushes it to a registry, and then signs that image.

apiVersion: tekton.dev/v1beta1
kind: Pipeline
metadata:
  name: build-and-sign-app
spec:
  tasks:
    - name: build-and-push
      taskRef:
        name: buildah-build-push
      params:
        - name: IMAGE
          value: index.docker.io/your-dockerhub-user/my-go-app:latest
    - name: sign-image
      taskRef:
        name: cosign-sign
      params:
        - name: IMAGE
          value: index.docker.io/your-dockerhub-user/my-go-app:latest
        - name: KEY_PATH
          value: /keys/cosign.key # Assumes a secret with cosign.key
        - name: PASSWORD_PATH
          value: /keys/cosign.password # Assumes a secret with cosign.password
      runAfter:
        - build-and-push

The buildah-build-push task (which you’d define separately, using standard build tools) handles the image creation and pushing. The crucial part is the cosign-sign task. It takes the image URI and references a Kubernetes Secret containing the private key and its password.

Here’s the cosign-sign Task definition:

apiVersion: tekton.dev/v1beta1
kind: Task
metadata:
  name: cosign-sign
spec:
  params:
    - name: IMAGE
      type: string
    - name: KEY_PATH
      type: string
    - name: PASSWORD_PATH
      type: string
  steps:
    - name: cosign-sign-step
      image: gcr.io/projects/cosign/cosign:v2.2.1 # Use a specific, stable version
      script: |
        #!/usr/bin/env bash
        set -e
        export COSIGN_PASSWORD="$(cat $(params.PASSWORD_PATH))"
        cosign sign --key $(params.KEY_PATH) $(params.IMAGE)
      volumeMounts:
        - name: cosign-keys
          mountPath: /keys # Mounts the secret containing the key and password
  volumes:
    - name: cosign-keys
      secret:
        secretName: cosign-signing-secret # This secret holds cosign.key and cosign.password

When this pipeline runs, the build-and-push task pushes index.docker.io/your-dockerhub-user/my-go-app:latest. Then, the sign-image task executes. It mounts the Kubernetes Secret cosign-signing-secret, which contains cosign.key and cosign.password. The COSIGN_PASSWORD environment variable is set from the file content, and cosign sign is invoked with the private key and the image digest. This attaches a signature to the image in the registry, typically as an OCI annotation.

The core problem Cosign solves here is establishing trust in your container images. Without signing, anyone could push a malicious image with the same tag, and your deployment system might pull it without question. Cosign allows you to verify that the image you’re about to deploy is the exact image that was built and approved by your pipeline, and that it hasn’t been tampered with.

Internally, Cosign leverages the OCI Image Manifest specification. When you sign an image, Cosign creates a separate OCI artifact (often a blob referenced by a manifest list) that contains the signature. This signature artifact is then pushed to the registry and associated with the original image manifest through OCI annotations. The cosign.key is typically an EC private key in PEM format, and the cosign.password is a plain-text password that encrypts the private key (though for automated systems, you might use an unencrypted key file or a KMS integration).

The exact levers you control are the signing key, the image URI, and the registry where the signature is stored. Tekton makes managing the secrets for the key and password straightforward via volumeMounts and secret volume types.

What most people don’t realize is that Cosign signatures are themselves OCI artifacts. When you cosign sign --key <key> <image>, Cosign generates a signature blob and a corresponding manifest. This manifest is then referenced by the original image manifest via annotations. This means you can list, retrieve, and even verify these signature artifacts independently, treating them as first-class citizens within the OCI registry ecosystem.

Once you have signed images, the next logical step is to integrate image verification into your deployment process, ensuring only trusted images reach your cluster.

Want structured learning?

Take the full Tekton course →