← Back to Blog

Generating SBOMs Remotely with a Hardware Root of Trust

The first step in understanding the attack surface of an application is to understand its makeup. This is typically done with a Software Bill of Materials (SBOM), generated from a tool like Syft as part of a build pipeline. The resultant SBOM can then be analyzed with a vulnerability scanning tool to determine all of the vulnerabilities that potentially exist within an application (some of those tools are better at reducing false positives).

The amount of confidence in that vulnerability report will come down to, among other things, the confidence in the authenticity of the SBOM. So, how can the authenticity of an SBOM be verified after it has left the build pipeline? To experiment with answers to this question, we built SBOM Server.

Generating an SBOM remotely with this tool provides some interesting properties:

  1. Integrity of SBOM server and its dependencies is cryptographically verified.
  2. Generation of the SBOM is isolated from a potentially compromised build pipeline.
  3. Provenance of the SBOM is tied to a strong root of trust.

Let’s explore how this is accomplished and how to verify these properties below.

SBOM Server

SBOM Server is a program which will generate an SBOM from an uploaded artifact, and wrap it within an in-toto attestation bundle. The attestation bundle proves the process by which the SBOM was generated, assuming a shared root of trust, in a verifiable manner — provenance (in fact, one of the attestations in the bundle is a SLSA Provenance). SBOM Server is only able to do this because it runs within an enclave — specifically, an AWS Nitro Enclave at the moment — created by Enclaver.

Enclaver helps to make it easy to build and run enclaves. Enclaves, as implemented on AWS, are locked-down instances — no access to network, disk, or most other peripherals — which only communicate with their parent instance through a vsock. They borrow, but critically do not share, the resources of their parent. There is no way for a instance to introspect, influence, or otherwise inject itself into an enclave; even if it is the parent.

SBOM Server uses the underlying Nitro Security Module (NSM) provided by the hypervisor to generate an attestation that is rooted to AWS, and this attestation forms the basis for trusting the other attestations within the in-toto bundle. The result is a server which can be categorized as SLSA Build L3, which means that it is considered to be a “hardened build platform that offers strong tamper protection”1. In practice, this means that a software artifact can be uploaded to a remote machine running SBOM Server, and the SBOM that is returned can be verified to be authentic.

We’ve set up a demo instance that you can try out. Download the client and try the following:

docker image save hello-world | \
    ./client --verbose --host sbom-server.demo.edgebit.io \
      sbom --attest docker-archive:-

This exports the “hello-world” container image from docker (this will need to be pulled with docker pull hello-world if it hasn’t already) and pipes it into the client, informing it of the format of the artifact in the last argument. It should look like this when run:

