Caleb Woodbine's blog
âĒ Back
đ Sign, Verify and Trust with Cosign
Can you prove that your project's artifacts were built by a trusted authority? Do you have assurance in the supply chain security of your project's artifacts?
An important piece of the this puzzle is container image and artifact signing and verification.
cosign
is a tool from the sigstore project for signing and verifying blobs and container images, in an easy and simple way.
đ Signing your artifacts
cosign
supports three types of keys
- key-pair
- key-pair in KMS
- OIDC
There may by different reasons for why a particular type of key is needed for a usecase.
Key-pairs mean that a public and private key will need to be stored and tracked for usage.
The use of a KMS (key management system) is the same as key-pairs, except the storage of it is managed externally.
OIDC means for an ephemeral key, used only for that signing instance.
đ Using key-pairs
Key-pairs are generated with the following command
cosign generate-key-pair
resulting in cosign.pub
and cosign.key
files.
A container image is able to be signed then with the following command
cosign sign --key cosign.key IMAGE
and verified with
cosign verify --key cosign.pub IMAGE
A blobs (any file) is able to be signed with the following
cosign sign-blob --key cosign.key --bundle FILE.bundle FILE
and verified with
cosign verify-blob --key cosign.pub --bundle FILE.bundle FILE
đĒĒ Using OIDC
OIDC allows for the use of identites to sign resources, supported providers include
- GitHub
- Microsoft
- GitLab
Locally, I use the GitHub provider but in a CI I use either the GitLab or GitHub provider.
To sign with OIDC, use the following command
cosign sign IMAGE
and a page launches on your local web browser for choosing a provider to use your identity to sign the resource.
an image can be verified with a similar command to the following
cosign verify \
--certificate-identity-regexp 'https://gitlab.com/BobyMCbobs/.*//.gitlab-ci.yml@(refs/heads/main|refs/tags/.*)' \
--certificate-oidc-issuer-regexp 'https://gitlab.com' \
-o text \
IMAGE
or if you don't know the expected identity+issuer just yet, you may like to use
cosign verify \
--certificate-identity-regexp '.*' \
--certificate-oidc-issuer-regexp '.*' \
-o text \
IMAGE
đ How I use it in production
In GitLab CI it might look something like this for a Go project
stages:
- build
build:
image: docker.io/golang:1.21.6-alpine3.19@sha256:a6a7f1fcf12f5efa9e04b1e75020931a616cd707f14f62ab5262bfbe109aa84a
id_tokens:
SIGSTORE_ID_TOKEN:
aud: "sigstore" # NOTE: important for enabling OIDC
before_script:
- echo 'https://dl-cdn.alpinelinux.org/alpine/edge/testing' | tee -a /etc/apk/repositories
- apk add --no-cache ko cosign git
- ko login "${CI_REGISTRY}" -u "${CI_REGISTRY_USER}" -p "${CI_REGISTRY_PASSWORD}"
- export KO_DOCKER_REPO="${CI_REGISTRY,,}"
script:
- IMAGE=$(ko build .)
- cosign sign --yes "$IMAGE"
(docs.gitlab.com/ee/ci/yaml/signing_examples.html)
or in GitHub Actions, like this
name: build
on:
push: {}
permissions:
contents: read
id-token: write # NOTE: important for enabling OIDC
packages: write
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@3df4ab11eba7bda6032a0b82a6bb43b11571feac # v4.0.0
- uses: actions/setup-go@93397bea11091df50f3d7e59dc26a7711a8bcfbe # v4.1.0
with:
go-version-file: go.mod
- uses: ko-build/setup-ko@ace48d793556083a76f1e3e6068850c1f4a369aa # v0.6
- uses: sigstore/cosign-installer@11086d25041f77fe8fe7b9ea4e48e3b9192b8f19 # v3.1.2
- name: build
env:
KO_DOCKER_REPO: ghcr.io/${{ github.repository }}
run: |
export KO_DOCKER_REPO="${KO_DOCKER_REPO,,}"
IMAGE=$(ko build .)
cosign sign --yes "$IMAGE"
(github.com/marketplace/actions/cosign-installer)
and in my production clusters I use sigstore's policy-controller, with policies like this
apiVersion: policy.sigstore.dev/v1alpha1
kind: ClusterImagePolicy
metadata:
name: registry-gitlab-com-bobymcbobs-is-signed
spec:
images:
- glob: "registry.gitlab.com/bobymcbobs/**"
authorities:
- keyless:
identities:
- issuer: https://gitlab.com
subjectRegExp: "https://gitlab.com/BobyMCbobs/.*//.gitlab-ci.yml@refs/heads/main"
which requires workloads to have signed images for anything that is from my GitLab registry namespace.
Or like this one to require Knative images to be signed
apiVersion: policy.sigstore.dev/v1beta1
kind: ClusterImagePolicy
metadata:
name: knative-signed
spec:
images:
- glob: gcr.io/knative-releases/**
authorities:
- keyless:
url: https://fulcio.sigstore.dev
identities:
- issuer: https://accounts.google.com
subject: signer@knative-releases.iam.gserviceaccount.com
ctlog:
url: https://rekor.sigstore.dev
(original author Chainguard: github.com/chainguard-dev/policy-catalog/âĻ/policies/sigstore-landscape/knative-signed.yaml)
đ Other cool things
- Sigstore is publicly auditable and witnessable
- designed around ease of use and security (sigstore.dev/âĻ/threat-model)
- see the secure software supply chain artifacts with
cosign tree IMAGE
đĨ Who's using Sigstore and Cosign?
and many many others!
I personally use it anytime I need to publish an artifact, such as the container image for this website.
⨠Closing
With the ever-increasing importance of securing a project's supply chain, it's really helpful how easy it is to implement cosign
in artifact release and verification. Many large Open Source projects, such as ones hosted by the CNCF have adopted it, providing users with a level of safety and security when consuming their project's artifacts.
Check out the docs here: docs.sigstore.dev
If this post is interesting to you, perhaps you might like to also checkout my presentation for this topic here!
Thank you for reading this post and hope it helped you!