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 versionInstall the Cosign Infisical plugin
Make sure Go is installed
sudo apt update
sudo apt install -y golang-go
go version # confirm it's installedClone and build the plugin
git clone https://github.com/Infisical/sigstore-kms-infisical.git
cd sigstore-kms-infisical
go build -o sigstore-kms-infisicalInstall it into your PATH
sudo cp sigstore-kms-infisical /usr/local/bin/
sigstore-kms-infisical --help # sanity check it's discoverableGenerate the Cosign public key
cosign generate-key-pair --kms infisical://cosign-signing-keyIf the latest command is successful, you should see the 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.

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-----



Comments