Viewing and verifying SBOMs of the Stackable Data Platform

With release 24.3 of SDP, we started providing SBOMs (Software Bill of Materials) for our container images. Please note that they currently are in a draft stage and we are continually working on improving them. As a first step, we aim to provide a list of all primary (top level) components and their versions included in each container image. Our SBOMs follow the CycloneDX standard and are available in JSON format.

You can browse through our SBOMs at https://sboms.stackable.tech/.

You will find a simple hierarchical structure, one directory per release, containing a list of all container images included in that release. For each container image, one SBOM per version of the image is listed.

This page is a simple wrapper on top of the Stackable OCI registry, where the SBOMs are attached as signed attestations to the container images. When you click on a link in the SBOM browser, the SBOM is validated, extracted from the container registry, and then downloaded to your device. The next step of this tutorial explains the single steps happening under the hood when a link is clicked, and how to do them manually.

Verifying and extracting an SBOM manually with cosign

To verify and extract the SBOM, a tool called cosign is needed. Please have a look at the installation instructions in the cosign documentation and choose your preferred installation method. Additionally, jq is used to parse the JSON output of cosign.

With the following chain of commands, the SBOM of airflow-operator version 24.3.0 is verified and extracted:

cosign verify-attestation --type cyclonedx \
--certificate-identity-regexp \
'^https://github.com/stackabletech/.+/.github/workflows/.+@.+' \
--certificate-oidc-issuer https://token.actions.githubusercontent.com \
docker.stackable.tech/stackable/airflow-operator:24.3.0 \
| jq '.payload' -r | base64 -d | jq '.predicate'
For simplicity, the tag 24.3.0 is used here to refer to the image. In a real scenario, we recommend to use the digest (airflow-operator@sha256:…​) instead, to ensure you’re pulling the SBOM for the exact image you’re interested in.

Explanation of the commands and parameters:

The --type parameter specifies the type of the predicate, in this case cyclonedx for CycloneDX SBOMs. The --certificate-identity-regexp parameter specifies a regular expression that is used to match the identity of the signer of the attestation. In this case, that means: The attestation must be signed by a GitHub Actions workflow run by the stackabletech organization (the identity). Now, because in general anyone could claim to be a stackabletech workflow run, the --certificate-oidc-issuer parameter ensures that this identity was actually verified by GitHub. If the identity of the signer matches, you can be sure the contents of the attestation are authentic and were created by one of Stackable’s Github Action Workflows. cosign verify-attestation then prints the signed attestation to stdout, which is an in-toto attestation wrapped in a DSSE. The next command (jq '.payload') gets the payload of the envelope, which is the base64 encoded attestation. base64 -d decodes it and returns the attestation in JSON format. The attestation has a subject attribute, which provides information about the container image the SBOM belongs to. predicate is the actual SBOM, which is extrated by the jq '.predicate' command and then printed to stdout in JSON format.

cosign also prints information to stderr, which can be used to determine further information on the verification results and the exact Github Action workflow that was used to create this attestation.

You can now be sure that the SBOM was attested to the container image you’re interested in by a Stackable Github Action workflow, it’s even possible to look at the workflow to see how exactly this happened.

Enabling automatic verification of SBOMs

Similar to our image signature verification tutorial, it’s possible to enforce that only container images with SBOMs that are signed by Stackable are allowed to run in your cluster. Sigstore’s Policy Controller can be used to achieve this.

Releases prior to SDP 24.3 do not have signed SBOMs. If you are using an older release and enforce SBOM verification, Pods with Stackable images will be prevented from starting.

Installing the Policy Controller

Install the Policy Controller via Helm:

helm repo add sigstore https://sigstore.github.io/helm-charts
helm repo update
helm install policy-controller sigstore/policy-controller

The default settings might not be appropriate for your environment, please refer to the configurable values for the Helm chart for more information.

Creating a policy to verify SBOMs

Now that the Policy Controller is installed, you can create a policy that verifies that all images provided by Stackable have an SBOM attached that is signed by Stackable’s CI pipeline (Github Actions):

apiVersion: policy.sigstore.dev/v1alpha1
kind: ClusterImagePolicy
metadata:
  name: stackable-image-has-signed-sbom
spec:
  images:
    - glob: "**.stackable.tech/**"
  authorities:
    - keyless:
        url: https://fulcio.sigstore.dev
        identities:
          - issuer: https://token.actions.githubusercontent.com
            subjectRegExp: "https://github.com/stackabletech/.+/.github/workflows/build.yml@refs.+"
      ctlog:
        url: https://rekor.sigstore.dev
      attestations:
        - name: must-have-cyclonedx-attestation
          predicateType: https://cyclonedx.org/bom
          policy:
            type: cue
            data: |
              predicateType: "https://cyclonedx.org/bom"

Apply this policy to the cluster by saving it as stackable-sbom-policy.yaml and running:

kubectl apply -f stackable-sbom-policy.yaml

If you used the default values for the Helm chart, policies will only be applied to namespaces labeled with policy.sigstore.dev/include: "true". Add a label for the namespace where you deployed SDP:

kubectl label namespace stackable policy.sigstore.dev/include=true

The Policy Controller checks all newly created Pods in this namespace that run any image matching **.stackable.tech/** (this matches images provided by Stackable) and ensures that these images have an attested SBOM that’s been signed by a Stackable Github Action. If no SBOM is present or its signature is invalid or missing, the policy will deny the pod creation. For a more detailed explanation of the policy options, please refer to the Sigstore documentation.