Besides a few blogposts on my employer’s blog, I haven’t blogged in a long time. My last post on here was over 4 years ago. I plan to start again and lower the bar of entry and am forcing myself to have less polished posts to be published and be okay with it.
For some time I have been very interested in the Software Supply Chain Security space. It reminds me a bit of the early days of Kubernetes, where new tools were popping up almost every week. I have been following closely what is happening with SLSA and Sigstore. Over the weekend I have been toying a bit with GitHub Actions and securing the supply chain with tools out of that space.
I used a simple ‘Hello World’ nodeJS application that I can build with a Dockerfile and get the container image build. I also generate the SBOM and provenance and sign all the artefacts with
cosign. I followed the steps as described in the blogpost of Marco Franssen but made some tweaks to fit my workflow. The changes I made are:
This was a great introduction to how all the tools fit together and can be used in your CI pipeline. The full pipeline I created can be found on my GitHub. Creation of all of the attestations in the CI pipeline is not enough, unless you actually use them, this is where the next step of my investigation took me.
As the image has been signed through the GitHub Actions workload identity and uses keyless signatures, the image signature can be verified in the following way:
This tells us that my GitHub action has signed the image and also contains information/metadata on the environment it has run in.
One of the things I investigated during the whole exercise was how to upload the SBOM and provenance data to my OCI registry.
cosign has an
attest command generates a tag in the OCI registry formatted as
<image name>:<sha256-string>.att and can have multiple layers to store all your attestations. In the example pipeline I created, it stores the SBOM and provenance in the
The advantage of the
attest command over
sign is that you end up with fewer tags and the uploading & signing happens in one step. When you do
sign, you would create 2 tags, 1 for the material (e.g. SBOM file) and 1 for the signing information. The disadvantage of the
attest command is that it is a bit harder to get the necessary information out. If you want to extract the SBOM file from my attestation, you need to run the following command:
COSIGN_EXPERIMENTAL=1 cosign verify-attestation mattiasgees/s3c-demo:main --type spdxjson | jq '.payload |= @base64d | .payload | fromjson | select(.predicateType == "https://spdx.dev/Document") | .predicate.Data' > sbom-spdx.json
When you use
cosign attach, you can use
cosign download to get the SBOM, which is easier. Based on talking to a few people, it seems the community is mostly standardising on
crane copy and
cosign copy will not only copy your container images from one OCI registry to another but also all of its associated tags (signatures, attestations). No more retagging of container images needed.
The last thing I did as part of my experiment is to enforce signatures on my Kubernetes Cluster. I deployed the Sigstore Policy Controller into my Kubernetes and enforced a simple policy where it checks if the container image comes from the GitHub action.
apiVersion: policy.sigstore.dev/v1beta1 kind: ClusterImagePolicy metadata: name: image-policy spec: images: - glob: "**" authorities: - keyless: # Signed by the public Fulcio certificate authority url: https://fulcio.sigstore.dev identities: # Matches the Github Actions OIDC issuer - issuer: https://token.actions.githubusercontent.com # Matches a specific github workflow on main branch. Here we use the # sigstore policy controller example testing workflow as an example. subject: "https://github.com/MattiasGees/S3C-demo/.github/workflows/build.yml@refs/heads/main"
Sigstore Policy controller can do a lot more complex scenarios as well where it can match if specific data is available in your SBOM, Provenance or any other attestation type. I plan to do further experimenting and blog on this in a subsequent blogpost
This blogpost only scratched the surface of the possibilities that can be done when you combine a lot of powerful tools like cosign, syft, policy controllers, and OCI registries. I am continuing my research in this space and plan to publish more of my thoughts and experiments in the near future.