diff --git a/docs/docs/references/configuration/cli/trivy_filesystem.md b/docs/docs/references/configuration/cli/trivy_filesystem.md index c09c46f69575..c34288188900 100644 --- a/docs/docs/references/configuration/cli/trivy_filesystem.md +++ b/docs/docs/references/configuration/cli/trivy_filesystem.md @@ -87,6 +87,7 @@ trivy filesystem [flags] PATH --token-header string specify a header name for token in client/server mode (default "Trivy-Token") --trace enable more verbose trace output for custom queries --username strings username. Comma-separated usernames allowed. + --vex string [EXPERIMENTAL] file path to VEX --vuln-type strings comma-separated list of vulnerability types (os,library) (default [os,library]) ``` diff --git a/docs/docs/references/configuration/cli/trivy_image.md b/docs/docs/references/configuration/cli/trivy_image.md index c08206a51a5b..f016a7fff185 100644 --- a/docs/docs/references/configuration/cli/trivy_image.md +++ b/docs/docs/references/configuration/cli/trivy_image.md @@ -106,6 +106,7 @@ trivy image [flags] IMAGE_NAME --token-header string specify a header name for token in client/server mode (default "Trivy-Token") --trace enable more verbose trace output for custom queries --username strings username. Comma-separated usernames allowed. + --vex string [EXPERIMENTAL] file path to VEX --vuln-type strings comma-separated list of vulnerability types (os,library) (default [os,library]) ``` diff --git a/docs/docs/references/configuration/cli/trivy_kubernetes.md b/docs/docs/references/configuration/cli/trivy_kubernetes.md index 3e2c7297e34d..00657886c681 100644 --- a/docs/docs/references/configuration/cli/trivy_kubernetes.md +++ b/docs/docs/references/configuration/cli/trivy_kubernetes.md @@ -97,6 +97,7 @@ trivy kubernetes [flags] { cluster | all | specific resources like kubectl. eg: --tolerations strings specify node-collector job tolerations (example: key1=value1:NoExecute,key2=value2:NoSchedule) --trace enable more verbose trace output for custom queries --username strings username. Comma-separated usernames allowed. + --vex string [EXPERIMENTAL] file path to VEX --vuln-type strings comma-separated list of vulnerability types (os,library) (default [os,library]) ``` diff --git a/docs/docs/references/configuration/cli/trivy_repository.md b/docs/docs/references/configuration/cli/trivy_repository.md index 4f2a9f65d30b..b21ffd326db0 100644 --- a/docs/docs/references/configuration/cli/trivy_repository.md +++ b/docs/docs/references/configuration/cli/trivy_repository.md @@ -87,6 +87,7 @@ trivy repository [flags] (REPO_PATH | REPO_URL) --token-header string specify a header name for token in client/server mode (default "Trivy-Token") --trace enable more verbose trace output for custom queries --username strings username. Comma-separated usernames allowed. + --vex string [EXPERIMENTAL] file path to VEX --vuln-type strings comma-separated list of vulnerability types (os,library) (default [os,library]) ``` diff --git a/docs/docs/references/configuration/cli/trivy_rootfs.md b/docs/docs/references/configuration/cli/trivy_rootfs.md index aaa120285021..47e9a434f075 100644 --- a/docs/docs/references/configuration/cli/trivy_rootfs.md +++ b/docs/docs/references/configuration/cli/trivy_rootfs.md @@ -88,6 +88,7 @@ trivy rootfs [flags] ROOTDIR --token-header string specify a header name for token in client/server mode (default "Trivy-Token") --trace enable more verbose trace output for custom queries --username strings username. Comma-separated usernames allowed. + --vex string [EXPERIMENTAL] file path to VEX --vuln-type strings comma-separated list of vulnerability types (os,library) (default [os,library]) ``` diff --git a/docs/docs/references/configuration/cli/trivy_vm.md b/docs/docs/references/configuration/cli/trivy_vm.md index 2b004b6992e9..3c4d8c06ff7d 100644 --- a/docs/docs/references/configuration/cli/trivy_vm.md +++ b/docs/docs/references/configuration/cli/trivy_vm.md @@ -75,6 +75,7 @@ trivy vm [flags] VM_IMAGE --tf-exclude-downloaded-modules exclude misconfigurations for downloaded terraform modules --token string for authentication in client/server mode --token-header string specify a header name for token in client/server mode (default "Trivy-Token") + --vex string [EXPERIMENTAL] file path to VEX --vuln-type strings comma-separated list of vulnerability types (os,library) (default [os,library]) ``` diff --git a/docs/docs/supply-chain/vex.md b/docs/docs/supply-chain/vex.md index a551629943cc..59f3c5b97353 100644 --- a/docs/docs/supply-chain/vex.md +++ b/docs/docs/supply-chain/vex.md @@ -4,7 +4,7 @@ This feature might change without preserving backwards compatibility. Trivy supports filtering detected vulnerabilities using [the Vulnerability Exploitability Exchange (VEX)](https://www.ntia.gov/files/ntia/publications/vex_one-page_summary.pdf), a standardized format for sharing and exchanging information about vulnerabilities. -By providing VEX alongside the Software Bill of Materials (SBOM) during scanning, it is possible to filter vulnerabilities based on their status. +By providing VEX during scanning, it is possible to filter vulnerabilities based on their status. Currently, Trivy supports the following three formats: - [CycloneDX](https://cyclonedx.org/capabilities/vex/) @@ -14,6 +14,15 @@ Currently, Trivy supports the following three formats: This is still an experimental implementation, with only minimal functionality added. ## CycloneDX +| Target | Supported | +|:---------------:|:---------:| +| Container Image | | +| Filesystem | | +| Code Repository | | +| VM Image | | +| Kubernetes | | +| SBOM | ✅ | + There are [two VEX formats](https://cyclonedx.org/capabilities/vex/) for CycloneDX: - Independent BOM and VEX BOM @@ -28,7 +37,7 @@ The following steps are required: 2. Create a VEX based on the SBOM generated in step 1 3. Provide the VEX when scanning the CycloneDX SBOM -### Generating the SBOM +### Generate the SBOM You can generate a CycloneDX SBOM with Trivy as follows: ```shell @@ -117,23 +126,24 @@ Total: 1 (UNKNOWN: 0, LOW: 1, MEDIUM: 0, HIGH: 0, CRITICAL: 0) CVE-2020-8911 is no longer shown as it is filtered out according to the given CycloneDX VEX document. ## OpenVEX +| Target | Supported | +|:---------------:|:---------:| +| Container Image | ✅ | +| Filesystem | ✅ | +| Code Repository | ✅ | +| VM Image | ✅ | +| Kubernetes | ✅ | +| SBOM | ✅ | + Trivy also supports [OpenVEX][openvex] that is designed to be minimal, compliant, interoperable, and embeddable. -Since OpenVEX aims to be SBOM format agnostic, both CycloneDX and SPDX formats are available for use as input SBOMs in Trivy. +OpenVEX can be used in all Trivy targets, unlike CycloneDX VEX. The following steps are required: -1. Generate a SBOM (CycloneDX or SPDX) -2. Create a VEX based on the SBOM generated in step 1 -3. Provide the VEX when scanning the SBOM +1. Create a VEX document +2. Provide the VEX when scanning your target -### Generating the SBOM -You can generate a CycloneDX or SPDX SBOM with Trivy as follows: - -```shell -$ trivy image --format spdx-json --output debian11.spdx.json debian:11 -``` - -### Create the VEX +### Create the VEX document Please see also [the example](https://github.com/openvex/examples). In Trivy, [the Package URL (PURL)][purl] is used as the product identifier. @@ -167,11 +177,11 @@ In the above example, PURLs, located in `packages.externalRefs.referenceLocator` `pkg:deb/debian/curl@7.50.3-1` in OpenVEX matches `pkg:deb/debian/curl@7.50.3-1?arch=i386`, while `pkg:deb/debian/curl@7.50.3-1?arch=amd64` does not match `pkg:deb/debian/curl@7.50.3-1?arch=i386`. -### Scan SBOM with VEX -Provide the VEX when scanning the SBOM. +### Scan with VEX +Provide the VEX when scanning your target. ``` -$ trivy sbom debian11.spdx.json --vex debian11.openvex +$ trivy image debian:11 --vex debian11.openvex ... 2023-04-26T17:56:05.358+0300 INFO Filtered out the detected vulnerability {"VEX format": "OpenVEX", "vulnerability-id": "CVE-2019-8457", "status": "not_affected", "justification": "vulnerable_code_not_in_execute_path"} @@ -182,25 +192,25 @@ Total: 80 (UNKNOWN: 0, LOW: 58, MEDIUM: 6, HIGH: 16, CRITICAL: 0) CVE-2019-8457 is no longer shown as it is filtered out according to the given OpenVEX document. -[openvex]: https://github.com/openvex/spec -[purl]: https://github.com/package-url/purl-spec ## CSAF +| Target | Supported | +|:---------------:|:---------:| +| Container Image | ✅ | +| Filesystem | ✅ | +| Code Repository | ✅ | +| VM Image | ✅ | +| Kubernetes | ✅ | +| SBOM | ✅ | + Trivy also supports [CSAF][csaf] format for VEX. Since CSAF aims to be SBOM format agnostic, both CycloneDX and SPDX formats are available for use as input SBOMs in Trivy. The following steps are required: -1. Generate a SBOM (CycloneDX or SPDX) -2. Create a CSAF document based on the SBOM generated in step 1 -3. Provide the CSAF document when scanning the SBOM - -### Generating the SBOM -You can generate a CycloneDX or SPDX SBOM with Trivy as follows: +1. Create a CSAF document +2. Provide the CSAF when scanning your target -```shell -$ trivy image --format spdx-json --output debian11.spdx.json debian:11 -``` ### Create the CSAF document Create a CSAF document in JSON format as follows: @@ -303,11 +313,11 @@ $ cat < debian11.vex.csaf EOF ``` -### Scan SBOM with CSAF document -Provide the CSAF document when scanning the SBOM. +### Scan with CSAF VEX +Provide the CSAF document when scanning your target. ```console -$ trivy sbom debian11.spdx.json --vex debian11.vex.csaf +$ trivy image debian:11 --vex debian11.vex.csaf ... 2024-01-02T10:28:26.704+0100 INFO Filtered out the detected vulnerability {"VEX format": "CSAF", "vulnerability-id": "CVE-2019-8457", "status": "not_affected"} @@ -318,4 +328,51 @@ Total: 80 (UNKNOWN: 0, LOW: 58, MEDIUM: 6, HIGH: 16, CRITICAL: 0) CVE-2019-8457 is no longer shown as it is filtered out according to the given CSAF document. +## Appendix +### PURL matching +In the context of VEX, Package URLs (PURLs) are utilized to identify specific software packages and their versions. +The PURL matching specification outlines how PURLs are interpreted for vulnerability exception processing, ensuring precise identification and broad coverage of software packages. + +!!! note + The following PURL matching rules are not formally defined within the current official PURL specification. + Instead, they represent [a community consensus][purl-matching] on how to interpret PURLs. + +Below are the key aspects of the PURL matching rules: + +#### Matching Without Version +A PURL without a specified version (e.g., `pkg:maven/com.google.guava/guava`) matches all versions of that package. +This rule simplifies the application of vulnerability exceptions to all versions of a package. + +**Example**: `pkg:maven/com.google.guava/guava` matches: + +- All versions of `guava`, such as `com.google.guava:guava:24.1.1`, `com.google.guava:guava:30.0`. + +#### Matching Without Qualifiers +A PURL without any qualifiers (e.g., `pkg:maven/com.google.guava/guava@24.1.1`) matches any variation of that package, irrespective of qualifiers. +This approach ensures broad matching capabilities, covering all architectural or platform-specific variations of a package version. + +**Example**: `pkg:maven/com.google.guava/guava@24.1.1` matches: + +- `pkg:maven/com.google.guava/guava@24.1.1?classifier=x86` +- `pkg:maven/com.google.guava/guava@24.1.1?type=pom` + +#### Matching With Specific Qualifiers +A PURL that includes specific qualifiers (e.g., `pkg:maven/com.google.guava/guava@24.1.1?classifier=x86`) matches only those package versions that include the same qualifiers. + +**Example**: `pkg:maven/com.google.guava/guava@24.1.1?classifier=x86` matches: + +- `pkg:maven/com.google.guava/guava@24.1.1?classifier=x86&type=dll` + - Extra qualifiers (e.g., `type=dll`) are ignored. + +does not match: + +- `pkg:maven/com.google.guava/guava@24.1.1` + - `classifier=x86` is missing. +- `pkg:maven/com.google.guava/guava@24.1.1?classifier=sources` + - `classifier` must have the same value. + + [csaf]: https://oasis-open.github.io/csaf-documentation/specification.html +[openvex]: https://github.com/openvex/spec +[purl]: https://github.com/package-url/purl-spec +[purl-matching]: https://github.com/openvex/spec/issues/27 diff --git a/pkg/flag/sbom_flags.go b/pkg/flag/sbom_flags.go index 5980e9eab59e..5d8c515c1d74 100644 --- a/pkg/flag/sbom_flags.go +++ b/pkg/flag/sbom_flags.go @@ -21,29 +21,20 @@ var ( Usage: "deprecated", Deprecated: true, } - VEXFlag = Flag{ - Name: "vex", - ConfigName: "sbom.vex", - Default: "", - Usage: "[EXPERIMENTAL] file path to VEX", - } ) type SBOMFlagGroup struct { ArtifactType *Flag // deprecated SBOMFormat *Flag // deprecated - VEXPath *Flag } type SBOMOptions struct { - VEXPath string } func NewSBOMFlagGroup() *SBOMFlagGroup { return &SBOMFlagGroup{ ArtifactType: &ArtifactTypeFlag, SBOMFormat: &SBOMFormatFlag, - VEXPath: &VEXFlag, } } @@ -55,7 +46,6 @@ func (f *SBOMFlagGroup) Flags() []*Flag { return []*Flag{ f.ArtifactType, f.SBOMFormat, - f.VEXPath, } } @@ -69,7 +59,5 @@ func (f *SBOMFlagGroup) ToOptions() (SBOMOptions, error) { return SBOMOptions{}, xerrors.New("'--artifact-type' and '--sbom-format' are no longer available") } - return SBOMOptions{ - VEXPath: getString(f.VEXPath), - }, nil + return SBOMOptions{}, nil } diff --git a/pkg/flag/vulnerability_flags.go b/pkg/flag/vulnerability_flags.go index c69ba3273dea..bf476c38fff9 100644 --- a/pkg/flag/vulnerability_flags.go +++ b/pkg/flag/vulnerability_flags.go @@ -35,17 +35,25 @@ var ( Values: dbTypes.Statuses, Usage: "comma-separated list of vulnerability status to ignore", } + VEXFlag = Flag{ + Name: "vex", + ConfigName: "vulnerability.vex", + Default: "", + Usage: "[EXPERIMENTAL] file path to VEX", + } ) type VulnerabilityFlagGroup struct { VulnType *Flag IgnoreUnfixed *Flag IgnoreStatus *Flag + VEXPath *Flag } type VulnerabilityOptions struct { VulnType []string IgnoreStatuses []dbTypes.Status + VEXPath string } func NewVulnerabilityFlagGroup() *VulnerabilityFlagGroup { @@ -53,6 +61,7 @@ func NewVulnerabilityFlagGroup() *VulnerabilityFlagGroup { VulnType: &VulnTypeFlag, IgnoreUnfixed: &IgnoreUnfixedFlag, IgnoreStatus: &IgnoreStatusFlag, + VEXPath: &VEXFlag, } } @@ -65,6 +74,7 @@ func (f *VulnerabilityFlagGroup) Flags() []*Flag { f.VulnType, f.IgnoreUnfixed, f.IgnoreStatus, + f.VEXPath, } } @@ -95,5 +105,6 @@ func (f *VulnerabilityFlagGroup) ToOptions() VulnerabilityOptions { return VulnerabilityOptions{ VulnType: getStringSlice(f.VulnType), IgnoreStatuses: ignoreStatuses, + VEXPath: getString(f.VEXPath), } }