Generating SBOMs for .NET apps and NuGet packages with Microsoft.Sbom.Targets

How to use the Microsoft.SBOM.Targets NuGet package to produce a Software Bill of Materials (SBOM) during your release builds.

Software Bill of Materials, or SBOMs, are those files everyone wants, and no-one knows what to do with. Still, in the eventual hope that they get integrated into developer flow it's a good idea to produce them.

Whilst there's a bunch of third-party tooling, for example CycloneDX and Syft, a quick and easy option is the Microsoft SBOM tool. Each of these requires running .NET tools, or additions to your GitHub Actions workflow. What if you could skip changing your workflow and just do it when you compile?

The Microsoft SBOM tooling has an alternative mechanism, Microsoft.Sbom.Targets, installed via a NuGet dependency, which you can add to your project, or your DirectoryBuilds.Props file. Adding the dependency isn't enough to generate an SBOM, you must also set the GenerateSBOM in your project or props file.

<PropertyGroup>
    <GenerateSBOM>true</GenerateSBOM>
</PropertyGroup>

An MSBuild snippet showing setting the GenerateSBOM property to true.

Generating the SBOM does increase your build time a lot, so rather than run it all the time, you should include it and use it only when you produce release builds, as the MSBuild snippet below illustrates. Don't forget to check that version number and use the latest version.

<Project>
  <!-- The rest of your project file or Directory.Build.Props file --->

  <Choose>
    <When Condition="'$(Configuration)' == 'Release'">
      <PropertyGroup>
        <GenerateSBOM>true</GenerateSBOM>
      </PropertyGroup>
      <ItemGroup>
        <PackageReference 
            Include="Microsoft.Sbom.Targets" 
            Version="4.1.4" 
            PrivateAssets="All" />
      </ItemGroup>
    </When>
  </Choose>
</Project>

An MSBuild snippet to include SBOM generation in your .NET Builds

You can see it in use in, for example, my password generator project.

Now once you build a release build two files will land alongside your project output, the SBOM spdx.json and the SBOM signature .spdx.json.sha256. The spdx file is a much more reliable way to examine dependencies than trying to parse deps.json.

If you're building NuGet packages when you dotnet pack they'll also be embedded inside your nupkg as part of a _manifest directory, which you can see via NuGet Explorer.

I do adjust my GitHub Actions workflows a little, to extract the SBOMs from any nupkg I produce, and place them alongside the nupkgs as part of the build stage assets, so I can see they've been produced without having to pop open the nupkgs. For example,

    - name: 'Extract SBOMs'
      shell: pwsh
      run: > 
        Get-ChildItem -Path ${env:OUTPUT_DIRECTORY} -Filter *.nupkg -Force | ForEach-Object { 
          Expand-Archive $_.FullName "$($_.DirectoryName)/$($_.Basename)" -Force 
          Copy-Item "$($_.DirectoryName)/$($_.Basename)/_manifest/spdx_2.2/manifest.spdx.json" -Destination "${env:OUTPUT_DIRECTORY}/$($_.Basename).spdx.json"
          Copy-Item "$($_.DirectoryName)/$($_.Basename)/_manifest/spdx_2.2/manifest.spdx.json.sha256" -Destination "${env:OUTPUT_DIRECTORY}/$($_.Basename).spdx.json.sha256"
          Remove-Item "$($_.DirectoryName)/$($_.Basename)" -Force -Recurse }

Using PowerShell in GitHub Actions to extract SBOMs from nupkgs

I have asked for nuget.org to highlight packages with embedded SBOMs, it's on their backlog as is tooling to extract them. As an aside, if you're not saying SBOM with the voice of Tom Jones in your head you're doing it wrong.

Subscribe to Ramblings from a .NET Security PM

Don’t miss out on the latest issues. Sign up now to get access to the library of members-only issues.
jamie@example.com
Subscribe