diff --git a/docs/sbom.md b/docs/sbom.md new file mode 100644 index 0000000..21f67a4 --- /dev/null +++ b/docs/sbom.md @@ -0,0 +1,417 @@ +# Understanding SBOMs + +A Software Bill of Materials (SBOM) is at its core a listing of software components for a given deliverable. That +deliverable may be a single RPM package, a container image, or an entire product version. There are several use +cases where SBOMs are beneficial: + +- in-depth review of the composition of a particular product for procurement or audit purposes, + +- accurate vulnerability risk assessment when combined with VEX data, + +- or faster incident response when aggregating SBOMs for an entire product portfolio. + +When talking about inventories of components, it's also important to describe what the current design goals of a +comprehensive SBOM are: + +- Provide a complete and accurate listing of software components and their relationships to each other from a + supply chain perspective. + +- Define an accurate identification of components and products usable across all published security data. + +It's also important to cover the qualities of an SBOM that are currently out of scope: + +- Provide a component dependency graph: providing dependency relationships between components as part of an + application or an operating system is currently out of scope. This type of information is varied between different + ecosystems, and it would be difficult to express it correctly in product-level SBOMs. + The relationships currently represented are limited to more direct dependencies, such as those between a container + image and the packages it includes, an operating system and its constituent packages, or a package and its + upstream counterpart. We do not include application-level dependencies, like those where a Python package such as + [`requests`](https://pypi.org/project/requests/) depends on another package like + [`certifi`](https://pypi.org/project/certifi/). + +- Inclusion of complete listings of individual files for each component: for each listed component in an SBOM, it is + assumed that the user can fetch it from its indicated location, and inspect the component itself to list out its + files. For example, when downloading a source RPM, the downloaded archive can be unpacked and inspected to acquire + a list of files contained in it. + +## Formats + +The two most widely used SBOM formats are [SPDX](https://spdx.dev/) and +[CycloneDX](https://cyclonedx.org/). Both offer similar features and data fields, and can be used to represent +complex inventories of components, their metadata (such as provenance or licensing), and additional document properties. + +Most of this document focuses on Red Hat's use of SPDX 2.3 in its published SBOMs. In the future, we may add similar +guidelines for CycloneDX and SPDX 3.0. + +## Types + +Depending on how an SBOM is generated, it will contain varying levels of information. The sections below highlight +different viewpoints of when an SBOM is created and what type of data it includes. + +### Build vs Release + +_Build-time_ SBOMs are created during the initial build process of an artifact (for example, when an RPM is created +from source files or a container image is built using [`buildah`](https://buildah.io/)). These SBOMs document the +components used during the build process to produce the final artifact as well as any components used for the build +process itself. This SBOM type also aligns with the _Build_ SBOM type from CISA's guidance on +[Types of SBOM Documents](https://www.cisa.gov/sites/default/files/2023-04/sbom-types-document-508c.pdf). + +_Release-time_ SBOMs are generated when an artifact is released or published. These SBOMs build upon build-time +SBOMs by incorporating additional metadata, such as the repositories or locations where the artifact is +published, and associating it with the relevant product information if there is any. Release-time SBOMs reflect the +state of the software as it is distributed to end users. This SBOM type is close to the _Deployed_ type as defined +by CISA, but it reflects the state of the product that _would_ be installed by a given end user. + +Red Hat's publicly available SBOMs are of the "release-time" type, including details about where an artifact +can be located after being released. + +**Example**: + +- Build-time SBOM of the `ubi9-micro` container image along with all of its installed components (RPMs): + [build/ubi9-micro-container-9.4-6.1716471860_amd64](https://github.com/RedHatProductSecurity/security-data-guidelines/blob/main/sbom/examples/container_image/build/ubi9-micro-container-9.4-6.1716471860_amd64.spdx.json) +- Release-time SBOM of the same `ubi9-micro` container image: + [release/ubi9-micro-container-9.4-6.1716471860_amd64](https://github.com/RedHatProductSecurity/security-data-guidelines/blob/main/sbom/examples/container_image/release/ubi9-micro-container-9.4-6.1716471860_amd64.spdx.json) + +The difference between these two SBOMs is relatively minor; the release-time SBOM contains information on where the +container image (identified by two distinct purls) itself is available from: + +```diff +--- sbom/examples/container_image/build/ubi9-micro-container-9.4-6.1716471860_amd64.spdx.json ++++ sbom/examples/container_image/release/ubi9-micro-container-9.4-6.1716471860_amd64.spdx.json +@@ -22,12 +22,12 @@ + { + "referenceCategory": "PACKAGE-MANAGER", + "referenceType": "purl", +- "referenceLocator": "pkg:oci/ubi-micro@sha256:1c8483e0fda0e990175eb9855a5f15e0910d2038dd397d9e2b357630f0321e6d?arch=amd64" ++ "referenceLocator": "pkg:oci/ubi-micro@sha256%3A1c8483e0fda0e990175eb9855a5f15e0910d2038dd397d9e2b357630f0321e6d?arch=amd64&repository_url=registry.access.redhat.com/ubi9/ubi-micro&tag=9.4-6.1716471860" + }, + { + "referenceCategory": "PACKAGE-MANAGER", + "referenceType": "purl", +- "referenceLocator": "pkg:oci/ubi9-micro@sha256:1c8483e0fda0e990175eb9855a5f15e0910d2038dd397d9e2b357630f0321e6d?arch=amd64" ++ "referenceLocator": "pkg:oci/ubi9-micro@sha256%3A1c8483e0fda0e990175eb9855a5f15e0910d2038dd397d9e2b357630f0321e6d?arch=amd64&repository_url=registry.access.redhat.com/ubi9-micro&tag=9.4-6.1716471860" + } + ], +``` + +### Component-Level vs Product-Level + +_Component-level_ SBOMs describe individual components, such as a single RPM package or a container +image. They document the full listing of individual components, libraries, and other relevant +software that went into building that component. Component-level SBOMs also include provenance metadata for certain +components. For example, a component-level SBOM of an RPM will point to the upstream sources that that RPM is based on. + +_Product-level_ SBOMs describe an entire product and the subset of its components that were built and included in +the final product. A product-level SBOM may cover one or more component-level SBOMs, providing a way to connect each +release component to its parent product. + +**Example**: + +- Component-level SBOM of the `openssl-3.0.7-18.el9_2` RPM package: + [release/openssl-3.0.7-18.el9_2](https://github.com/RedHatProductSecurity/security-data-guidelines/blob/main/sbom/examples/rpm/release/openssl-3.0.7-18.el9_2.spdx.json) + +- Product-level SBOM of the `openssl-3.0.7-18.el9_2` RPM package as included in RHEL 9.2 EUS repositories: + [product/rhel-9.2-eus](https://github.com/RedHatProductSecurity/security-data-guidelines/blob/main/sbom/examples/product/rhel-9.2-eus.spdx.json) + +Note that the root package described by the component-level SBOM, the OpenSSL Source RPM (SRPM), is the only +reference present in the product-level SBOM to not duplicate information between the two SBOMs. The purl +reference from the SRPM package can be used to discover the component-level SBOM from the product-level SBOM. + +### Shallow vs Complete + +_Shallow_ SBOMs describe only the current layer of components that were used to build a specific artifact. They +focus on the immediate components without necessarily documenting their origins. The benefit of this approach is +smaller SBOM files, and the ability to make incremental changes in select SBOMs while others remain unchanged when +composing multiple SBOMs into a larger set (to describe a product, for example). + +_Complete_ SBOMs provide a full, in-depth representation of all levels of the build process in a single file. A +Complete SBOM includes all component layers and their dependencies, offering a complete view of a product's composition. +These types of SBOMs are mostly used for procurement and audit purposes. + +Examples: +- TODO + +## Document Structure + +The following snippet shows a minimal SBOM document; each field is annotated (inline or below the example) with +details about its purpose and usage: + +=== "SPDX 2.3" + + ```json + { + "spdxVersion": "SPDX-2.3",// (1)! + "dataLicense": "CC-BY-4.0",// (2)! + "SPDXID": "SPDXRef-DOCUMENT",// (3)! + "creationInfo": { + "created": "2006-08-14T02:34:56Z", + "creators": [ + "Tool: example SPDX document only" + ] + }, + "name": "ubi9-micro-container-9.4-6.1716471860_amd64", + "documentNamespace": "https://www.redhat.com/ubi9-micro-container-9.4-6.1716471860_amd64.spdx.json", + "packages": [...], + "files": [], + "relationships": [...] + } + ``` + + 1. SPDX version 2.3 as described at [https://spdx.github.io/spdx-spec/v2.3/](https://spdx.github.io/spdx-spec/v2.3/). + + 2. All Red Hat security data is published under the + [Creative Commons Attribution 4.0 International License](https://creativecommons.org/licenses/by/4.0/). + + 3. [`SPDXID`](https://spdx.github.io/spdx-spec/v2.3/document-creation-information/#63-spdx-identifier-field) + must be set to this value. + +A more detailed breakdown of some of the fields: + +`creationInfo` +: This field must contain at least the + [`created`](https://spdx.github.io/spdx-spec/v2.3/document-creation-information/#68-creator-field) and + [`creators`](https://spdx.github.io/spdx-spec/v2.3/document-creation-information/#69-created-field) + fields. The timestamp in the `created` field must be set to an ISO 8601-formatted date and time string using + the UTC timezone. The `creators` field must identify the tool and its version that was used to generate the SBOM + file (for example, `Tool: SBOMer 1.2.3` or even `Tool: pkg:github/project-ncl/sbomer@1.0.0.M3`). + Optionally, the organization responsible for generating the SBOM can be included in a separate string + (for example, `Organization: Red Hat Product Security (secalert@redhat.com)`). + +[`name`](https://spdx.github.io/spdx-spec/v2.3/document-creation-information/#64-document-name-field) +: This is an arbitrary value that should describe the main artifact described by the SBOM document. This can be a + product, a container image, or a specific package. The name should contain a descriptive value for that given + artifact along with a version identifier. This field should only serve as a human-readable value and be shown in + user interfaces for informational purposes. The metadata of the main package (the one _DESCRIBED_ by + the SBOM document) should be used for any automation purposes. Note also that the `name` value may not be unique + to a single SBOM document. + +[`documentNamespace`](https://spdx.github.io/spdx-spec/v2.3/document-creation-information/#65-spdx-document-namespace-field) +: This field uniquely identifies the SPDX SBOM document and must be a valid URI, even though that URI does not + have to be accessible. Red Hat SBOMs can use one of two possible values: + + - A URI that is namespaced to a generic Red Hat location: `https://www.redhat.com/[DocumentID].spdx.json`. + This URI is not accessible and only serves the purpose of identifying the document to its namespace (here, + Red Hat). + + - A URI that is namespaced to `access.redhat.com/security/data`: + `https://security.access.redhat.com/data/sbom/spdx/[DocumentID].spdx.json`. This URI is assumed to be accessible + and the identified SBOM can be downloaded from the specified location. + + The `documentNamespace` value has no direct relationship to the `name` value. + +The `packages` and `relationships` fields are described in depth in the sections below for each respective software +content type. The `files` field is currently unused and will thus either not be present at all, or set to an empty +list. All software components in an SBOM are described as packages; all files are assumed to be a part of _some_ +package and should thus not be listed on their own in the `files` field. + +### Packages and Relationships + +The following example shows the structure of a package object for a specific component; each field is annotated +(inline or below the example) with details about its purpose and usage: + +=== "SPDX 2.3" + + ```json + { + "SPDXID": "SPDXRef-[UUID]",// (1)! + "name": "ubi9-micro-container", + "versionInfo": "9.4-6.1716471860", + "supplier": "Organization: Red Hat",// (2)! + "downloadLocation": "NOASSERTION", + "licenseConcluded": "NOASSERTION", + "externalRefs": [...], + "checksums": [...] + } + ``` + + 1. A unique identifier of a given component within this document. This value should only be used to associate + relationships to other components described in an SBOM via their relationships. + + 2. The value `Organization: Red Hat` must be used for all components that are distributed by Red Hat. + +[`name`](https://spdx.github.io/spdx-spec/v2.3/package-information/#71-package-name-field) +: The name of the component. This value may differ for different types of package ecosystems. It is recommended to + use the `name` field of the associated purl string for consistent results. + +[`versionInfo`](https://spdx.github.io/spdx-spec/v2.3/package-information/#73-package-version-field) +: The version of the component. This value may differ for different types of package ecosystems. It is + recommended to use the `version` field of the associated purl string for consistent results. + +[`downloadLocation`](https://spdx.github.io/spdx-spec/v2.3/package-information/#77-package-download-location-field) +: This field is used to point to the VCS that holds the related source code for this component. In most cases, + this field will be set to `NOASSERTION` because the upstream equivalent of a downstream component is represented + with its own package object. + +[`licenseConcluded`](https://spdx.github.io/spdx-spec/v2.3/package-information/#713-concluded-license-field) +: The concluded license of the package, based on the information available during the build. If during the build, + this information cannot be determined, the value `NOASSERTION` should be used. + +[`externalRefs`](https://spdx.github.io/spdx-spec/v2.3/package-information/#722-external-reference-comment-field) +: At least one of the references must include a Package URL (purl) unless the object is describing a product. + [Identifying Red Hat components using Package URL](./purl.md) documents what purl strings for different types of + components should look like. Note that multiple purls may be used for a single package to identify multiple + locations from where the package can be accessed. + +[`checksums`](https://spdx.github.io/spdx-spec/v2.3/package-information/#710-package-checksum-field) +: The checksums of the component. The type of checksum used will depend on the type of the component. See below + sections for more information. + + +#### Container Image + +=== "SPDX 2.3" + + ```json + { + "SPDXID": "SPDXRef-image-index",// (1)! + "name": "ubi9-micro-container",// (2)! + "versionInfo": "9.4-6.1716471860", + "supplier": "Organization: Red Hat", + "downloadLocation": "NOASSERTION", + "licenseConcluded": "NOASSERTION", + "externalRefs": [ + { + "referenceCategory": "PACKAGE-MANAGER", + "referenceType": "purl", + "referenceLocator": "pkg:oci/ubi-micro@sha256%3A1c8483e0fda0e990175eb9855a5f15e0910d2038dd397d9e2b357630f0321e6d?repository_url=registry.access.redhat.com/ubi9&tag=9.4-6.1716471860" + }, + { + "referenceCategory": "PACKAGE-MANAGER", + "referenceType": "purl", + "referenceLocator": "pkg:oci/ubi9-micro@sha256%3A1c8483e0fda0e990175eb9855a5f15e0910d2038dd397d9e2b357630f0321e6d?repository_url=registry.access.redhat.com&tag=9.4-6.1716471860" + } + ], + "checksums": [ + { + "algorithm": "SHA256", + "checksumValue": "1c8483e0fda0e990175eb9855a5f15e0910d2038dd397d9e2b357630f0321e6d" + } + ] + } + ``` + +TODO: +- Document differences between image index vs image +- Document what checksum refer to +- Mention purls may point to different repos but same image +- Mention licenseDeclared will mostly be NOASSERTION since licensing is set on components, not images +- downloadlocation will never be set; container images don't have their own repos + +#### RPM + +Downstream: + +=== "SPDX 2.3" + + ```json + { + "SPDXID": "SPDXRef-aarch64-openssl-libs", + "name": "openssl-libs", + "versionInfo": "3.0.7-18.el9_2", + "supplier": "Organization: Red Hat", + "downloadLocation": "NOASSERTION", + "packageFileName": "openssl-libs-3.0.7-18.el9_2.aarch64.rpm", + "licenseConcluded": "Apache-2.0", + "externalRefs": [ + { + "referenceCategory": "PACKAGE-MANAGER", + "referenceType": "purl", + "referenceLocator": "pkg:rpm/redhat/openssl-libs@3.0.7-18.el9_2?arch=aarch64&repository_id=rhel-9-for-aarch64-baseos-eus-rpms" + }, + { + "referenceCategory": "PACKAGE-MANAGER", + "referenceType": "purl", + "referenceLocator": "pkg:rpm/redhat/openssl-libs@3.0.7-18.el9_2?arch=aarch64&repository_id=rhel-9-for-aarch64-baseos-aus-rpms" + }, + { + "referenceCategory": "PACKAGE-MANAGER", + "referenceType": "purl", + "referenceLocator": "pkg:rpm/redhat/openssl-libs@3.0.7-18.el9_2?arch=aarch64&repository_id=rhel-9-for-aarch64-baseos-e4s-rpms" + } + ], + "checksums": [ + { + "algorithm": "SHA256", + "checksumValue": "cae5941219fd64e75c2b29509c6fe712bef77181a586702275a46a5e812d4dd4" + } + ] + } + ``` + +TODO: +- describe binary vs source RPM +- downloadLocation will never be set; see upstream + +Upstream: + +=== "SPDX 2.3" + ```json + { + "SPDXID": "SPDXRef-Source0-origin", + "name": "openssl", + "versionInfo": "3.0.7", + "downloadLocation": "https://openssl.org/source/openssl-3.0.7.tar.gz", + "packageFileName": "openssl-3.0.7.tar.gz", + "checksums": [ + { + "algorithm": "SHA256", + "checksumValue": "83049d042a260e696f62406ac5c08bf706fd84383f945cf21bd61e9ed95c396e" + } + ], + "externalRefs": [ + { + "referenceCategory": "PACKAGE-MANAGER", + "referenceType": "purl", + "referenceLocator": "pkg:generic/openssl@3.0.7?download_url=https://openssl.org/source/openssl-3.0.7.tar.gz&checksum=sha256:83049d042a260e696f62406ac5c08bf706fd84383f945cf21bd61e9ed95c396e" + } + ] + } + ``` + +TODO: +- Note: we may not have this yet in our SBOMs +- Note: mention midstream; may not be present +- downloadLocation points to upstream VCS + +#### Product + +=== "SPDX 2.3" + ```json + { + "SPDXID": "SPDXRef-RHEL-9.2-EUS", + "name": "Red Hat Enterprise Linux", + "versionInfo": "9.2 EUS", + "supplier": "Organization: Red Hat", + "downloadLocation": "NOASSERTION",// (1)! + "licenseConcluded": "NOASSERTION",// (2)! + "externalRefs": [ + { + "referenceCategory": "SECURITY", + "referenceLocator": "cpe:/a:redhat:rhel_eus:9.2::baseos", + "referenceType": "cpe22Type" + } + ] + } + ``` + + 1. Not used because this product component is not specific enough to an architecture or ISO variant (workstation vs server) + + 2. Not set, only components have licenses + +`name` +: This field must contain a human-readable name of the product. + +`versionInfo` +: This field must contain the most granular version of the product, for which the SBOM was generated. + +`externalRefs` +: TODO: describe CPE usage + +## Additional Notes + +The guidelines highlighted in this document represent an ideal state across all of Red Hat-published security data +that we want to achieve in the long term. In some SBOMs, components may be missing their provenance data or their +license expressions may not be accurate. Please +[contact Red Hat Product Security](https://access.redhat.com/security/team/contact/) or file a Jira issue in the +[SECDATA project](https://issues.redhat.com/projects/SECDATA) if you find any discrepancies in Red Hat's security data. +Feedback on our SBOM design and publishing is always welcome and appreciated. diff --git a/mkdocs.yml b/mkdocs.yml index d8e68c8..62ddd43 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -36,6 +36,7 @@ theme: nav: - Home: "index.md" + - SBOM: "sbom.md" - purl: "purl.md" plugins: diff --git a/sbom/examples/container_image/release/from_catalog.py b/sbom/examples/container_image/release/from_catalog.py index 46e87be..47b4d82 100644 --- a/sbom/examples/container_image/release/from_catalog.py +++ b/sbom/examples/container_image/release/from_catalog.py @@ -15,8 +15,6 @@ nvr_api = catalog_url + "images/nvr/" rpm_manifest_api = catalog_url + "images/id/{catalog_image_id}/rpm-manifest" -rpm_sbom_url = "https://access.redhat.com/security/data/sbom/v1/rpm/" - def get_image_data(image_nvr): response = requests.get(nvr_api + image_nvr)