-
Notifications
You must be signed in to change notification settings - Fork 2.3k
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
feat(report): add support for Cosign vulnerability attestation #2567
Merged
Merged
Changes from 20 commits
Commits
Show all changes
21 commits
Select commit
Hold shift + click to select a range
483ca4e
feat(report): add support for Cosign vulnerability predicate
otms61 f3c8f57
add time fields tests
otms61 106599d
refactor
otms61 73c500f
refactor: define CosignVulnPredicate to make the Result field easier …
otms61 3e5a691
refactor: use trivy's clock package
otms61 e1c3d5b
refactor: apploy go mod tidy
otms61 ce515d3
refactor: add a comment to CosignVulnPredicate
otms61 f9cb8a2
fix: fix lint error
otms61 cdd986d
fix: remove unintended modifications of go.mod
otms61 cda3cb5
fix: fix word
otms61 8a63658
docs: add cosign vulnerability doc
otms61 fa1b583
docs: remove a comment out section
otms61 cbff270
Merge branch 'main' into cosign_vuln
otms61 6dad54a
docs: add a description of how to create an attestation
otms61 0add976
refactor: add a comment about the PR to Cosign
otms61 b02e159
refactor: use require package and rename variable names
otms61 1e37c6d
docs: add keyless signing section
otms61 c443551
refactor: rename types and functions
otms61 ab9bcaf
refactor: improve the comment for CosignVulnPredicate
otms61 7aaa34c
refactor: align words with Cosign documentation
otms61 f50124a
docs: update cli references
otms61 File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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 | ||
``` | ||
|
||
<details> | ||
<summary>Result</summary> | ||
|
||
```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" | ||
} | ||
} | ||
``` | ||
|
||
</details> | ||
|
||
## 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 <IMAGE> | ||
$ cosign attest --key /path/to/cosign.key --type vuln --predicate vuln.json <IMAGE> | ||
``` | ||
|
||
Then, you can verify attestations on the image. | ||
|
||
``` | ||
$ cosign verify-attestation --key /path/to/cosign.pub <IMAGE> | ||
``` | ||
|
||
### 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 <IMAGE> | ||
$ COSIGN_EXPERIMENTAL=1 cosign attest --type vuln --predicate vuln.json <IMAGE> | ||
``` | ||
|
||
You can verify attestations. | ||
|
||
``` | ||
$ COSIGN_EXPERIMENTAL=1 cosign verify-attestation <IMAGE> | ||
``` | ||
|
||
[vuln-attest-spec]: https://github.com/sigstore/cosign/blob/95b74db89941e8ec85e768f639efd4d948db06cd/specs/COSIGN_VULN_ATTESTATION_SPEC.md |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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 | ||
|
||
} |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can we add a keyless section?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Alright. I've added a keyless signing section.