SEANK.H.LIAO

cosign in cloudbuild

signing the things you wanted

signing container images

Sigstore's cosign is the new, widely supported way of signing container images.

Of particular interest is the keyless OpenID signing flow: it proves a time-constrained signing identity, vs an unconstrained signing identity you usually get with static / long-lived keys.

cloudbuild

To use it in cloudbuild:

 1steps:
 2  - id: sign
 3    name: "gcr.io/projectsigstore/cosign"
 4    entrypoint: sh
 5    env:
 6      - "TUF_ROOT=/tmp" # cosign tries to create $HOME/.sigstore
 7      - "COSIGN_EXPERIMENTAL=1"
 8      - "GOOGLE_SERVICE_ACCOUNT_NAME=cosign-signer@com-seankhliao.iam.gserviceaccount.com"
 9    args:
10      - "-c"
11      - "cosign sign gcr.io/project/image@sha256:..."

The cosign container runs as non root, so it doesn't have permission to create $HOME/.sigstore and it dies. Setting TUF_ROOT changes where it tries to do that.

digests

Container registries are a big pile of global shared state, and if you push a tag such as :latest and later refer to them, it might not be the same thing (if someone else pushed something called :latest in between). Thankfully, registries are also content addressable using digests, looking something like sha256:..... How do you get one?

docker

docker is not very helpful, docker build --iidfile outputs a file with sha256:.... but that's for the image's "local configuration". Apparently the only reliable way is to push the image to a v2 registry, and then a manifest will be generated, and you can get a digest for that.

kaniko

kaniko is much better, providing flags such as: --digest-file, --image-name-with-digest-file, --image-name-tag-with-digest-file outputting files onto the local system which contain digests (optionally with image names), one per line.

So with cosign, the invocation becomes (assuming --image-name-with-digest-file=.image.txt):

1args:
2  - "-c"
3  - "cosign sign $(head -n 1 .image.txt)"