Contents

Hooking up Dependency Tracker, CDXGEN, and GitHub Actions

Contents

Another at work post…

So my focus for improving our security best practices and an upcoming audit has been looking at SBOM and vulnerability management. Part of this involved building out on some work carried out be a former colleague, said person had done some reviews of the tooling available for these 2 pieces. This review recommended using the tool Dependency Tracker, to process the SBOM from each project. From this we can then understand supply chain risk for our applications.

Because we’re a services and product organisation we have a large landscape of projects, ranging from the very small to fairly large. With a mixture of them being under active development or in a heritage state. Generally this means that have a range ages and tech stacks (which, yes isn’t the best), some of which we prefer to not start having to fully resurrect and would like a loosely coupled approach.

Sure we could use Dependabot, but this doesn’t really provide what we are looking for as an organisation.

So onto Dependency Tracker… This is a project that comes from OWASP so has had some serious security people involved in the writing of it. I’m not going to go into a detailed review, as I’d like to focus on the part that I have been working on recently.

DT consumes SBOM files in CycloneDX format, this is the OG of SBOM formats and has been joined by SPDX. Now interestingly it is super easy to get a SPDX SBOM out of GitHub… There are caveats around this, in that you have to convert it to CycloneDX to use in DT, and the tools to convert them seem to be not really mature, appear on the surface to be standoffish with the other formats, or that they are still finding their space in the market.

Oh! Joy! So this means it not as simple as just hoovering up the SPDX files from GitHub, converting them to CycloneDX, and then lobbing them at DT’s API to be consumed. Also, the SPDX file doesn’t contain all the details needed to generate a supply chain hierarchy, how annoying!

So to generate a CycloneDX SBOM that is not significantly compromised we can either use the language specific generator, or just use the cdxgen container which has all the dependencies for all the languages. The downside of this approach is that the container is MAHOOSIVE! Which means that it can eat CI credits on download time alone, but it does mean that you can have 1 tool to generate SBOMs for all the projects.

Great so we have the tool to generate the SBOM… Now how do we run it in CI? Well we’re able to use the .github project in GitHub to define an organisational work flow that can be referenced by projects.

name: Generate SBOM
run-name: Generate SBOM
on:
  workflow_call:
jobs:
  generate-upload-sbom:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout
        # Required to mount the GitHub Workspace to a volume
        uses: actions/checkout@v2
      - uses: addnab/docker-run-action@v3
        with:
          image: ghcr.io/cyclonedx/cdxgen:master
          options: |
            -v ${{ github.workspace }}:/app:rw
            -v /tmp:/tmp
            -t
            -e CDXGEN_DEBUG_MODE=debug
          run: |
            node /opt/cdxgen/bin/cdxgen.js
              -r /app -o /app/bom.json
      - name: Upload
        run: |
          curl -X 'POST' ${DT_URL}/api/v1/bom \
          -H 'accept: application/json' \
          -H 'Content-Type: multipart/form-data' \
          -H "X-API-Key: ${DT_API_KEY}" \
          -F projectName=${{ github.repository }} \
          -F autoCreate=true \
          -F bom=@bom.json
        env:
          # This is loaded as an organisation secret,
          # so does not need to be added for each work flow.
          DT_URL: ${{ vars.DT_URL }}
          DT_API_KEY: ${{ secrets.DT_API_KEY }}

Hold on that looks really simple… well yes it should be all we need to do is checkout, run cdxgen, and upload the SBOM to Dependency Tracker.

Then to reference this is the project we use:

name: CDXGEN
on:
  workflow_dispatch:
jobs:
  cdxgen:
    name: CDXGen
    uses: ***/.github/.github/workflows/run_cdx_gen.yml@main
    secrets: inherit

Again super simple… So in this case we’re only specifying that the work flow can be called manually. But this could be swapped out with a cron schedule, on a merge to branch, on a tag, or on the creation of a release.