Step 7 - Generating a SBOM

- Thomas Jungbauer Thomas Jungbauer ( Lastmod: 2024-07-02 ) - 3 min read

A software bill of materials (SBOM) offers an insight into the makeup of an application developed using third-party commercial tools and open-source software. It is a machine-readable, formally structured list of all components. This list is important to gain visibility into what risks might exist in a package and their potential impact. It allows to prioritize the risks and define a remediation path. The teams can use the SBOM to monitor all components that are used across an application.

We will create a Task that will generate a SBOM and uploads it into an SBOM repository.

Goals

The goals of this step are:

  • Install a SBOM repository.

  • Generate a SBOM and upload it to the repository.

Tool/Standard CycloneDX

OWASP CycloneDX is a full-stack Bill of Materials (BOM) standard that provides advanced supply chain capabilities for cyber risk reduction. The specification supports:

  1. Software Bill of Materials (SBOM)

  2. Software-as-a-Service Bill of Materials (SaaSBOM)

  3. Hardware Bill of Materials (HBOM)

  4. Operations Bill of Materials (OBOM)

  5. Vulnerability Disclosure Reports (VDR)

  6. Vulnerability Exploitability eXchange (VEX)

Strategic direction of the specification is managed by the CycloneDX Core Working Group, is backed by the OWASP Foundation, and is supported by the global information security community.

The CycloneDX module for Node.js creates a valid CycloneDX Software Bill-of-Materials (SBOM) containing an aggregate of all project dependencies. CycloneDX is a lightweight SBOM specification that is easily created, human and machine-readable, and simple to parse.

We will use this standard and will deploy a small Pod in our cluster to be able to upload our SBOM locally.

Install CycloneDX Repository Server

We can install a CycloneDX Repository Server, which is a simple Pod running in our cluster. You can use the following Argo CD application, which will create the Namespace (cyclonedx),Deployment, Route, and Service.

apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
  name: in-cluster-install-cyclonedx
  namespace: openshift-gitops
spec:
  destination:
    namespace: cyclonedx
    server: 'https://kubernetes.default.svc'
  info:
    - name: Description
      value: Install CycloneDX SBOM Repository
  project: in-cluster
  source:
    path: clusters/management-cluster/cyclonedx (1)
    repoURL: 'https://github.com/tjungbauer/openshift-clusterconfig-gitops'
    targetRevision: main
1Path and URL to the Git repository.

In Argo CD the following Application will be created:

CycloneDX Installation
Figure 1. CycloneDX Installation

Update the Tekton Pipeline

  1. Update the TriggerBinding globex-ui and add the following:

        - name: cyclonedxHostUrl
          value: >-
            https://cyclonedx-bom-repo-server-cyclonedx.apps.ocp.aws.ispworld.at (1)
    1DO NOT add a trailing slash here.
  2. Update the TriggerTemplate and add the following to the appropriate blocks:

    spec:
      parames:
        ...
        - description: Cyclonedx host url
          name: cyclonedxHostUrl (1)
      resourcetemplates:
        ...
        spec:
          params:
            ...
              - name: CYCLONEDX_HOST_URL
                value: $(tt.params.cyclonedxHostUrl) (2)
    1The parameter defined in the TriggerBinding
    2The parameter as it will be provided to the Pipeline.
  3. Install the following Task

    apiVersion: tekton.dev/v1beta1
    kind: Task
    metadata:
      name: generate-sbom
      namespace: ci
    spec:
      params: (1)
        - default: >-
            https://cyclonedx-bom-repo-server-cyclonedx.apps.placeholder.com/
          name: cyclonedxHostUrl
          type: string
        - default: 'cyclonedx/cyclonedx-node'
          name: cycloneDXnodeImage
          type: string
      results:
        - description: The url location of the generate SBOM
          name: sbomUrl
          type: string
      steps:
        - image: $(params.cycloneDXnodeImage)
          name: generate-sbom
          resources:
            requests:
              memory: 1Gi
          script: > (2)
            apk add git curl
    
            npm install .
    
            /usr/src/cyclonedx-bom/bin/make-bom.js -o bom.xml
    
            curl -v -k $(params.cyclonedxHostUrl)/v1/bom -H "Content-Type:
            application/vnd.cyclonedx+xml; version=1.4" -H "Accept: */*" -d @bom.xml
            -D /tmp/header.txt
    
            LOCATION=$(cat /tmp/header.txt | grep location: | awk '{print $2}' | sed
            's|http:|https:|g')
    
            printf "%s" "$LOCATION" > "$(results.sbomUrl.path)"
    
            echo "SBOM URL accessible on Results of TaskRun $(context.taskRun.name)"
          workingDir: /workspace/repository
      workspaces:
        - name: repository
    1Default parameters for this task. Might be overwritten, by the EventListener
    2Script to be executed. It will download a script and upload the SBOM to our CycloneDX server.
  4. Update the Pipeline object

    spec:
      params:
        ...
        - name: CYCLONEDX_HOST_URL (1)
          type: string
      tasks:
      ...
        - name: generate-sbom (2)
          params:
            - name: cyclonedxHostUrl
              value: $(params.CYCLONEDX_HOST_URL)
          runAfter:
            - build-sign-image (3)
          taskRef:
            kind: Task
            name: generate-sbom
          workspaces:
            - name: repository
              workspace: shared-data
    1Add this to the parameter section
    2The new Task to generate a SBOM
    3Run after build-sign-image (and in parallel to the ACS tasks)
Pipeline
Figure 2. Pipeline

Execute the Pipeline

Let’s trigger the pipeline again. If everything works well, the URL to the uploaded SBOM will be visible in the TaskRun log.

Pipeline
Figure 3. Pipeline

When you open this URL, you will get a huge list of components end dependencies.

For example, the following snippet shows that the angular component animations (version 13.2.6) is used.

<components>
  <component type="library" bom-ref="pkg:npm/%40angular/animations@13.2.6">
  <author>angular</author>
  <group>@angular</group>
  <name>animations</name>
  <version>13.2.6</version>
  <description>Angular - animations integration with web-animations</description>
  <licenses>
    <license>
      <id>MIT</id>
    </license>
  </licenses>
  <purl>pkg:npm/%40angular/animations@13.2.6</purl>
  <externalReferences>
    <reference type="website">
      <url>https://github.com/angular/angular#readme</url>
    </reference>
    <reference type="issue-tracker">
      <url>https://github.com/angular/angular/issues</url>
    </reference>
    <reference type="vcs">
      <url>git+https://github.com/angular/angular.git</url>
    </reference>
  </externalReferences>
</component>

Summary

This concludes our security scans for the whole build process. With the SBOM you have now a complete list of components and dependencies of your images.

During the next steps, we will work with the Kubernetes manifests and update them, perform a linting on these manifests, and try to deploy the updated image to our DEV environment.