From c2a7ad5c014e3e1861b8bf79b6ef321573cb8983 Mon Sep 17 00:00:00 2001 From: saso Date: Wed, 27 Jul 2022 23:39:35 +0900 Subject: [PATCH] feat(report): add support for Cosign vulnerability attestation (#2567) --- docs/docs/attestation/vuln.md | 186 +++++++++++++++++++++++++++++ docs/docs/references/cli/client.md | 23 ++-- docs/docs/references/cli/config.md | 35 +++--- docs/docs/references/cli/fs.md | 25 ++-- docs/docs/references/cli/image.md | 26 ++-- docs/docs/references/cli/index.md | 21 ++-- docs/docs/references/cli/module.md | 17 +-- docs/docs/references/cli/plugin.md | 19 +-- docs/docs/references/cli/repo.md | 27 +++-- docs/docs/references/cli/rootfs.md | 25 ++-- docs/docs/references/cli/sbom.md | 22 ++-- docs/docs/references/cli/server.md | 15 +-- mkdocs.yml | 1 + pkg/flag/report_flags.go | 2 +- pkg/report/predicate/vuln.go | 89 ++++++++++++++ pkg/report/predicate/vuln_test.go | 112 +++++++++++++++++ pkg/report/writer.go | 20 ++-- 17 files changed, 541 insertions(+), 124 deletions(-) create mode 100644 docs/docs/attestation/vuln.md create mode 100644 pkg/report/predicate/vuln.go create mode 100644 pkg/report/predicate/vuln_test.go diff --git a/docs/docs/attestation/vuln.md b/docs/docs/attestation/vuln.md new file mode 100644 index 000000000000..240030d7d763 --- /dev/null +++ b/docs/docs/attestation/vuln.md @@ -0,0 +1,186 @@ +# Cosign Vulnerability Attestation + +## Generate Cosign Vulnerability Scan Record + +Trivy generates reports in the [Cosign vulnerability scan record format][vuln-attest-spec]. + +You can use the regular subcommands (like image, fs and rootfs) and specify `cosign-vuln` with the --format option. + +``` +$ trivy image --format cosign-vuln --output vuln.json alpine:3.10 +``` + +
+Result + +```json +{ + "invocation": { + "parameters": null, + "uri": "", + "event_id": "", + "builder.id": "" + }, + "scanner": { + "uri": "pkg:github/aquasecurity/trivy@v0.30.1-8-gf9cb8a28", + "version": "v0.30.1-8-gf9cb8a28", + "db": { + "uri": "", + "version": "" + }, + "result": { + "SchemaVersion": 2, + "ArtifactName": "alpine:3.10", + "ArtifactType": "container_image", + "Metadata": { + "OS": { + "Family": "alpine", + "Name": "3.10.9", + "EOSL": true + }, + "ImageID": "sha256:e7b300aee9f9bf3433d32bc9305bfdd22183beb59d933b48d77ab56ba53a197a", + "DiffIDs": [ + "sha256:9fb3aa2f8b8023a4bebbf92aa567caf88e38e969ada9f0ac12643b2847391635" + ], + "RepoTags": [ + "alpine:3.10" + ], + "RepoDigests": [ + "alpine@sha256:451eee8bedcb2f029756dc3e9d73bab0e7943c1ac55cff3a4861c52a0fdd3e98" + ], + "ImageConfig": { + "architecture": "amd64", + "container": "fdb7e80e3339e8d0599282e606c907aa5881ee4c668a68136119e6dfac6ce3a4", + "created": "2021-04-14T19:20:05.338397761Z", + "docker_version": "19.03.12", + "history": [ + { + "created": "2021-04-14T19:20:04.987219124Z", + "created_by": "/bin/sh -c #(nop) ADD file:c5377eaa926bf412dd8d4a08b0a1f2399cfd708743533b0aa03b53d14cb4bb4e in / " + }, + { + "created": "2021-04-14T19:20:05.338397761Z", + "created_by": "/bin/sh -c #(nop) CMD [\"/bin/sh\"]", + "empty_layer": true + } + ], + "os": "linux", + "rootfs": { + "type": "layers", + "diff_ids": [ + "sha256:9fb3aa2f8b8023a4bebbf92aa567caf88e38e969ada9f0ac12643b2847391635" + ] + }, + "config": { + "Cmd": [ + "/bin/sh" + ], + "Env": [ + "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin" + ], + "Image": "sha256:eb2080c455e94c22ae35b3aef9e078c492a00795412e026e4d6b41ef64bc7dd8" + } + } + }, + "Results": [ + { + "Target": "alpine:3.10 (alpine 3.10.9)", + "Class": "os-pkgs", + "Type": "alpine", + "Vulnerabilities": [ + { + "VulnerabilityID": "CVE-2021-36159", + "PkgName": "apk-tools", + "InstalledVersion": "2.10.6-r0", + "FixedVersion": "2.10.7-r0", + "Layer": { + "Digest": "sha256:396c31837116ac290458afcb928f68b6cc1c7bdd6963fc72f52f365a2a89c1b5", + "DiffID": "sha256:9fb3aa2f8b8023a4bebbf92aa567caf88e38e969ada9f0ac12643b2847391635" + }, + "SeveritySource": "nvd", + "PrimaryURL": "https://avd.aquasec.com/nvd/cve-2021-36159", + "DataSource": { + "ID": "alpine", + "Name": "Alpine Secdb", + "URL": "https://secdb.alpinelinux.org/" + }, + "Description": "libfetch before 2021-07-26, as used in apk-tools, xbps, and other products, mishandles numeric strings for the FTP and HTTP protocols. The FTP passive mode implementation allows an out-of-bounds read because strtol is used to parse the relevant numbers into address bytes. It does not check if the line ends prematurely. If it does, the for-loop condition checks for the '\\0' terminator one byte too late.", + "Severity": "CRITICAL", + "CweIDs": [ + "CWE-125" + ], + "CVSS": { + "nvd": { + "V2Vector": "AV:N/AC:L/Au:N/C:P/I:N/A:P", + "V3Vector": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:N/A:H", + "V2Score": 6.4, + "V3Score": 9.1 + } + }, + "References": [ + "https://github.com/freebsd/freebsd-src/commits/main/lib/libfetch", + "https://gitlab.alpinelinux.org/alpine/apk-tools/-/issues/10749", + "https://lists.apache.org/thread.html/r61db8e7dcb56dc000a5387a88f7a473bacec5ee01b9ff3f55308aacc@%3Cdev.kafka.apache.org%3E", + "https://lists.apache.org/thread.html/r61db8e7dcb56dc000a5387a88f7a473bacec5ee01b9ff3f55308aacc@%3Cusers.kafka.apache.org%3E", + "https://lists.apache.org/thread.html/rbf4ce74b0d1fa9810dec50ba3ace0caeea677af7c27a97111c06ccb7@%3Cdev.kafka.apache.org%3E", + "https://lists.apache.org/thread.html/rbf4ce74b0d1fa9810dec50ba3ace0caeea677af7c27a97111c06ccb7@%3Cusers.kafka.apache.org%3E" + ], + "PublishedDate": "2021-08-03T14:15:00Z", + "LastModifiedDate": "2021-10-18T12:19:00Z" + } + ] + } + ] + } + }, + "metadata": { + "scanStartedOn": "2022-07-24T17:14:04.864682+09:00", + "scanFinishedOn": "2022-07-24T17:14:04.864682+09:00" + } +} +``` + +
+ +## Create Cosign Vulnerability Attestation + +[Cosign](https://github.com/sigstore/cosign) supports generating and verifying [in-toto attestations](https://github.com/in-toto/attestation). This tool enables you to sign and verify Cosign vulnerability attestation. + +!!! note + In the following examples, the `cosign` command will write an attestation to a target OCI registry, so you must have permission to write. + If you want to avoid writing an OCI registry and only want to see an attestation, add the `--no-upload` option to the `cosign` command. + + +### Sign with a local key pair + +Cosign can generate key pairs and use them for signing and verification. Read more about [how to generate key pairs](https://docs.sigstore.dev/cosign/key-generation). + +In the following example, Trivy generates a cosign vulnerability scan record, and then Cosign attaches an attestation of it to a container image with a local key pair. + +``` +$ trivy image --format cosign-vuln --output vuln.json +$ cosign attest --key /path/to/cosign.key --type vuln --predicate vuln.json +``` + +Then, you can verify attestations on the image. + +``` +$ cosign verify-attestation --key /path/to/cosign.pub +``` + +### Keyless signing + +You can use Cosign to sign without keys by authenticating with an OpenID Connect protocol supported by sigstore (Google, GitHub, or Microsoft). + +``` +$ trivy image --format cosign-vuln -o vuln.json +$ COSIGN_EXPERIMENTAL=1 cosign attest --type vuln --predicate vuln.json +``` + +You can verify attestations. + +``` +$ COSIGN_EXPERIMENTAL=1 cosign verify-attestation +``` + +[vuln-attest-spec]: https://github.com/sigstore/cosign/blob/95b74db89941e8ec85e768f639efd4d948db06cd/specs/COSIGN_VULN_ATTESTATION_SPEC.md \ No newline at end of file diff --git a/docs/docs/references/cli/client.md b/docs/docs/references/cli/client.md index 3d210dd788fc..3113c346c699 100644 --- a/docs/docs/references/cli/client.md +++ b/docs/docs/references/cli/client.md @@ -2,7 +2,7 @@ ```bash Usage: - [DEPRECATED] trivy client [flags] IMAGE_NAME + trivy client [flags] IMAGE_NAME Aliases: client, c @@ -10,13 +10,13 @@ Aliases: Scan Flags --offline-scan do not issue API requests to identify dependencies --security-checks string comma-separated list of what security issues to detect (vuln,config,secret) (default "vuln,secret") - --skip-dirs string specify the directories where the traversal is skipped - --skip-files string specify the file paths to skip traversal + --skip-dirs strings specify the directories where the traversal is skipped + --skip-files strings specify the file paths to skip traversal Report Flags --dependency-tree show dependency origin tree (EXPERIMENTAL) --exit-code int specify exit code when any security issues are found - -f, --format string format (table, json, sarif, template, cyclonedx, spdx, spdx-json, github) (default "table") + -f, --format string format (table, json, sarif, template, cyclonedx, spdx, spdx-json, github, cosign-vuln) (default "table") --ignore-policy string specify the Rego file path to evaluate each vulnerability --ignorefile string specify .trivyignore file (default ".trivyignore") --list-all-pkgs enabling the option will output all packages regardless of vulnerability @@ -59,11 +59,12 @@ Client/Server Flags --token-header string specify a header name for token in client/server mode (default "Trivy-Token") Global Flags: - --cache-dir string cache directory (default "/Users/teppei/Library/Caches/trivy") - -c, --config string config path (default "trivy.yaml") - -d, --debug debug mode - --insecure allow insecure server connections when using TLS - -q, --quiet suppress progress bar and log output - --timeout duration timeout (default 5m0s) - -v, --version show version + --cache-dir string cache directory (default "/Users/teppei/Library/Caches/trivy") + -c, --config string config path (default "trivy.yaml") + -d, --debug debug mode + --generate-default-config write the default config to trivy-default.yaml + --insecure allow insecure server connections when using TLS + -q, --quiet suppress progress bar and log output + --timeout duration timeout (default 5m0s) + -v, --version show version ``` diff --git a/docs/docs/references/cli/config.md b/docs/docs/references/cli/config.md index cb39adb127d9..ee753037bbe5 100644 --- a/docs/docs/references/cli/config.md +++ b/docs/docs/references/cli/config.md @@ -10,19 +10,16 @@ Aliases: config, conf Scan Flags - --skip-dirs string specify the directories where the traversal is skipped - --skip-files string specify the file paths to skip traversal + --skip-dirs strings specify the directories where the traversal is skipped + --skip-files strings specify the file paths to skip traversal Report Flags - --dependency-tree show dependency origin tree (EXPERIMENTAL) - --exit-code int specify exit code when any security issues are found - -f, --format string format (table, json, sarif, template, cyclonedx, spdx, spdx-json, github) (default "table") - --ignore-policy string specify the Rego file path to evaluate each vulnerability - --ignorefile string specify .trivyignore file (default ".trivyignore") - --list-all-pkgs enabling the option will output all packages regardless of vulnerability - -o, --output string output file name - -s, --severity string severities of security issues to be displayed (comma separated) (default "UNKNOWN,LOW,MEDIUM,HIGH,CRITICAL") - -t, --template string output template + --exit-code int specify exit code when any security issues are found + -f, --format string format (table, json, sarif, template, cyclonedx, spdx, spdx-json, github, cosign-vuln) (default "table") + --ignorefile string specify .trivyignore file (default ".trivyignore") + -o, --output string output file name + -s, --severity string severities of security issues to be displayed (comma separated) (default "UNKNOWN,LOW,MEDIUM,HIGH,CRITICAL") + -t, --template string output template Cache Flags --cache-backend string cache backend (e.g. redis://localhost:6379) (default "fs") @@ -41,12 +38,12 @@ Misconfiguration Flags --trace enable more verbose trace output for custom queries Global Flags: - --cache-dir string cache directory (default "/Users/teppei/Library/Caches/trivy") - -c, --config string config path (default "trivy.yaml") - -d, --debug debug mode - --insecure allow insecure server connections when using TLS - -q, --quiet suppress progress bar and log output - --timeout duration timeout (default 5m0s) - -v, --version show version - + --cache-dir string cache directory (default "/Users/teppei/Library/Caches/trivy") + -c, --config string config path (default "trivy.yaml") + -d, --debug debug mode + --generate-default-config write the default config to trivy-default.yaml + --insecure allow insecure server connections when using TLS + -q, --quiet suppress progress bar and log output + --timeout duration timeout (default 5m0s) + -v, --version show version ``` diff --git a/docs/docs/references/cli/fs.md b/docs/docs/references/cli/fs.md index 005b97288c95..a7bf002ea811 100644 --- a/docs/docs/references/cli/fs.md +++ b/docs/docs/references/cli/fs.md @@ -19,13 +19,13 @@ Examples: Scan Flags --offline-scan do not issue API requests to identify dependencies --security-checks string comma-separated list of what security issues to detect (vuln,config,secret) (default "vuln,secret") - --skip-dirs string specify the directories where the traversal is skipped - --skip-files string specify the file paths to skip traversal + --skip-dirs strings specify the directories where the traversal is skipped + --skip-files strings specify the file paths to skip traversal Report Flags --dependency-tree show dependency origin tree (EXPERIMENTAL) --exit-code int specify exit code when any security issues are found - -f, --format string format (table, json, sarif, template, cyclonedx, spdx, spdx-json, github) (default "table") + -f, --format string format (table, json, sarif, template, cyclonedx, spdx, spdx-json, github, cosign-vuln) (default "table") --ignore-policy string specify the Rego file path to evaluate each vulnerability --ignorefile string specify .trivyignore file (default ".trivyignore") --list-all-pkgs enabling the option will output all packages regardless of vulnerability @@ -63,6 +63,10 @@ Misconfiguration Flags Secret Flags --secret-config string specify a path to config file for secret scanning (default "trivy-secret.yaml") +License Flags + --ignored-licenses strings specify a list of license to ignore + --license-full eagerly look for licenses in source code headers and license files + Client/Server Flags --custom-headers strings custom headers in client mode --server string server address in client mode @@ -70,11 +74,12 @@ Client/Server Flags --token-header string specify a header name for token in client/server mode (default "Trivy-Token") Global Flags: - --cache-dir string cache directory (default "/Users/teppei/Library/Caches/trivy") - -c, --config string config path (default "trivy.yaml") - -d, --debug debug mode - --insecure allow insecure server connections when using TLS - -q, --quiet suppress progress bar and log output - --timeout duration timeout (default 5m0s) - -v, --version show version + --cache-dir string cache directory (default "/Users/teppei/Library/Caches/trivy") + -c, --config string config path (default "trivy.yaml") + -d, --debug debug mode + --generate-default-config write the default config to trivy-default.yaml + --insecure allow insecure server connections when using TLS + -q, --quiet suppress progress bar and log output + --timeout duration timeout (default 5m0s) + -v, --version show version ``` \ No newline at end of file diff --git a/docs/docs/references/cli/image.md b/docs/docs/references/cli/image.md index e5c7abb5886c..2d345eaf7481 100644 --- a/docs/docs/references/cli/image.md +++ b/docs/docs/references/cli/image.md @@ -34,13 +34,12 @@ Examples: Scan Flags --offline-scan do not issue API requests to identify dependencies --security-checks string comma-separated list of what security issues to detect (vuln,config,secret) (default "vuln,secret") - --skip-dirs string specify the directories where the traversal is skipped - --skip-files string specify the file paths to skip traversal + --skip-dirs strings specify the directories where the traversal is skipped + --skip-files strings specify the file paths to skip traversal Report Flags - --dependency-tree show dependency origin tree (EXPERIMENTAL) --exit-code int specify exit code when any security issues are found - -f, --format string format (table, json, sarif, template, cyclonedx, spdx, spdx-json, github) (default "table") + -f, --format string format (table, json, sarif, template, cyclonedx, spdx, spdx-json, github, cosign-vuln) (default "table") --ignore-policy string specify the Rego file path to evaluate each vulnerability --ignorefile string specify .trivyignore file (default ".trivyignore") --list-all-pkgs enabling the option will output all packages regardless of vulnerability @@ -82,6 +81,10 @@ Misconfiguration Flags Secret Flags --secret-config string specify a path to config file for secret scanning (default "trivy-secret.yaml") +License Flags + --ignored-licenses strings specify a list of license to ignore + --license-full eagerly look for licenses in source code headers and license files + Client/Server Flags --custom-headers strings custom headers in client mode --server string server address in client mode @@ -89,11 +92,12 @@ Client/Server Flags --token-header string specify a header name for token in client/server mode (default "Trivy-Token") Global Flags: - --cache-dir string cache directory (default "/Users/teppei/Library/Caches/trivy") - -c, --config string config path (default "trivy.yaml") - -d, --debug debug mode - --insecure allow insecure server connections when using TLS - -q, --quiet suppress progress bar and log output - --timeout duration timeout (default 5m0s) - -v, --version show version + --cache-dir string cache directory (default "/Users/teppei/Library/Caches/trivy") + -c, --config string config path (default "trivy.yaml") + -d, --debug debug mode + --generate-default-config write the default config to trivy-default.yaml + --insecure allow insecure server connections when using TLS + -q, --quiet suppress progress bar and log output + --timeout duration timeout (default 5m0s) + -v, --version show version ``` diff --git a/docs/docs/references/cli/index.md b/docs/docs/references/cli/index.md index 13b21d06d5bc..b40dc30726ff 100644 --- a/docs/docs/references/cli/index.md +++ b/docs/docs/references/cli/index.md @@ -4,6 +4,7 @@ Trivy has several sub commands, image, fs, repo, client and server. Scanner for vulnerabilities in container images, file systems, and Git repositories, as well as for configuration issues and hard-coded secrets Usage: + trivy [global flags] command [flags] target trivy [command] Examples: @@ -24,7 +25,6 @@ Available Commands: filesystem Scan local filesystem help Help about any command image Scan a container image - kubectl scan kubectl resources kubernetes scan kubernetes cluster module Manage modules plugin Manage plugins @@ -35,15 +35,16 @@ Available Commands: version Print the version Flags: - --cache-dir string cache directory (default "/Users/teppei/Library/Caches/trivy") - -c, --config string config path (default "trivy.yaml") - -d, --debug debug mode - -f, --format string version format (json) - -h, --help help for trivy - --insecure allow insecure server connections when using TLS - -q, --quiet suppress progress bar and log output - --timeout duration timeout (default 5m0s) - -v, --version show version + --cache-dir string cache directory (default "/Users/teppei/Library/Caches/trivy") + -c, --config string config path (default "trivy.yaml") + -d, --debug debug mode + -f, --format string version format (json) + --generate-default-config write the default config to trivy-default.yaml + -h, --help help for trivy + --insecure allow insecure server connections when using TLS + -q, --quiet suppress progress bar and log output + --timeout duration timeout (default 5m0s) + -v, --version show version Use "trivy [command] --help" for more information about a command. ``` diff --git a/docs/docs/references/cli/module.md b/docs/docs/references/cli/module.md index ddd35f33bb52..8f42afe224f5 100644 --- a/docs/docs/references/cli/module.md +++ b/docs/docs/references/cli/module.md @@ -17,11 +17,14 @@ Flags: -h, --help help for module Global Flags: - --cache-dir string cache directory (default "/Users/teppei/Library/Caches/trivy") - -c, --config string config path (default "trivy.yaml") - -d, --debug debug mode - --insecure allow insecure server connections when using TLS - -q, --quiet suppress progress bar and log output - --timeout duration timeout (default 5m0s) - -v, --version show version + --cache-dir string cache directory (default "/Users/teppei/Library/Caches/trivy") + -c, --config string config path (default "trivy.yaml") + -d, --debug debug mode + --generate-default-config write the default config to trivy-default.yaml + --insecure allow insecure server connections when using TLS + -q, --quiet suppress progress bar and log output + --timeout duration timeout (default 5m0s) + -v, --version show version + +Use "trivy module [command] --help" for more information about a command. ``` \ No newline at end of file diff --git a/docs/docs/references/cli/plugin.md b/docs/docs/references/cli/plugin.md index 5a308b28e9f9..35054c856e5e 100644 --- a/docs/docs/references/cli/plugin.md +++ b/docs/docs/references/cli/plugin.md @@ -10,22 +10,25 @@ Aliases: plugin, p Available Commands: - Uninstall uninstall a plugin info Show information about the specified plugin install Install a plugin list List installed plugin run Run a plugin on the fly + uninstall Uninstall a plugin update Update an existing plugin Flags: -h, --help help for plugin Global Flags: - --cache-dir string cache directory (default "/Users/teppei/Library/Caches/trivy") - -c, --config string config path (default "trivy.yaml") - -d, --debug debug mode - --insecure allow insecure server connections when using TLS - -q, --quiet suppress progress bar and log output - --timeout duration timeout (default 5m0s) - -v, --version show version + --cache-dir string cache directory (default "/Users/teppei/Library/Caches/trivy") + -c, --config string config path (default "trivy.yaml") + -d, --debug debug mode + --generate-default-config write the default config to trivy-default.yaml + --insecure allow insecure server connections when using TLS + -q, --quiet suppress progress bar and log output + --timeout duration timeout (default 5m0s) + -v, --version show version + +Use "trivy plugin [command] --help" for more information about a command. ``` \ No newline at end of file diff --git a/docs/docs/references/cli/repo.md b/docs/docs/references/cli/repo.md index 682b524df5e3..a3dc29e9ceb2 100644 --- a/docs/docs/references/cli/repo.md +++ b/docs/docs/references/cli/repo.md @@ -16,13 +16,13 @@ Examples: Scan Flags --offline-scan do not issue API requests to identify dependencies --security-checks string comma-separated list of what security issues to detect (vuln,config,secret) (default "vuln,secret") - --skip-dirs string specify the directories where the traversal is skipped - --skip-files string specify the file paths to skip traversal + --skip-dirs strings specify the directories where the traversal is skipped + --skip-files strings specify the file paths to skip traversal Report Flags --dependency-tree show dependency origin tree (EXPERIMENTAL) --exit-code int specify exit code when any security issues are found - -f, --format string format (table, json, sarif, template, cyclonedx, spdx, spdx-json, github) (default "table") + -f, --format string format (table, json, sarif, template, cyclonedx, spdx, spdx-json, github, cosign-vuln) (default "table") --ignore-policy string specify the Rego file path to evaluate each vulnerability --ignorefile string specify .trivyignore file (default ".trivyignore") --list-all-pkgs enabling the option will output all packages regardless of vulnerability @@ -60,23 +60,28 @@ Misconfiguration Flags Secret Flags --secret-config string specify a path to config file for secret scanning (default "trivy-secret.yaml") +License Flags + --ignored-licenses strings specify a list of license to ignore + --license-full eagerly look for licenses in source code headers and license files + Client/Server Flags --custom-headers strings custom headers in client mode --server string server address in client mode --token string for authentication in client/server mode --token-header string specify a header name for token in client/server mode (default "Trivy-Token") - + Repository Flags --branch string pass the branch name to be scanned --commit string pass the commit hash to be scanned --tag string pass the tag name to be scanned Global Flags: - --cache-dir string cache directory (default "/Users/teppei/Library/Caches/trivy") - -c, --config string config path (default "trivy.yaml") - -d, --debug debug mode - --insecure allow insecure server connections when using TLS - -q, --quiet suppress progress bar and log output - --timeout duration timeout (default 5m0s) - -v, --version show version + --cache-dir string cache directory (default "/Users/teppei/Library/Caches/trivy") + -c, --config string config path (default "trivy.yaml") + -d, --debug debug mode + --generate-default-config write the default config to trivy-default.yaml + --insecure allow insecure server connections when using TLS + -q, --quiet suppress progress bar and log output + --timeout duration timeout (default 5m0s) + -v, --version show version ``` \ No newline at end of file diff --git a/docs/docs/references/cli/rootfs.md b/docs/docs/references/cli/rootfs.md index ba27989de7be..bdba1ffb38b3 100644 --- a/docs/docs/references/cli/rootfs.md +++ b/docs/docs/references/cli/rootfs.md @@ -19,13 +19,13 @@ Examples: Scan Flags --offline-scan do not issue API requests to identify dependencies --security-checks string comma-separated list of what security issues to detect (vuln,config,secret) (default "vuln,secret") - --skip-dirs string specify the directories where the traversal is skipped - --skip-files string specify the file paths to skip traversal + --skip-dirs strings specify the directories where the traversal is skipped + --skip-files strings specify the file paths to skip traversal Report Flags --dependency-tree show dependency origin tree (EXPERIMENTAL) --exit-code int specify exit code when any security issues are found - -f, --format string format (table, json, sarif, template, cyclonedx, spdx, spdx-json, github) (default "table") + -f, --format string format (table, json, sarif, template, cyclonedx, spdx, spdx-json, github, cosign-vuln) (default "table") --ignore-policy string specify the Rego file path to evaluate each vulnerability --ignorefile string specify .trivyignore file (default ".trivyignore") --list-all-pkgs enabling the option will output all packages regardless of vulnerability @@ -63,12 +63,17 @@ Misconfiguration Flags Secret Flags --secret-config string specify a path to config file for secret scanning (default "trivy-secret.yaml") +License Flags + --ignored-licenses strings specify a list of license to ignore + --license-full eagerly look for licenses in source code headers and license files + Global Flags: - --cache-dir string cache directory (default "/Users/teppei/Library/Caches/trivy") - -c, --config string config path (default "trivy.yaml") - -d, --debug debug mode - --insecure allow insecure server connections when using TLS - -q, --quiet suppress progress bar and log output - --timeout duration timeout (default 5m0s) - -v, --version show version + --cache-dir string cache directory (default "/Users/teppei/Library/Caches/trivy") + -c, --config string config path (default "trivy.yaml") + -d, --debug debug mode + --generate-default-config write the default config to trivy-default.yaml + --insecure allow insecure server connections when using TLS + -q, --quiet suppress progress bar and log output + --timeout duration timeout (default 5m0s) + -v, --version show version ``` \ No newline at end of file diff --git a/docs/docs/references/cli/sbom.md b/docs/docs/references/cli/sbom.md index e07fd5f53fab..49f892a3bcdd 100644 --- a/docs/docs/references/cli/sbom.md +++ b/docs/docs/references/cli/sbom.md @@ -17,13 +17,12 @@ Examples: Scan Flags --offline-scan do not issue API requests to identify dependencies --security-checks string comma-separated list of what security issues to detect (vuln,config,secret) (default "vuln,secret") - --skip-dirs string specify the directories where the traversal is skipped - --skip-files string specify the file paths to skip traversal + --skip-dirs strings specify the directories where the traversal is skipped + --skip-files strings specify the file paths to skip traversal Report Flags - --dependency-tree show dependency origin tree (EXPERIMENTAL) --exit-code int specify exit code when any security issues are found - -f, --format string format (table, json, sarif, template, cyclonedx, spdx, spdx-json, github) (default "table") + -f, --format string format (table, json, sarif, template, cyclonedx, spdx, spdx-json, github, cosign-vuln) (default "table") --ignore-policy string specify the Rego file path to evaluate each vulnerability --ignorefile string specify .trivyignore file (default ".trivyignore") --list-all-pkgs enabling the option will output all packages regardless of vulnerability @@ -57,11 +56,12 @@ Client/Server Flags --token-header string specify a header name for token in client/server mode (default "Trivy-Token") Global Flags: - --cache-dir string cache directory (default "/Users/teppei/Library/Caches/trivy") - -c, --config string config path (default "trivy.yaml") - -d, --debug debug mode - --insecure allow insecure server connections when using TLS - -q, --quiet suppress progress bar and log output - --timeout duration timeout (default 5m0s) - -v, --version show version + --cache-dir string cache directory (default "/Users/teppei/Library/Caches/trivy") + -c, --config string config path (default "trivy.yaml") + -d, --debug debug mode + --generate-default-config write the default config to trivy-default.yaml + --insecure allow insecure server connections when using TLS + -q, --quiet suppress progress bar and log output + --timeout duration timeout (default 5m0s) + -v, --version show version ``` \ No newline at end of file diff --git a/docs/docs/references/cli/server.md b/docs/docs/references/cli/server.md index 84805b5d6d0c..c58844cfa205 100644 --- a/docs/docs/references/cli/server.md +++ b/docs/docs/references/cli/server.md @@ -38,11 +38,12 @@ Client/Server Flags --token-header string specify a header name for token in client/server mode (default "Trivy-Token") Global Flags: - --cache-dir string cache directory (default "/Users/teppei/Library/Caches/trivy") - -c, --config string config path (default "trivy.yaml") - -d, --debug debug mode - --insecure allow insecure server connections when using TLS - -q, --quiet suppress progress bar and log output - --timeout duration timeout (default 5m0s) - -v, --version show version + --cache-dir string cache directory (default "/Users/teppei/Library/Caches/trivy") + -c, --config string config path (default "trivy.yaml") + -d, --debug debug mode + --generate-default-config write the default config to trivy-default.yaml + --insecure allow insecure server connections when using TLS + -q, --quiet suppress progress bar and log output + --timeout duration timeout (default 5m0s) + -v, --version show version ``` diff --git a/mkdocs.yml b/mkdocs.yml index 630789bbcba5..38c41bb7be96 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -74,6 +74,7 @@ nav: - SPDX: docs/sbom/spdx.md - Attestation: - SBOM: docs/attestation/sbom.md + - Cosign Vulnerability Scan Record: docs/attestation/vuln.md - Integrations: - Overview: docs/integrations/index.md - GitHub Actions: docs/integrations/github-actions.md diff --git a/pkg/flag/report_flags.go b/pkg/flag/report_flags.go index 585f7f15ad13..e450b993b1ab 100644 --- a/pkg/flag/report_flags.go +++ b/pkg/flag/report_flags.go @@ -26,7 +26,7 @@ var ( ConfigName: "format", Shorthand: "f", Value: report.FormatTable, - Usage: "format (table, json, sarif, template, cyclonedx, spdx, spdx-json, github)", + Usage: "format (table, json, sarif, template, cyclonedx, spdx, spdx-json, github, cosign-vuln)", } ReportFormatFlag = Flag{ Name: "report", diff --git a/pkg/report/predicate/vuln.go b/pkg/report/predicate/vuln.go new file mode 100644 index 000000000000..c1f15edb59de --- /dev/null +++ b/pkg/report/predicate/vuln.go @@ -0,0 +1,89 @@ +package predicate + +import ( + "encoding/json" + "fmt" + "io" + "time" + + "github.com/package-url/packageurl-go" + "golang.org/x/xerrors" + + "github.com/aquasecurity/trivy/pkg/clock" + "github.com/aquasecurity/trivy/pkg/types" +) + +// CosignVulnPredicate represents the Cosign Vulnerability Scan Record. +// CosignVulnPredicate is based on structures in the Cosign repository. +// We defined them ourselves to reduce our dependence on the repository. +// cf. https://github.com/sigstore/cosign/blob/e0547cff64f98585a837a524ff77ff6b47ff5609/pkg/cosign/attestation/attestation.go#L45-L50 +type CosignVulnPredicate struct { + Invocation Invocation `json:"invocation"` + Scanner Scanner `json:"scanner"` + Metadata Metadata `json:"metadata"` +} + +type Invocation struct { + Parameters interface{} `json:"parameters"` + URI string `json:"uri"` + EventID string `json:"event_id"` + BuilderID string `json:"builder.id"` +} + +type DB struct { + URI string `json:"uri"` + Version string `json:"version"` +} + +type Scanner struct { + URI string `json:"uri"` + Version string `json:"version"` + DB DB `json:"db"` + Result types.Report `json:"result"` +} + +type Metadata struct { + ScanStartedOn time.Time `json:"scanStartedOn"` + ScanFinishedOn time.Time `json:"scanFinishedOn"` +} + +type VulnWriter struct { + output io.Writer + version string +} + +func NewVulnWriter(output io.Writer, version string) VulnWriter { + return VulnWriter{ + output: output, + version: version, + } +} + +func (w VulnWriter) Write(report types.Report) error { + + predicate := CosignVulnPredicate{} + + purl := packageurl.NewPackageURL("github", "aquasecurity", "trivy", w.version, nil, "") + predicate.Scanner = Scanner{ + URI: purl.ToString(), + Version: w.version, + Result: report, + } + + now := clock.Now() + predicate.Metadata = Metadata{ + ScanStartedOn: now, + ScanFinishedOn: now, + } + + output, err := json.MarshalIndent(predicate, "", " ") + if err != nil { + return xerrors.Errorf("failed to marshal cosign vulnerability predicate: %w", err) + } + + if _, err = fmt.Fprint(w.output, string(output)); err != nil { + return xerrors.Errorf("failed to write cosign vulnerability predicate: %w", err) + } + return nil + +} diff --git a/pkg/report/predicate/vuln_test.go b/pkg/report/predicate/vuln_test.go new file mode 100644 index 000000000000..d050969b6c15 --- /dev/null +++ b/pkg/report/predicate/vuln_test.go @@ -0,0 +1,112 @@ +package predicate_test + +import ( + "bytes" + "encoding/json" + "testing" + "time" + + dbTypes "github.com/aquasecurity/trivy-db/pkg/types" + "github.com/aquasecurity/trivy-db/pkg/vulnsrc/vulnerability" + "github.com/stretchr/testify/require" + + "github.com/aquasecurity/trivy/pkg/clock" + ftypes "github.com/aquasecurity/trivy/pkg/fanal/types" + "github.com/aquasecurity/trivy/pkg/report/predicate" + "github.com/aquasecurity/trivy/pkg/types" +) + +func TestWriter_Write(t *testing.T) { + tests := []struct { + name string + detectedVulns []types.DetectedVulnerability + want predicate.CosignVulnPredicate + }{ + { + name: "happy path", + detectedVulns: []types.DetectedVulnerability{ + { + VulnerabilityID: "CVE-2020-0001", + PkgName: "foo", + InstalledVersion: "1.2.3", + FixedVersion: "3.4.5", + PrimaryURL: "https://avd.aquasec.com/nvd/cve-2020-0001", + Vulnerability: dbTypes.Vulnerability{ + Title: "foobar", + Description: "baz", + Severity: "HIGH", + VendorSeverity: map[dbTypes.SourceID]dbTypes.Severity{ + vulnerability.NVD: dbTypes.SeverityHigh, + }, + }, + }, + }, + want: predicate.CosignVulnPredicate{ + Scanner: predicate.Scanner{ + URI: "pkg:github/aquasecurity/trivy@dev", + Version: "dev", + Result: types.Report{ + SchemaVersion: 2, + ArtifactName: "alpine:3.14", + ArtifactType: ftypes.ArtifactType(""), + Metadata: types.Metadata{}, + Results: types.Results{ + { + Target: "foojson", + Vulnerabilities: []types.DetectedVulnerability{ + { + VulnerabilityID: "CVE-2020-0001", + PkgName: "foo", + InstalledVersion: "1.2.3", + FixedVersion: "3.4.5", + PrimaryURL: "https://avd.aquasec.com/nvd/cve-2020-0001", + Vulnerability: dbTypes.Vulnerability{ + Title: "foobar", + Description: "baz", + Severity: "HIGH", + }, + }, + }, + }, + }, + }, + }, + Metadata: predicate.Metadata{ + ScanStartedOn: time.Date(2022, time.July, 22, 12, 20, 30, 5, time.UTC), + ScanFinishedOn: time.Date(2022, time.July, 22, 12, 20, 30, 5, time.UTC), + }, + }, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + + inputResults := types.Report{ + SchemaVersion: 2, + ArtifactName: "alpine:3.14", + Results: types.Results{ + { + Target: "foojson", + Vulnerabilities: tt.detectedVulns, + }, + }, + } + + output := bytes.NewBuffer(nil) + + clock.SetFakeTime(t, time.Date(2022, 7, 22, 12, 20, 30, 5, time.UTC)) + writer := predicate.NewVulnWriter(output, "dev") + + err := writer.Write(inputResults) + require.NoError(t, err) + + var got predicate.CosignVulnPredicate + err = json.Unmarshal(output.Bytes(), &got) + require.NoError(t, err, "invalid json written") + + require.Equal(t, tt.want, got, tt.name) + + }) + } +} diff --git a/pkg/report/writer.go b/pkg/report/writer.go index b6d3f9f1a664..2f727ada71a2 100644 --- a/pkg/report/writer.go +++ b/pkg/report/writer.go @@ -5,6 +5,7 @@ import ( "strings" "sync" + "github.com/aquasecurity/trivy/pkg/report/predicate" "github.com/aquasecurity/trivy/pkg/report/table" "golang.org/x/xerrors" @@ -20,14 +21,15 @@ import ( const ( SchemaVersion = 2 - FormatTable = "table" - FormatJSON = "json" - FormatTemplate = "template" - FormatSarif = "sarif" - FormatCycloneDX = "cyclonedx" - FormatSPDX = "spdx" - FormatSPDXJSON = "spdx-json" - FormatGitHub = "github" + FormatTable = "table" + FormatJSON = "json" + FormatTemplate = "template" + FormatSarif = "sarif" + FormatCycloneDX = "cyclonedx" + FormatSPDX = "spdx" + FormatSPDXJSON = "spdx-json" + FormatGitHub = "github" + FormatCosignVuln = "cosign-vuln" ) var ( @@ -89,6 +91,8 @@ func Write(report types.Report, option Option) error { } case FormatSarif: writer = SarifWriter{Output: option.Output, Version: option.AppVersion} + case FormatCosignVuln: + writer = predicate.NewVulnWriter(option.Output, option.AppVersion) default: return xerrors.Errorf("unknown format: %v", option.Format) }