$ docker image save hello-world | \
    ./client --verbose --host sbom-server.demo.edgebit.io \
      sbom --attest docker-archive:-
 INFO  client > sbom-server-client: 0.2.0
 INFO  client > Sending artifact
 INFO  client > Receiving response
 INFO  client > Verifying attestation bundle
 DEBUG client > Verified enclave attestation certificate chain
 DEBUG client > Verified enclave image is known-good
 DEBUG client > Verified subject of SPDX Document matches uploaded artifact
 DEBUG client > Verified subject of SCAI Attribute Report matches payload of SPDX envelope
 DEBUG client > Verified signature on the SPDX envelope
 DEBUG client > Verified signature on the Provenance envelope
 DEBUG client > Verified server is using a hardened configuration
{
 "spdxVersion": "SPDX-2.3",
 "dataLicense": "CC0-1.0",
 "SPDXID": "SPDXRef-DOCUMENT",
 "name": "hello-world:latest.tar",
...

If you get a “502 Bad Gateway”, try again in a few seconds. The demo machine can only run a limited number of enclaves and each enclave can only handle a single request in order to be SLSA Build L3 (the server can be configured to handle multiple requests, but this lowers it to SLSA Build L2).

Verifying Authenticity

Digging a little deeper, how does the client verify the authenticity of the SBOM? The verbose logging provides a hint, but it makes for interesting blog content to go through the full process.

As mentioned earlier, the SBOM Server uses the AWS Nitro Attestation PKI as its root of trust. The attestation generated by the NSM is the first piece to verify, since it will provide the key to verifying the other attestations in the bundle. The SBOM Server client can be run with --no-verify to get it to defer verification to the user:

$ docker image save hello-world | \
    ./client --verbose --host sbom-server.demo.edgebit.io \
      sbom --attest --no-verify docker-archive:-
 INFO  client > sbom-server-client: 0.2.0
 INFO  client > Sending artifact
 INFO  client > Receiving response
{"payloadType":"application/vnd.in-toto+json","payload":"eyJfdHlwZSI6Imh0dHBzOi…
...

The NSM’s attestation is stored as an attribute within a Supply Chain Attribute Integrity (SCAI) report, which is the third attestation in the in-toto bundle:

$ docker image save hello-world | \
  ./client --host sbom-server.demo.edgebit.io \
    sbom --attest --no-verify docker-archive:- | \
  sed --quiet '3p' | \
  jq --raw-output .payload | \
  base64 --decode
 INFO  client > sbom-server-client: 0.2.0
 INFO  client > Sending artifact
 INFO  client > Receiving response
{
  "_type": "https://in-toto.io/Statement/v1",
  "subject": [{
    "name": "hello-world:latest.tar.spdx-envelope-payload.json",
    "digest": {
      "sha256": "c1f4ad82a8b1fd979bbfd105ba11168f27d470922e179011170b586aa2d4498e"
    }
  }],
  "predicateType": "https://in-toto.io/attestation/scai/attribute-report/v0.2",
  "predicate": {
    "attributes": [{
      "attribute": "VALID_ENCLAVE",
      "evidence": {
        "content": "hEShATgioFkQ7alpbW9kdWxlX2lkeCdpLTBiMTUxZDEwYzAxZTQ1YmQxLWV…
...

The NSM’s attestation can be extracted with the following series of commands and then inspected with a tool like Attestation Explorer:

docker image save hello-world | \
  ./client --host sbom-server.demo.edgebit.io \
    sbom --attest --no-verify docker-archive:- | \
  sed --quiet '3p' | \
  jq --raw-output .payload | \
  base64 --decode | \
  jq --raw-output '.predicate.attributes[0].evidence.content' | \
  base64 --decode > nsm-attestation.cbor

The Attestation Explorer determines that the attestation is valid by verifying the certificate chain and shows the chain, Platform Configuration Registers (PCRs), and a public key, among other information.

Screenshot of the attestation explorer, showing the NSM module ID, creation timestamp, and the first few entries of the certificate chain

The client uses the PCR values within the attestation to determine whether or not the server is running in a known configuration. PCR0 holds a digest of the entire enclave image — the kernel, SBOM Server and its configuration, Enclaver’s inner component, and any other userspace libraries and utilities — so if it’s a known-good value, the execution of the server can be trusted (assuming there are no exploits).

This attestation from the NSM is very trustworthy, but it only covers the contents of the enclave image; not its output. How can this be used to provide provenance for the SBOM that is generated?

Extending Trust

Within the enclave, SBOM Server generates an ephemeral key pair. The private half of this key pair, which is used for signing the generated SBOM and metadata about the build, never leaves the enclave and is lost when the process terminates — by default, after every request. The public half of the key pair is used to validate these signatures and is included in the server’s response; more precisely, it’s stored within the NSM’s attestation.

When a request is made to the NSM to generate an attestation, the caller is allowed to optionally provide a few extra pieces of information. This extra information — a public key, arbitrary user data, and a cryptographic nonce — is included in the attestation and is therefore covered by the same AWS Nitro Enclaves certificate chain. SBOM Server makes use of this to protect the public half of its ephemeral signing key, tying the generated SBOM and metadata into the same root of trust.

The client uses the public key from the nitro attestation to verify the signatures on the two other attestations within the bundle: the SLSA Provenance and the SBOM (in SPDX format). Both of these are signed with the ephemeral key mentioned above. If the signatures are valid, those documents and the enclave attestation must have been generated inside the same, authentic enclave. From there, the client then verifies that the uploaded artifact and downloaded response haven’t been altered in transit by looking at the metadata — also signed by the ephemeral key. If all of this checks out, it prints the SBOM to stdout and exits successfully.

Building Further

So what can we do with this ability to generate an SBOM in a verifiable manner? Aside from it potentially helping to reinforce and automate regulatory compliance, this can provide a greater degree of confidence in your vulnerability reports and overall understanding of risk. Knowing that the SBOM has not been tampered with before analysis removes one more potential attack vector on your infrastructure and your customers’ data. We’re experimenting with visualization of this chain of trust in our platform, though we don’t have anything further to announce at the moment:

Screenshot of a mockup of the EdgeBit Platform, showing an attestation chain of Release Build, Enclave, SBOM, and Workloads

Another avenue of possibility is to take what we’ve learned in this process and extend it to more of the build pipeline. In fact, this was the original intent of the SBOM Server — to act as a proving ground for doing more in an enclave. Similar techniques to the ones described above can be used to implement verifiable builders for arbitrary workflows; for example, compiling and linking a Rust project.

If you found the above interesting and would like to know more, please reach out to get in touch with the team. We’d love to hear more about your use cases and help improve your overall security posture.

Cut through the noise in vulnerability management

Less investigation toil.

More action on real issues.

Happy engineers.

Request Demo
Close Video