Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow platforms to provide run image sboms #211

Closed
wants to merge 12 commits into from
128 changes: 128 additions & 0 deletions text/0000-run-image-sbom.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,128 @@
# Meta
[meta]: #meta
- Name: Run Image SBOM
- Start Date: 2022-03-09
- Author(s): natalieparellano
- Status: Draft <!-- Acceptable values: Draft, Approved, On Hold, Superseded -->
- RFC Pull Request: (leave blank)
- CNB Pull Request: (leave blank)
- CNB Issue: (leave blank)
- Supersedes: https://github.com/buildpacks/rfcs/pull/186

# Summary
[summary]: #summary

This RFC proposes a mechanism for platforms, when running builds, to provide an sbom for the run image that will be included in the final app image.

# Definitions
[definitions]: #definitions

- Run Image: A container image that serves as a base image for application images in the buildpack toolchain.
- SBOM (Software Bill Of Materials) / BOM: A list of components in a piece of software. Software vendors often create products by assembling open source and commercial software components. The SBOM describes the components in a product. In case of buildpacks the SBOM describes the contents of the various layers, buildpacks, base images and the output app container.
- Attestation: authenticated metadata about one or more software artifacts, as per the SLSA Attestation Model (see [here](https://github.com/in-toto/attestation) and [here](https://github.com/sigstore/cosign#in-toto-attestations)).
- Cosign sbom attachment: an sbom object represented as an OCI Image Manifest V1 (see [here](https://github.com/sigstore/cosign/blob/main/specs/SBOM_SPEC.md)).

# Motivation
[motivation]: #motivation

This RFC serves as an addendum to [#RFC 95: Structured SBOMs](https://github.com/buildpacks/rfcs/blob/main/text/0095-sbom.md), which introduced a structured way for buildpacks to provide an sbom for dependencies installed at build time. For a full depiction of dependencies within a container image, container scanning tools would _also_ need an sbom for OS packages that were installed on the run image when it was created.

# What it is
natalieparellano marked this conversation as resolved.
Show resolved Hide resolved
[what-it-is]: #what-it-is
natalieparellano marked this conversation as resolved.
Show resolved Hide resolved

This RFC proposes a mechanism for platforms to supply the SBOM for a run image at build time, leaving the method of storing and associating the SBOM to the run image unspec'd. The lifecycle would ingest the provided SBOM and place it in a spec'd location in the final app image. A label would be used to designate the layer containing the SBOM for the run image.

- Define the target persona: platform operator, platform implementor, end user.
- If applicable, provide sample error messages, deprecation warnings, or migration guidance.
- The lifecycle could warn if a usable run image sbom is not provided.

Example invocation:
* build: `/cnb/lifecycle/exporter -run-image my-run-image -run-image-sbom <path or directory - e.g., ./my-run-image-sbom.cdx.json> my-app-image`
* rebase: `/cnb/lifecycle/rebaser -run-image my-new-run-image -run-image-sbom <path or directory - e.g., ./my-new-run-image-sbom.cdx.json> my-app-image`

# How it Works
[how-it-works]: #how-it-works

## Build

Following the build invocation above, the exported app image would contain:
* `my-run-image-sbom.cdx.json` at `/layers/sbom/launch/base-image/sbom.cdx.json`. Note that this would make `base-image` a reserved buildpack ID.

* An `io.buildpacks.base.sbom` label containing the diffID of the layer containing the run image SBOM.

The accepted SBOM media types would be:
* `application/vnd.cyclonedx+json` for files with extension `cdx.json`
* `application/spdx+json` for files with extension `spdx.json`
* `application/vnd.syft+json` for files with extension `syft.json`

If `-run-image-sbom` is provided as a file:
* The lifecycle will ensure that the file has a supported extension

If `-run-image-sbom` is provided as a directory:
* The lifecycle will ensure that all files within the directory have supported extensions

## Buildpack-provided SBOMs

SBOM files output by buildpacks are currently exported in `/layers/sbom/launch/<buildpack id>`. The layer containing the buildpack-provided SBOM files is referenced in the `io.buildpacks.lifecycle.metadata` label with key `sbom`. For parity with `io.buildpacks.base.sbom`, a `io.buildpacks.app.sbom` label will also be added.
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggestion: there should be criteria for what gets included in the io.buildpacks.lifecycle.metadata label.


## Rebase

Following the rebase invocation above, the exported app image would contain:
* `my-new-run-image-sbom.cdx.json` at `/layers/sbom/launch/base-image/sbom.cdx.json`
* The layer containing the old run image sbom would be removed
* The `io.buildpacks.base.sbom` label would be updated to contain the diffID of the layer containing the new run image sbom

## When a run image has an sbom baked in

A platform could provide a run image that already has an sbom baked in - i.e., has a layer containing an sbom that is advertised in `io.buildpacks.base.sbom`. In this case, the lifecycle could just do nothing, and the final app image would contain an sbom in the expected location with the expected label. This (as in #186) runs the risk that the sbom baked into the run image has fallen out of date.

If a platform provided a run image with a baked in sbom and also supplied the `-run-image-sbom` argument, the lifecycle could replace the baked in sbom with the new sbom, much like rebase.

## With Dockerfiles

https://github.com/buildpacks/rfcs/pull/173 proposes allowing the run image to be extended or swapped using Dockerfiles. There are a few scenarios that could occur:
* The run image is extended - the lifecycle would need to run a `genpkgs` executable after Dockerfiles have been applied. The result of this invocation would replace the `io.buildpacks.base.sbom` label on the extended run image. In this scenario, the build would proceed according to the process outlined in "When a run image has an sbom baked in".
* The run image is swapped for a new run image that already has a `io.buildpacks.base.sbom` label. In this scenario, the lifecycle would NOT run `genpkgs`, and the build would proceed according to the process outlined in "When a run image has an sbom baked in".
* The run image is swapped for a new run image that does not have a `io.buildpacks.base.sbom` label. In this scenario, there are a couple things that could occur:
* The lifecycle could run `genpkgs` to produce a run image sbom for use during export
* The lifecycle could return the new run image reference to the platform, expecting the platform to locate an sbom

## With pack

`pack` could make use of the preparer binary described below to download a run image sbom prior to running the exporter. When Dockerfiles are supported, the preparer invocation would need to happen after the `extender` has run to cover the case where a new run image is selected.

# Drawbacks
[drawbacks]: #drawbacks

Why should we *not* do this? Leaving the location of the run image sbom unspec'd (as opposed to baking it into the run image at a specific location) could make it harder for logic-less platforms like Tekton to use the creator.

## preparer binary
* A possible mitigation to the drawback noted above would be a CNB-provided "prepare" operation ([currently under discussion](https://github.com/buildpacks/rfcs/pull/202)). For example, a preparer could look for a run image sbom in a file, attestation, attachment, or layer (picking the first one it finds) and provide the data as a file to the creator. The Tekton task that uses the creator currently already has a ["prepare" step](https://github.com/tektoncd/catalog/blob/4bf8b57aa105f0c7ce05fc122a11b1b0d5822fcd/task/buildpacks/0.3/buildpacks.yaml#L70-L121) which could be modified to invoke a preparer binary.

# Alternatives
[alternatives]: #alternatives
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wasn't there an alternative discussed where we would leave it up to the platform to determine the method of attaching an sbom? For instance, if our platform want to use more of an associative artifact (similar to cosign) we could do that. It seems like this RFC only proposes one of what I see possibly being many ways for platforms to want to add this feature. Would it be better if we spec'd out the possible options and a way for further tools to be able to discover how the run image sbom is attached to the app image?

For example, some label that states a) "it's this layer here", or b) "it's located at this URI".

Copy link
Member Author

@natalieparellano natalieparellano Mar 24, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think there are two problems to solve here - one is how to attach or associate an SBOM with the run image. The other is how to attach or associate a run image SBOM with a CNB-built app image. This RFC is essentially saying we shouldn't worry about the first issue. As for the second issue, this RFC proposes staying consistent with the pattern introduced in https://github.com/buildpacks/rfcs/blob/main/text/0095-sbom.md and put the run image sbom somewhere in /layers/sbom.


- What other designs have been considered? [Adding the sbom as a layer](https://github.com/buildpacks/rfcs/pull/186) to the run image and adding its diffID as a label. Some [concerns](https://github.com/buildpacks/rfcs/pull/186#issuecomment-1043348097) with this proposal included:
* Special tooling is required to create the run image (because we don't know the diffID ahead of time)
* The run image may [fall out of date](https://github.com/buildpacks/rfcs/pull/186#discussion_r773246636) in a way that is not obvious
* We don't want to "pick a winner" just yet for the mechanism for attaching sboms to the run image
- Why is this proposal the best? This frees platforms to choose their own method of attaching sboms to the run image, while providing a standardized way to consume a complete sbom for the app image.
- What is the impact of not doing this? Each platform will have to come up with its own way of attaching run image sboms to the app image.

# Prior Art
[prior-art]: #prior-art

- [#RFC 95: Structured SBOMs](https://github.com/buildpacks/rfcs/blob/main/text/0095-sbom.md)

# Unresolved Questions
[unresolved-questions]: #unresolved-questions

- Should the lifecycle run `genpkgs` if no run image SBOM is provided?
- Do the SBOM formats need to be communicated in a label?

- What related issues do you consider out of scope for this RFC that could be addressed in the future independently of the solution that comes out of this RFC?
- The existence or behavior of a preparer binary that knows how to download run image sboms.

# Spec. Changes (OPTIONAL)
[spec-changes]: #spec-changes
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should this section be filled in?

Does this RFC entail any proposed changes to the core specifications or extensions? New fields on the exporter and rebaser. A new label on the app image to designate the layer containing the run image sbom.