top of page
Search

Cosign - Trust your Docker images

  • brki47
  • Jul 23
  • 3 min read

Security has become one of the main concerns in recent years, especially with AI. Attackers gain new possibilities to compromise your system. One rogue pod in your Kubernetes cluster can create a mess and affect your whole system.


Cosign is a tool for signing OCI containers (and other artifacts) using Sigstore!


Cosign aims to make signatures invisible infrastructure.

Cosign supports:

  • "Keyless signing" with the Sigstore public good Fulcio certificate authority and Rekor transparency log (default)

  • Hardware and KMS signing

  • Signing with a cosign generated encrypted private/public keypair

  • Container Signing, Verification and Storage in an OCI registry.

  • Bring-your-own PKI


Cosign has integration with Infisical, a secret management tool I already wrote about.

This allows us to use our own private-public key for signing. Integrate Cosign and Infisical:

  • Create KMS project in Infisical

  • Add KMS project in Infisical

  • Add a new or existing identity provider and a new client ID and secret

  • Use client ID, secret, and KMS project ID

export INFISICAL_SITE_URL=<infisical_url>
export INFISICAL_UNIVERSAL_AUTH_CLIENT_ID=<client_id>
export INFISICAL_UNIVERSAL_AUTH_CLIENT_SECRET=<client_secret>		     export INFISICAL_PROJECT_ID=<kms_project_id>

Install Cosign

curl -O -L "https://github.com/sigstore/cosign/releases/latest/download/cosign-linux-amd64"
sudo mv cosign-linux-amd64 /usr/local/bin/cosign
sudo chmod +x /usr/local/bin/cosign
cosign version

Install the Cosign Infisical plugin

Make sure Go is installed
sudo apt update
sudo apt install -y golang-go
go version   # confirm it's installed

Clone and build the plugin

git clone https://github.com/Infisical/sigstore-kms-infisical.git
cd sigstore-kms-infisical
go build -o sigstore-kms-infisical

Install it into your PATH

sudo cp sigstore-kms-infisical /usr/local/bin/
sigstore-kms-infisical --help   # sanity check it's discoverable

Generate the Cosign public key

cosign generate-key-pair --kms infisical://cosign-signing-key

If the latest command is successful, you should see the key in Infisical.


Image 1 - Cosign key in Infisical
Image 1 - Cosign key in Infisical

Sign Docker image

After we set everything up, the latest step will be to sign Docker images after we build them. When signing with Cosign, we should always use the Docker image digest, not the image tag. This is because image tags can be overwritten, whereas the digest is always unique.

We are signing images with this command:

cosign sign --key "infisical://cosign-signing-key" --yes "${ECR_IMAGE_REPO}@${IMAGE_DIGEST}"

Where ECR_IMAGE_REPO is the URL to your Docker image registry (ECR in my case), and IMAGE_DIGEST is the actual digest, which can be fetched with:

DIGEST=$(aws ecr describe-images --repository-name "$ECR_REPO_NAME" --image-ids imageTag="$IMAGE_TAG" --region $AWS_REGION --query 'imageDetails[0].imageDigest' --output text)

The signing process should be part of your CI-CD tool, so this can be automated from the GitLab jobs, GitHub actions etc.


After successfully signing, you will see a new artifact in your ECR repository.

Image 2 - signed image artifact
Image 2 - signed image artifact

This is just the first part of the puzzle; after you start successfully signing your images, you will need additional application like Kyverno, which can allow only signed images inside your cluster. This is a Kyverno policy example:

apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
  name: verify-image
  annotations:
    policies.kyverno.io/title: Verify Image
    policies.kyverno.io/category: Software Supply Chain Security, EKS Best Practices
    policies.kyverno.io/severity: medium
    policies.kyverno.io/subject: Pod
    policies.kyverno.io/minversion: 1.7.0
    policies.kyverno.io/description: Using the Cosign project, OCI images may be signed to ensure supply chain security is maintained. Those signatures can be verified before pulling into a cluster. This policy checks the signature of an image repo called ghcr.io/kyverno/test-verify-image to ensure it has been signed by verifying its signature against the provided public key. This policy serves as an illustration for how to configure a similar rule and will require replacing with your image(s) and keys.
spec:
  validationFailureAction: Enforce
  background: false
  rules:
    - name: verify-image
      match:
        any:
          - resources:
              kinds:
                - Pod
      verifyImages:
        - imageReferences:
            - ghcr.io/kyverno/test-verify-image*
          mutateDigest: true
          attestors:
            - entries:
                - keys:
                    publicKeys: |
                      -----BEGIN PUBLIC KEY-----                  	MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE8nXRh950IZbRj8Ra/N9sbqOPZrfM                      5/KAQN0/KjHcorm/J5yctVd7iEcnessRQjU917hmKO6JWVGHpDguIyakZA==
                      -----END PUBLIC KEY-----

Signing your images shouldn't be optional; it should be the default implementation in your cluster...


 
 
 

Comments


Ebisoft
bottom of page