mirror of
https://github.com/aquasecurity/trivy.git
synced 2025-12-22 07:10:41 -08:00
feat: add secret scanning (#1901)
Co-authored-by: VaismanLior <97836016+VaismanLior@users.noreply.github.com> Co-authored-by: AMF <work@afdesk.com>
This commit is contained in:
141
docs/docs/secret/configuration.md
Normal file
141
docs/docs/secret/configuration.md
Normal file
@@ -0,0 +1,141 @@
|
|||||||
|
# Configuration
|
||||||
|
Trivy tries to load `trivy-secret.yaml` in the current directory by default.
|
||||||
|
If the file doesn't exist, only builtin rules are used.
|
||||||
|
You can customize the config file name via the `--secret-config` flag.
|
||||||
|
|
||||||
|
## Custom Rules
|
||||||
|
Trivy allows defining custom rules. You can see an example.
|
||||||
|
|
||||||
|
``` yaml
|
||||||
|
rules:
|
||||||
|
- id: rule1
|
||||||
|
category: general
|
||||||
|
title: Generic Rule
|
||||||
|
severity: HIGH
|
||||||
|
path:
|
||||||
|
- .*\.sh
|
||||||
|
keywords:
|
||||||
|
- secret
|
||||||
|
regex: (?i)(?P<key>(secret))(=|:).{0,5}['"](?P<secret>[0-9a-zA-Z\-_=]{8,64})['"]
|
||||||
|
secret-group-name: secret
|
||||||
|
allow-rules:
|
||||||
|
- id: skip-text
|
||||||
|
description: skip text files
|
||||||
|
path: .*\.txt
|
||||||
|
```
|
||||||
|
|
||||||
|
`id` (required)
|
||||||
|
: - Unique identifier for this rule.
|
||||||
|
|
||||||
|
`category` (required)
|
||||||
|
: - String used for metadata and reporting purposes.
|
||||||
|
|
||||||
|
`title` (required)
|
||||||
|
: - Short human-readable title of the rule.
|
||||||
|
|
||||||
|
`severity` (required)
|
||||||
|
: - How critical this rule is.
|
||||||
|
- Allowed values:
|
||||||
|
- CRITICAL
|
||||||
|
- HIGH
|
||||||
|
- MEDIUM
|
||||||
|
- LOW
|
||||||
|
|
||||||
|
`regex` (required)
|
||||||
|
: - Golang regular expression used to detect secrets.
|
||||||
|
|
||||||
|
`path` (optional)
|
||||||
|
: - Golang regular expression used to match paths.
|
||||||
|
|
||||||
|
`keywords` (optional, recommended)
|
||||||
|
: - Keywords are used for pre-regex check filtering.
|
||||||
|
- Rules that contain keywords will perform a quick string compare check to make sure the keyword(s) are in the content being scanned.
|
||||||
|
- Ideally these values should either be part of the identifier or unique strings specific to the rule's regex.
|
||||||
|
- It is recommended to define for better performance.
|
||||||
|
|
||||||
|
`allow-rules` (optional)
|
||||||
|
: - Allow rules for a single rule to reduce false positives with known secrets.
|
||||||
|
- The details are below.
|
||||||
|
|
||||||
|
## Allow Rules
|
||||||
|
If the detected secret is matched with the specified `regex`, then that secret will be skipped and not detected.
|
||||||
|
The same logic applies for `path`.
|
||||||
|
|
||||||
|
`allow-rules` can be defined globally and per each rule. The fields are the same.
|
||||||
|
|
||||||
|
``` yaml
|
||||||
|
rules:
|
||||||
|
- id: rule1
|
||||||
|
category: general
|
||||||
|
title: Generic Rule
|
||||||
|
severity: HIGH
|
||||||
|
regex: (?i)(?P<key>(secret))(=|:).{0,5}['"](?P<secret>[0-9a-zA-Z\-_=]{8,64})['"]
|
||||||
|
allow-rules:
|
||||||
|
- id: skip-text
|
||||||
|
description: skip text files
|
||||||
|
path: .*\.txt
|
||||||
|
allow-rules:
|
||||||
|
- id: social-security-number
|
||||||
|
description: skip social security number
|
||||||
|
regex: 219-09-9999
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
`id` (required)
|
||||||
|
: - Unique identifier for this allow rule.
|
||||||
|
|
||||||
|
`description` (optional)
|
||||||
|
: - Short human-readable description of this allow rule.
|
||||||
|
|
||||||
|
`regex` (optional)
|
||||||
|
: - Golang regular expression used to allow detected secrets.
|
||||||
|
- `regex` or `path` must be specified.
|
||||||
|
|
||||||
|
`path` (optional)
|
||||||
|
: - Golang regular expression used to allow matched paths.
|
||||||
|
- `regex` or `path` must be specified.
|
||||||
|
|
||||||
|
## Disable Rules
|
||||||
|
Trivy offers builtin rules and allow rules, but you may want to disable some of them.
|
||||||
|
For example, you don't use Slack, so Slack doesn't have to be scanned.
|
||||||
|
You can specify `slack-access-token` and `slack-web-hook` in `disable-rules` so that those rules will be disabled for less false positives.
|
||||||
|
|
||||||
|
Markdown files are ignored by default, but you may want to scan markdown files as well.
|
||||||
|
You can disable the allow list by adding `markdown` to `disable-allow-rules`.
|
||||||
|
|
||||||
|
You can see a full list of rule IDs [here][builtin]. Allow rule IDs are below in the file.
|
||||||
|
|
||||||
|
``` yaml
|
||||||
|
disable-rules:
|
||||||
|
- slack-access-token
|
||||||
|
- slack-web-hook
|
||||||
|
disable-allow-rules:
|
||||||
|
- markdown
|
||||||
|
```
|
||||||
|
|
||||||
|
## Example
|
||||||
|
|
||||||
|
``` yaml
|
||||||
|
$ cat trivy-secret.yaml
|
||||||
|
rules:
|
||||||
|
- id: rule1
|
||||||
|
category: general
|
||||||
|
title: Generic Rule
|
||||||
|
severity: HIGH
|
||||||
|
regex: (?i)(?P<key>(secret))(=|:).{0,5}['"](?P<secret>[0-9a-zA-Z\-_=]{8,64})['"]
|
||||||
|
allow-rules:
|
||||||
|
- id: skip-text
|
||||||
|
description: skip text files
|
||||||
|
path: .*\.txt
|
||||||
|
allow-rules:
|
||||||
|
- id: social-security-number
|
||||||
|
description: skip social security number
|
||||||
|
regex: 219-09-9999
|
||||||
|
disable-rules:
|
||||||
|
- slack-access-token
|
||||||
|
- slack-web-hook
|
||||||
|
disable-allow-rules:
|
||||||
|
- markdown
|
||||||
|
```
|
||||||
|
|
||||||
|
[builtin]: https://github.com/aquasecurity/fanal/blob/main/secret/builtin.go
|
||||||
100
docs/docs/secret/scanning.md
Normal file
100
docs/docs/secret/scanning.md
Normal file
@@ -0,0 +1,100 @@
|
|||||||
|
# Secret Scanning
|
||||||
|
|
||||||
|
Trivy scans any container image, filesystem and git repository to detect exposed secrets like passwords, api keys, and tokens.
|
||||||
|
Secret scanning is enabled by default.
|
||||||
|
|
||||||
|
Trivy will scan every plaintext file, according to builtin rules or configuration. There are plenty of builtin rules:
|
||||||
|
|
||||||
|
- AWS access key
|
||||||
|
- GCP service account
|
||||||
|
- GitHub personal access token
|
||||||
|
- GitLab personal access token
|
||||||
|
- Slack access token
|
||||||
|
- etc.
|
||||||
|
|
||||||
|
You can see a full list of builtin rules [here][builtin].
|
||||||
|
|
||||||
|
|
||||||
|
## Quick start
|
||||||
|
This section shows how to scan secrets in container image and filesystem. Other subcommands should be the same.
|
||||||
|
|
||||||
|
### Container image
|
||||||
|
Specify an image name.
|
||||||
|
|
||||||
|
``` shell
|
||||||
|
$ trivy image myimage:1.0.0
|
||||||
|
2022-04-21T18:56:44.099+0300 INFO Detected OS: alpine
|
||||||
|
2022-04-21T18:56:44.099+0300 INFO Detecting Alpine vulnerabilities...
|
||||||
|
2022-04-21T18:56:44.101+0300 INFO Number of language-specific files: 0
|
||||||
|
|
||||||
|
myimage:1.0.0 (alpine 3.15.0)
|
||||||
|
=============================
|
||||||
|
Total: 6 (UNKNOWN: 0, LOW: 0, MEDIUM: 0, HIGH: 0, CRITICAL: 2)
|
||||||
|
|
||||||
|
+--------------+------------------+----------+-------------------+---------------+---------------------------------------+
|
||||||
|
| LIBRARY | VULNERABILITY ID | SEVERITY | INSTALLED VERSION | FIXED VERSION | TITLE |
|
||||||
|
+--------------+------------------+----------+-------------------+---------------+---------------------------------------+
|
||||||
|
| busybox | CVE-2022-28391 | CRITICAL | 1.34.1-r3 | 1.34.1-r5 | CVE-2022-28391 affecting |
|
||||||
|
| | | | | | package busybox 1.35.0 |
|
||||||
|
| | | | | | -->avd.aquasec.com/nvd/cve-2022-28391 |
|
||||||
|
+--------------+------------------| |-------------------+---------------+---------------------------------------+
|
||||||
|
| ssl_client | CVE-2022-28391 | | 1.34.1-r3 | 1.34.1-r5 | CVE-2022-28391 affecting |
|
||||||
|
| | | | | | package busybox 1.35.0 |
|
||||||
|
| | | | | | -->avd.aquasec.com/nvd/cve-2022-28391 |
|
||||||
|
+--------------+------------------+----------+-------------------+---------------+---------------------------------------+
|
||||||
|
|
||||||
|
app/secret.sh (secrets)
|
||||||
|
=======================
|
||||||
|
Total: 1 (UNKNOWN: 0, LOW: 0, MEDIUM: 0, HIGH: 0, CRITICAL: 1)
|
||||||
|
|
||||||
|
+----------+-------------------+----------+---------+--------------------------------+
|
||||||
|
| CATEGORY | DESCRIPTION | SEVERITY | LINE NO | MATCH |
|
||||||
|
+----------+-------------------+----------+---------+--------------------------------+
|
||||||
|
| AWS | AWS Access Key ID | CRITICAL | 10 | export AWS_ACCESS_KEY_ID=***** |
|
||||||
|
+----------+-------------------+----------+---------+--------------------------------+
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
!!! tip
|
||||||
|
Trivy tries to detect a base image and skip those layers for secret scanning.
|
||||||
|
A base image usually contains a lot of files and makes secret scanning much slower.
|
||||||
|
If a secret is not detected properly, you can see base layers with the `--debug` flag.
|
||||||
|
|
||||||
|
### Filesystem
|
||||||
|
|
||||||
|
``` shell
|
||||||
|
$ trivy fs /path/to/your_project
|
||||||
|
...(snip)...
|
||||||
|
|
||||||
|
certs/key.pem (secrets)
|
||||||
|
========================
|
||||||
|
Total: 1 (UNKNOWN: 0, LOW: 0, MEDIUM: 0, HIGH: 1, CRITICAL: 0)
|
||||||
|
|
||||||
|
+----------------------+------------------------+----------+---------+---------------------------------+
|
||||||
|
| CATEGORY | DESCRIPTION | SEVERITY | LINE NO | MATCH |
|
||||||
|
+----------------------+------------------------+----------+---------+---------------------------------+
|
||||||
|
| AsymmetricPrivateKey | Asymmetric Private Key | HIGH | 1 | -----BEGIN RSA PRIVATE KEY----- |
|
||||||
|
+----------------------+------------------------+----------+---------+---------------------------------+
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
!!! tip
|
||||||
|
Your project may have some secrets for testing. You can skip them with `--skip-dirs` or `--skip-files`.
|
||||||
|
We would recommend specifying these options so that the secret scanning can be faster if those files don't need to be scanned.
|
||||||
|
Also, you can specify paths to be allowed in a configuration file. See the detail [here][configuration].
|
||||||
|
|
||||||
|
## Configuration
|
||||||
|
Trivy has a set of builtin rules for secret scanning, which can be extended or modified by a configuration file.
|
||||||
|
|
||||||
|
If you don't need secret scanning, you can disable it via the `--security-checks` flag.
|
||||||
|
|
||||||
|
```shell
|
||||||
|
$ trivy image --security-checks vuln alpine:3.15
|
||||||
|
```
|
||||||
|
|
||||||
|
## Credit
|
||||||
|
This feature is inspired by [gitleaks][gitleaks].
|
||||||
|
|
||||||
|
[builtin]: https://github.com/aquasecurity/fanal/blob/main/secret/builtin.go
|
||||||
|
[configuration]: ./configuration.md
|
||||||
|
[gitleaks]: https://github.com/zricethezav/gitleaks
|
||||||
@@ -174,7 +174,7 @@ The same image is hosted on [Amazon ECR Public][ecr] as well.
|
|||||||
docker pull public.ecr.aws/aquasecurity/trivy:{{ git.tag[1:] }}
|
docker pull public.ecr.aws/aquasecurity/trivy:{{ git.tag[1:] }}
|
||||||
```
|
```
|
||||||
## Helm
|
## Helm
|
||||||
### Installing from the the Aqua Chart Repository
|
### Installing from the Aqua Chart Repository
|
||||||
|
|
||||||
```
|
```
|
||||||
helm repo add aquasecurity https://aquasecurity.github.io/helm-charts/
|
helm repo add aquasecurity https://aquasecurity.github.io/helm-charts/
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
# Overview
|
# Overview
|
||||||
|
|
||||||
Trivy detects two types of security issues:
|
Trivy detects three types of security issues:
|
||||||
|
|
||||||
- [Vulnerabilities][vuln]
|
- [Vulnerabilities][vuln]
|
||||||
- [OS packages][os] (Alpine, Red Hat Universal Base Image, Red Hat Enterprise Linux, CentOS, AlmaLinux, Rocky Linux, CBL-Mariner, Oracle Linux, Debian, Ubuntu, Amazon Linux, openSUSE Leap, SUSE Enterprise Linux, Photon OS and Distroless)
|
- [OS packages][os] (Alpine, Red Hat Universal Base Image, Red Hat Enterprise Linux, CentOS, AlmaLinux, Rocky Linux, CBL-Mariner, Oracle Linux, Debian, Ubuntu, Amazon Linux, openSUSE Leap, SUSE Enterprise Linux, Photon OS and Distroless)
|
||||||
@@ -11,6 +11,11 @@ Trivy detects two types of security issues:
|
|||||||
- Terraform
|
- Terraform
|
||||||
- CloudFormation
|
- CloudFormation
|
||||||
- more coming soon
|
- more coming soon
|
||||||
|
- [Secrets][secret]
|
||||||
|
- AWS access key
|
||||||
|
- GCP service account
|
||||||
|
- GitHub personal access token
|
||||||
|
- etc.
|
||||||
|
|
||||||
Trivy can scan three different artifacts:
|
Trivy can scan three different artifacts:
|
||||||
|
|
||||||
@@ -27,6 +32,8 @@ See [Integrations][integrations] for details.
|
|||||||
|
|
||||||
[misconf]: ../docs/misconfiguration/index.md
|
[misconf]: ../docs/misconfiguration/index.md
|
||||||
|
|
||||||
|
[secret]: ../docs/secret/scanning.md
|
||||||
|
|
||||||
[container]: ../docs/vulnerability/scanning/image.md
|
[container]: ../docs/vulnerability/scanning/image.md
|
||||||
[rootfs]: ../docs/vulnerability/scanning/rootfs.md
|
[rootfs]: ../docs/vulnerability/scanning/rootfs.md
|
||||||
[filesystem]: ../docs/vulnerability/scanning/filesystem.md
|
[filesystem]: ../docs/vulnerability/scanning/filesystem.md
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
# Quick Start
|
# Quick Start
|
||||||
|
|
||||||
## Scan image for vulnerabilities
|
## Scan image for vulnerabilities and secrets
|
||||||
|
|
||||||
Simply specify an image name (and a tag).
|
Simply specify an image name (and a tag).
|
||||||
|
|
||||||
@@ -10,32 +10,40 @@ $ trivy image [YOUR_IMAGE_NAME]
|
|||||||
|
|
||||||
For example:
|
For example:
|
||||||
|
|
||||||
```
|
``` shell
|
||||||
$ trivy image python:3.4-alpine
|
$ trivy image myimage:1.0.0
|
||||||
```
|
2022-04-21T18:56:44.099+0300 INFO Detected OS: alpine
|
||||||
|
2022-04-21T18:56:44.099+0300 INFO Detecting Alpine vulnerabilities...
|
||||||
|
2022-04-21T18:56:44.101+0300 INFO Number of language-specific files: 0
|
||||||
|
|
||||||
<details>
|
myimage:1.0.0 (alpine 3.15.0)
|
||||||
<summary>Result</summary>
|
=============================
|
||||||
|
Total: 6 (UNKNOWN: 0, LOW: 0, MEDIUM: 0, HIGH: 0, CRITICAL: 2)
|
||||||
|
|
||||||
```
|
+--------------+------------------+----------+-------------------+---------------+---------------------------------------+
|
||||||
2019-05-16T01:20:43.180+0900 INFO Updating vulnerability database...
|
|
||||||
2019-05-16T01:20:53.029+0900 INFO Detecting Alpine vulnerabilities...
|
|
||||||
|
|
||||||
python:3.4-alpine3.9 (alpine 3.9.2)
|
|
||||||
===================================
|
|
||||||
Total: 1 (UNKNOWN: 0, LOW: 0, MEDIUM: 1, HIGH: 0, CRITICAL: 0)
|
|
||||||
|
|
||||||
+---------+------------------+----------+-------------------+---------------+--------------------------------+
|
|
||||||
| LIBRARY | VULNERABILITY ID | SEVERITY | INSTALLED VERSION | FIXED VERSION | TITLE |
|
| LIBRARY | VULNERABILITY ID | SEVERITY | INSTALLED VERSION | FIXED VERSION | TITLE |
|
||||||
+---------+------------------+----------+-------------------+---------------+--------------------------------+
|
+--------------+------------------+----------+-------------------+---------------+---------------------------------------+
|
||||||
| openssl | CVE-2019-1543 | MEDIUM | 1.1.1a-r1 | 1.1.1b-r1 | openssl: ChaCha20-Poly1305 |
|
| busybox | CVE-2022-28391 | CRITICAL | 1.34.1-r3 | 1.34.1-r5 | CVE-2022-28391 affecting |
|
||||||
| | | | | | with long nonces |
|
| | | | | | package busybox 1.35.0 |
|
||||||
+---------+------------------+----------+-------------------+---------------+--------------------------------+
|
| | | | | | -->avd.aquasec.com/nvd/cve-2022-28391 |
|
||||||
|
+--------------+------------------| |-------------------+---------------+---------------------------------------+
|
||||||
|
| ssl_client | CVE-2022-28391 | | 1.34.1-r3 | 1.34.1-r5 | CVE-2022-28391 affecting |
|
||||||
|
| | | | | | package busybox 1.35.0 |
|
||||||
|
| | | | | | -->avd.aquasec.com/nvd/cve-2022-28391 |
|
||||||
|
+--------------+------------------+----------+-------------------+---------------+---------------------------------------+
|
||||||
|
|
||||||
|
app/deploy.sh (secrets)
|
||||||
|
=======================
|
||||||
|
Total: 1 (UNKNOWN: 0, LOW: 0, MEDIUM: 0, HIGH: 0, CRITICAL: 1)
|
||||||
|
|
||||||
|
+----------+-------------------+----------+---------+--------------------------------+
|
||||||
|
| CATEGORY | DESCRIPTION | SEVERITY | LINE NO | MATCH |
|
||||||
|
+----------+-------------------+----------+---------+--------------------------------+
|
||||||
|
| AWS | AWS Access Key ID | CRITICAL | 10 | export AWS_ACCESS_KEY_ID=***** |
|
||||||
|
+----------+-------------------+----------+---------+--------------------------------+
|
||||||
```
|
```
|
||||||
|
|
||||||
</details>
|
For more details, see [vulnerability][vulnerability] and [secret][secret] pages.
|
||||||
|
|
||||||
For more details, see [here][vulnerability].
|
|
||||||
|
|
||||||
## Scan directory for misconfigurations
|
## Scan directory for misconfigurations
|
||||||
|
|
||||||
@@ -47,16 +55,10 @@ $ trivy config [YOUR_IAC_DIR]
|
|||||||
|
|
||||||
For example:
|
For example:
|
||||||
|
|
||||||
```
|
``` shell
|
||||||
$ ls build/
|
$ ls build/
|
||||||
Dockerfile
|
Dockerfile
|
||||||
$ trivy config ./build
|
$ trivy config ./build
|
||||||
```
|
|
||||||
|
|
||||||
<details>
|
|
||||||
<summary>Result</summary>
|
|
||||||
|
|
||||||
```
|
|
||||||
2021-07-09T10:06:29.188+0300 INFO Need to update the built-in policies
|
2021-07-09T10:06:29.188+0300 INFO Need to update the built-in policies
|
||||||
2021-07-09T10:06:29.188+0300 INFO Downloading the built-in policies...
|
2021-07-09T10:06:29.188+0300 INFO Downloading the built-in policies...
|
||||||
2021-07-09T10:06:30.520+0300 INFO Detected config files: 1
|
2021-07-09T10:06:30.520+0300 INFO Detected config files: 1
|
||||||
@@ -75,9 +77,8 @@ Failures: 1 (UNKNOWN: 0, LOW: 0, MEDIUM: 0, HIGH: 1, CRITICAL: 0)
|
|||||||
+---------------------------+------------+----------------------+----------+------------------------------------------+
|
+---------------------------+------------+----------------------+----------+------------------------------------------+
|
||||||
```
|
```
|
||||||
|
|
||||||
</details>
|
|
||||||
|
|
||||||
For more details, see [here][misconf].
|
For more details, see [here][misconf].
|
||||||
|
|
||||||
[vulnerability]: ../docs/vulnerability/scanning/index.md
|
[vulnerability]: ../docs/vulnerability/scanning/index.md
|
||||||
[misconf]: ../docs/misconfiguration/index.md
|
[misconf]: ../docs/misconfiguration/index.md
|
||||||
|
[secret]: ../docs/secret/scanning.md
|
||||||
|
|||||||
@@ -5,8 +5,8 @@
|
|||||||
"elements": [
|
"elements": [
|
||||||
{
|
{
|
||||||
"type": "rectangle",
|
"type": "rectangle",
|
||||||
"version": 476,
|
"version": 787,
|
||||||
"versionNonce": 916788210,
|
"versionNonce": 1318065410,
|
||||||
"isDeleted": false,
|
"isDeleted": false,
|
||||||
"id": "BkXuq_6BxgqZGZWc8oCtu",
|
"id": "BkXuq_6BxgqZGZWc8oCtu",
|
||||||
"fillStyle": "hachure",
|
"fillStyle": "hachure",
|
||||||
@@ -15,21 +15,24 @@
|
|||||||
"roughness": 1,
|
"roughness": 1,
|
||||||
"opacity": 100,
|
"opacity": 100,
|
||||||
"angle": 0,
|
"angle": 0,
|
||||||
"x": 599.211669921875,
|
"x": 599.653076171875,
|
||||||
"y": 376.32061767578125,
|
"y": 734.7542114257812,
|
||||||
"strokeColor": "#000000",
|
"strokeColor": "#000000",
|
||||||
"backgroundColor": "#fd7e14",
|
"backgroundColor": "#fd7e14",
|
||||||
"width": 1076.4584350585938,
|
"width": 1227.452155219184,
|
||||||
"height": 151.39703369140625,
|
"height": 151.39703369140625,
|
||||||
"seed": 1632394695,
|
"seed": 1632394695,
|
||||||
"groupIds": [],
|
"groupIds": [],
|
||||||
"strokeSharpness": "sharp",
|
"strokeSharpness": "sharp",
|
||||||
"boundElementIds": []
|
"boundElements": [],
|
||||||
|
"updated": 1650567161407,
|
||||||
|
"link": null,
|
||||||
|
"locked": false
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"type": "text",
|
"type": "text",
|
||||||
"version": 423,
|
"version": 653,
|
||||||
"versionNonce": 931200686,
|
"versionNonce": 1863936606,
|
||||||
"isDeleted": false,
|
"isDeleted": false,
|
||||||
"id": "YQURTHNPSe05RPSlYRcok",
|
"id": "YQURTHNPSe05RPSlYRcok",
|
||||||
"fillStyle": "hachure",
|
"fillStyle": "hachure",
|
||||||
@@ -38,8 +41,8 @@
|
|||||||
"roughness": 1,
|
"roughness": 1,
|
||||||
"opacity": 100,
|
"opacity": 100,
|
||||||
"angle": 0,
|
"angle": 0,
|
||||||
"x": 1119.1937866210938,
|
"x": 1137.7821926540798,
|
||||||
"y": 403.56756591796875,
|
"y": 764.0207858615452,
|
||||||
"strokeColor": "#000000",
|
"strokeColor": "#000000",
|
||||||
"backgroundColor": "transparent",
|
"backgroundColor": "transparent",
|
||||||
"width": 88,
|
"width": 88,
|
||||||
@@ -47,18 +50,23 @@
|
|||||||
"seed": 891391049,
|
"seed": 891391049,
|
||||||
"groupIds": [],
|
"groupIds": [],
|
||||||
"strokeSharpness": "sharp",
|
"strokeSharpness": "sharp",
|
||||||
"boundElementIds": [],
|
"boundElements": [],
|
||||||
|
"updated": 1650567336690,
|
||||||
|
"link": null,
|
||||||
|
"locked": false,
|
||||||
"fontSize": 36,
|
"fontSize": 36,
|
||||||
"fontFamily": 1,
|
"fontFamily": 1,
|
||||||
"text": "Trivy",
|
"text": "Trivy",
|
||||||
"baseline": 32,
|
"baseline": 32,
|
||||||
"textAlign": "left",
|
"textAlign": "left",
|
||||||
"verticalAlign": "top"
|
"verticalAlign": "top",
|
||||||
|
"containerId": null,
|
||||||
|
"originalText": "Trivy"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"type": "text",
|
"type": "text",
|
||||||
"version": 758,
|
"version": 1139,
|
||||||
"versionNonce": 813811122,
|
"versionNonce": 1994750018,
|
||||||
"isDeleted": false,
|
"isDeleted": false,
|
||||||
"id": "6dpF2EyZBtYgO6MrvGj0-",
|
"id": "6dpF2EyZBtYgO6MrvGj0-",
|
||||||
"fillStyle": "hachure",
|
"fillStyle": "hachure",
|
||||||
@@ -67,27 +75,32 @@
|
|||||||
"roughness": 1,
|
"roughness": 1,
|
||||||
"opacity": 100,
|
"opacity": 100,
|
||||||
"angle": 0,
|
"angle": 0,
|
||||||
"x": 922.1328735351562,
|
"x": 900.5941772460938,
|
||||||
"y": 470.18975830078125,
|
"y": 819.7337171766493,
|
||||||
"strokeColor": "#000000",
|
"strokeColor": "#000000",
|
||||||
"backgroundColor": "transparent",
|
"backgroundColor": "transparent",
|
||||||
"width": 507,
|
"width": 612,
|
||||||
"height": 35,
|
"height": 36,
|
||||||
"seed": 687997545,
|
"seed": 687997545,
|
||||||
"groupIds": [],
|
"groupIds": [],
|
||||||
"strokeSharpness": "sharp",
|
"strokeSharpness": "sharp",
|
||||||
"boundElementIds": [],
|
"boundElements": [],
|
||||||
|
"updated": 1650567334181,
|
||||||
|
"link": null,
|
||||||
|
"locked": false,
|
||||||
"fontSize": 28,
|
"fontSize": 28,
|
||||||
"fontFamily": 1,
|
"fontFamily": 1,
|
||||||
"text": "Vulnerability/Misconfiguration Scanner",
|
"text": "Vulnerability/Misconfiguration/Secret Scanner",
|
||||||
"baseline": 25,
|
"baseline": 25,
|
||||||
"textAlign": "left",
|
"textAlign": "left",
|
||||||
"verticalAlign": "top"
|
"verticalAlign": "top",
|
||||||
|
"containerId": null,
|
||||||
|
"originalText": "Vulnerability/Misconfiguration/Secret Scanner"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"type": "rectangle",
|
"type": "rectangle",
|
||||||
"version": 595,
|
"version": 805,
|
||||||
"versionNonce": 1705780846,
|
"versionNonce": 1609410334,
|
||||||
"isDeleted": false,
|
"isDeleted": false,
|
||||||
"id": "cpnTMy7L2AUg9IDJppF4H",
|
"id": "cpnTMy7L2AUg9IDJppF4H",
|
||||||
"fillStyle": "hachure",
|
"fillStyle": "hachure",
|
||||||
@@ -96,21 +109,24 @@
|
|||||||
"roughness": 1,
|
"roughness": 1,
|
||||||
"opacity": 100,
|
"opacity": 100,
|
||||||
"angle": 0,
|
"angle": 0,
|
||||||
"x": 597.4796142578125,
|
"x": 600.9835205078125,
|
||||||
"y": 258.9286651611328,
|
"y": 627.2060089111328,
|
||||||
"strokeColor": "#000000",
|
"strokeColor": "#000000",
|
||||||
"backgroundColor": "#fab005",
|
"backgroundColor": "#fab005",
|
||||||
"width": 349.1224975585937,
|
"width": 298.6342163085937,
|
||||||
"height": 103.28388977050778,
|
"height": 96.74092102050778,
|
||||||
"seed": 77164935,
|
"seed": 77164935,
|
||||||
"groupIds": [],
|
"groupIds": [],
|
||||||
"strokeSharpness": "sharp",
|
"strokeSharpness": "sharp",
|
||||||
"boundElementIds": []
|
"boundElements": [],
|
||||||
|
"updated": 1650567155021,
|
||||||
|
"link": null,
|
||||||
|
"locked": false
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"type": "text",
|
"type": "text",
|
||||||
"version": 921,
|
"version": 1011,
|
||||||
"versionNonce": 929185650,
|
"versionNonce": 477782466,
|
||||||
"isDeleted": false,
|
"isDeleted": false,
|
||||||
"id": "9-blmNVtLesthMSY_f60t",
|
"id": "9-blmNVtLesthMSY_f60t",
|
||||||
"fillStyle": "hachure",
|
"fillStyle": "hachure",
|
||||||
@@ -119,8 +135,8 @@
|
|||||||
"roughness": 1,
|
"roughness": 1,
|
||||||
"opacity": 100,
|
"opacity": 100,
|
||||||
"angle": 0,
|
"angle": 0,
|
||||||
"x": 655.6057739257812,
|
"x": 628.7854614257812,
|
||||||
"y": 292.4844055175781,
|
"y": 658.9062805175781,
|
||||||
"strokeColor": "#000000",
|
"strokeColor": "#000000",
|
||||||
"backgroundColor": "transparent",
|
"backgroundColor": "transparent",
|
||||||
"width": 238,
|
"width": 238,
|
||||||
@@ -128,18 +144,23 @@
|
|||||||
"seed": 860091815,
|
"seed": 860091815,
|
||||||
"groupIds": [],
|
"groupIds": [],
|
||||||
"strokeSharpness": "sharp",
|
"strokeSharpness": "sharp",
|
||||||
"boundElementIds": [],
|
"boundElements": [],
|
||||||
|
"updated": 1650567155021,
|
||||||
|
"link": null,
|
||||||
|
"locked": false,
|
||||||
"fontSize": 28,
|
"fontSize": 28,
|
||||||
"fontFamily": 1,
|
"fontFamily": 1,
|
||||||
"text": "Container Images",
|
"text": "Container Images",
|
||||||
"baseline": 25,
|
"baseline": 25,
|
||||||
"textAlign": "center",
|
"textAlign": "center",
|
||||||
"verticalAlign": "top"
|
"verticalAlign": "top",
|
||||||
|
"containerId": null,
|
||||||
|
"originalText": "Container Images"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"type": "rectangle",
|
"type": "rectangle",
|
||||||
"version": 853,
|
"version": 1051,
|
||||||
"versionNonce": 377039022,
|
"versionNonce": 1210520414,
|
||||||
"isDeleted": false,
|
"isDeleted": false,
|
||||||
"id": "gugZxhi7ThlcjWY_MFO7q",
|
"id": "gugZxhi7ThlcjWY_MFO7q",
|
||||||
"fillStyle": "hachure",
|
"fillStyle": "hachure",
|
||||||
@@ -148,21 +169,24 @@
|
|||||||
"roughness": 1,
|
"roughness": 1,
|
||||||
"opacity": 100,
|
"opacity": 100,
|
||||||
"angle": 0,
|
"angle": 0,
|
||||||
"x": 955.929443359375,
|
"x": 911.257568359375,
|
||||||
"y": 262.11351776123047,
|
"y": 625.7697677612305,
|
||||||
"strokeColor": "#000000",
|
"strokeColor": "#000000",
|
||||||
"backgroundColor": "#be4bdb",
|
"backgroundColor": "#be4bdb",
|
||||||
"width": 359.85211181640625,
|
"width": 452.44976806640636,
|
||||||
"height": 99.05134582519533,
|
"height": 99.05134582519533,
|
||||||
"seed": 1232790121,
|
"seed": 1232790121,
|
||||||
"groupIds": [],
|
"groupIds": [],
|
||||||
"strokeSharpness": "sharp",
|
"strokeSharpness": "sharp",
|
||||||
"boundElementIds": []
|
"boundElements": [],
|
||||||
|
"updated": 1650567155021,
|
||||||
|
"link": null,
|
||||||
|
"locked": false
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"type": "text",
|
"type": "text",
|
||||||
"version": 1065,
|
"version": 1202,
|
||||||
"versionNonce": 126714162,
|
"versionNonce": 842114,
|
||||||
"isDeleted": false,
|
"isDeleted": false,
|
||||||
"id": "K48gtpesBxIGJxLTnI2CB",
|
"id": "K48gtpesBxIGJxLTnI2CB",
|
||||||
"fillStyle": "hachure",
|
"fillStyle": "hachure",
|
||||||
@@ -171,8 +195,8 @@
|
|||||||
"roughness": 1,
|
"roughness": 1,
|
||||||
"opacity": 100,
|
"opacity": 100,
|
||||||
"angle": 0,
|
"angle": 0,
|
||||||
"x": 1064.449462890625,
|
"x": 1065.672119140625,
|
||||||
"y": 296.9230194091797,
|
"y": 656.4816131591797,
|
||||||
"strokeColor": "#000000",
|
"strokeColor": "#000000",
|
||||||
"backgroundColor": "transparent",
|
"backgroundColor": "transparent",
|
||||||
"width": 137,
|
"width": 137,
|
||||||
@@ -180,18 +204,23 @@
|
|||||||
"seed": 449264361,
|
"seed": 449264361,
|
||||||
"groupIds": [],
|
"groupIds": [],
|
||||||
"strokeSharpness": "sharp",
|
"strokeSharpness": "sharp",
|
||||||
"boundElementIds": [],
|
"boundElements": [],
|
||||||
|
"updated": 1650567155021,
|
||||||
|
"link": null,
|
||||||
|
"locked": false,
|
||||||
"fontSize": 28,
|
"fontSize": 28,
|
||||||
"fontFamily": 1,
|
"fontFamily": 1,
|
||||||
"text": "Filesystem",
|
"text": "Filesystem",
|
||||||
"baseline": 25,
|
"baseline": 25,
|
||||||
"textAlign": "center",
|
"textAlign": "center",
|
||||||
"verticalAlign": "top"
|
"verticalAlign": "top",
|
||||||
|
"containerId": null,
|
||||||
|
"originalText": "Filesystem"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"type": "rectangle",
|
"type": "rectangle",
|
||||||
"version": 896,
|
"version": 1163,
|
||||||
"versionNonce": 585884398,
|
"versionNonce": 1149481794,
|
||||||
"isDeleted": false,
|
"isDeleted": false,
|
||||||
"id": "La6f87LDZ0uEIZB947bXo",
|
"id": "La6f87LDZ0uEIZB947bXo",
|
||||||
"fillStyle": "hachure",
|
"fillStyle": "hachure",
|
||||||
@@ -200,21 +229,24 @@
|
|||||||
"roughness": 1,
|
"roughness": 1,
|
||||||
"opacity": 100,
|
"opacity": 100,
|
||||||
"angle": 0,
|
"angle": 0,
|
||||||
"x": 1329.0839233398438,
|
"x": 1375.0136108398438,
|
||||||
"y": 264.9097213745117,
|
"y": 626.2495651245117,
|
||||||
"strokeColor": "#000000",
|
"strokeColor": "#000000",
|
||||||
"backgroundColor": "#12b886",
|
"backgroundColor": "#12b886",
|
||||||
"width": 346.5517578125,
|
"width": 452.76554361979186,
|
||||||
"height": 96.3990020751953,
|
"height": 96.3990020751953,
|
||||||
"seed": 2005637801,
|
"seed": 2005637801,
|
||||||
"groupIds": [],
|
"groupIds": [],
|
||||||
"strokeSharpness": "sharp",
|
"strokeSharpness": "sharp",
|
||||||
"boundElementIds": []
|
"boundElements": [],
|
||||||
|
"updated": 1650567157857,
|
||||||
|
"link": null,
|
||||||
|
"locked": false
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"type": "text",
|
"type": "text",
|
||||||
"version": 1186,
|
"version": 1371,
|
||||||
"versionNonce": 1013615346,
|
"versionNonce": 1552918366,
|
||||||
"isDeleted": false,
|
"isDeleted": false,
|
||||||
"id": "aOgRPVQ81jhOfkvzjWTMF",
|
"id": "aOgRPVQ81jhOfkvzjWTMF",
|
||||||
"fillStyle": "hachure",
|
"fillStyle": "hachure",
|
||||||
@@ -223,286 +255,512 @@
|
|||||||
"roughness": 1,
|
"roughness": 1,
|
||||||
"opacity": 100,
|
"opacity": 100,
|
||||||
"angle": 0,
|
"angle": 0,
|
||||||
"x": 1392.300048828125,
|
"x": 1490.9330512152778,
|
||||||
"y": 294.1288604736328,
|
"y": 654.3717736138237,
|
||||||
"strokeColor": "#000000",
|
"strokeColor": "#000000",
|
||||||
"backgroundColor": "transparent",
|
"backgroundColor": "transparent",
|
||||||
"width": 223,
|
"width": 224,
|
||||||
"height": 35,
|
"height": 36,
|
||||||
"seed": 1284472935,
|
"seed": 1284472935,
|
||||||
"groupIds": [],
|
"groupIds": [],
|
||||||
"strokeSharpness": "sharp",
|
"strokeSharpness": "sharp",
|
||||||
"boundElementIds": [],
|
"boundElements": [],
|
||||||
|
"updated": 1650567166643,
|
||||||
|
"link": null,
|
||||||
|
"locked": false,
|
||||||
"fontSize": 28,
|
"fontSize": 28,
|
||||||
"fontFamily": 1,
|
"fontFamily": 1,
|
||||||
"text": "Git Repositories",
|
"text": "Git Repositories",
|
||||||
"baseline": 25,
|
"baseline": 25,
|
||||||
"textAlign": "center",
|
"textAlign": "center",
|
||||||
"verticalAlign": "top"
|
"verticalAlign": "top",
|
||||||
|
"containerId": null,
|
||||||
|
"originalText": "Git Repositories"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"type": "rectangle",
|
"type": "rectangle",
|
||||||
"version": 974,
|
"version": 2340,
|
||||||
"versionNonce": 1011959534,
|
"versionNonce": 1952732126,
|
||||||
"isDeleted": false,
|
"isDeleted": false,
|
||||||
"id": "BYJwfkhd1BilbLQGc973f",
|
"id": "p8fn5gPx8DfP8QE1lN98-",
|
||||||
"fillStyle": "hachure",
|
"fillStyle": "hachure",
|
||||||
"strokeWidth": 1,
|
"strokeWidth": 1,
|
||||||
"strokeStyle": "solid",
|
"strokeStyle": "solid",
|
||||||
"roughness": 1,
|
"roughness": 1,
|
||||||
"opacity": 100,
|
"opacity": 100,
|
||||||
"angle": 0,
|
"angle": 0,
|
||||||
"x": 1141.5093994140625,
|
"x": 1064.5642678676506,
|
||||||
"y": 171.09759140014648,
|
"y": 537.71609717149,
|
||||||
"strokeColor": "#000000",
|
"strokeColor": "#000000",
|
||||||
"backgroundColor": "#82c91e",
|
"backgroundColor": "#82c91e",
|
||||||
"width": 169.93957519531259,
|
"width": 144.5880126953128,
|
||||||
"height": 77.80606079101562,
|
"height": 77.80606079101562,
|
||||||
"seed": 1923498546,
|
"seed": 684019996,
|
||||||
"groupIds": [],
|
"groupIds": [],
|
||||||
"strokeSharpness": "sharp",
|
"strokeSharpness": "sharp",
|
||||||
"boundElementIds": []
|
"boundElements": [],
|
||||||
},
|
"updated": 1650567155021,
|
||||||
{
|
"link": null,
|
||||||
"type": "text",
|
"locked": false
|
||||||
"version": 403,
|
|
||||||
"versionNonce": 1635608306,
|
|
||||||
"isDeleted": false,
|
|
||||||
"id": "eedUyCpr8i1aY_3PHsHAB",
|
|
||||||
"fillStyle": "hachure",
|
|
||||||
"strokeWidth": 1,
|
|
||||||
"strokeStyle": "solid",
|
|
||||||
"roughness": 1,
|
|
||||||
"opacity": 100,
|
|
||||||
"angle": 0,
|
|
||||||
"x": 1149.8379821777344,
|
|
||||||
"y": 197.31159591674805,
|
|
||||||
"strokeColor": "#000000",
|
|
||||||
"backgroundColor": "#82c91e",
|
|
||||||
"width": 155,
|
|
||||||
"height": 25,
|
|
||||||
"seed": 595309038,
|
|
||||||
"groupIds": [],
|
|
||||||
"strokeSharpness": "sharp",
|
|
||||||
"boundElementIds": [],
|
|
||||||
"fontSize": 20,
|
|
||||||
"fontFamily": 1,
|
|
||||||
"text": "Misconfiguration",
|
|
||||||
"baseline": 18,
|
|
||||||
"textAlign": "center",
|
|
||||||
"verticalAlign": "middle"
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"type": "rectangle",
|
"type": "rectangle",
|
||||||
"version": 1035,
|
"version": 2497,
|
||||||
"versionNonce": 1646453614,
|
"versionNonce": 832692482,
|
||||||
"isDeleted": false,
|
"isDeleted": false,
|
||||||
"id": "SPkrBrH6DGvkgQXtZQjIJ",
|
"id": "kFTL0HnUdDs_ngg2xVFbn",
|
||||||
"fillStyle": "hachure",
|
"fillStyle": "hachure",
|
||||||
"strokeWidth": 1,
|
"strokeWidth": 1,
|
||||||
"strokeStyle": "solid",
|
"strokeStyle": "solid",
|
||||||
"roughness": 1,
|
"roughness": 1,
|
||||||
"opacity": 100,
|
"opacity": 100,
|
||||||
"angle": 0,
|
"angle": 0,
|
||||||
"x": 959.9851989746094,
|
"x": 600.7947366176511,
|
||||||
"y": 170.4835319519043,
|
"y": 538.67312842149,
|
||||||
"strokeColor": "#000000",
|
"strokeColor": "#000000",
|
||||||
"backgroundColor": "#fa5252",
|
"backgroundColor": "#fa5252",
|
||||||
"width": 169.93957519531259,
|
"width": 144.5880126953128,
|
||||||
"height": 77.80606079101562,
|
"height": 77.80606079101562,
|
||||||
"seed": 1896460914,
|
"seed": 541443108,
|
||||||
"groupIds": [],
|
"groupIds": [],
|
||||||
"strokeSharpness": "sharp",
|
"strokeSharpness": "sharp",
|
||||||
"boundElementIds": []
|
"boundElements": [],
|
||||||
|
"updated": 1650567155021,
|
||||||
|
"link": null,
|
||||||
|
"locked": false
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"type": "text",
|
"type": "rectangle",
|
||||||
"version": 532,
|
"version": 2345,
|
||||||
"versionNonce": 1887556210,
|
"versionNonce": 1129796482,
|
||||||
"isDeleted": false,
|
"isDeleted": false,
|
||||||
"id": "n06MNIqirDmVZBkDg_UPV",
|
"id": "KIztJcYHiVtM-GMlZAXAE",
|
||||||
"fillStyle": "hachure",
|
"fillStyle": "hachure",
|
||||||
"strokeWidth": 1,
|
"strokeWidth": 1,
|
||||||
"strokeStyle": "solid",
|
"strokeStyle": "solid",
|
||||||
"roughness": 1,
|
"roughness": 1,
|
||||||
"opacity": 100,
|
"opacity": 100,
|
||||||
"angle": 0,
|
"angle": 0,
|
||||||
"x": 988.8137817382812,
|
"x": 753.0955178676511,
|
||||||
"y": 196.69753646850586,
|
"y": 538.61062842149,
|
||||||
|
"strokeColor": "#000000",
|
||||||
|
"backgroundColor": "#4c6ef5",
|
||||||
|
"width": 145,
|
||||||
|
"height": 77.80606079101562,
|
||||||
|
"seed": 424425892,
|
||||||
|
"groupIds": [],
|
||||||
|
"strokeSharpness": "sharp",
|
||||||
|
"boundElements": [],
|
||||||
|
"updated": 1650567234562,
|
||||||
|
"link": null,
|
||||||
|
"locked": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "rectangle",
|
||||||
|
"version": 2329,
|
||||||
|
"versionNonce": 1518497986,
|
||||||
|
"isDeleted": false,
|
||||||
|
"id": "IWq_LcOearBV5cvqbJ_-o",
|
||||||
|
"fillStyle": "hachure",
|
||||||
|
"strokeWidth": 1,
|
||||||
|
"strokeStyle": "solid",
|
||||||
|
"roughness": 1,
|
||||||
|
"opacity": 100,
|
||||||
|
"angle": 0,
|
||||||
|
"x": 911.3064553676511,
|
||||||
|
"y": 537.97781592149,
|
||||||
|
"strokeColor": "#000000",
|
||||||
|
"backgroundColor": "#fa5252",
|
||||||
|
"width": 144.5880126953128,
|
||||||
|
"height": 77.80606079101562,
|
||||||
|
"seed": 468230812,
|
||||||
|
"groupIds": [],
|
||||||
|
"strokeSharpness": "sharp",
|
||||||
|
"boundElements": [],
|
||||||
|
"updated": 1650567155021,
|
||||||
|
"link": null,
|
||||||
|
"locked": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "rectangle",
|
||||||
|
"version": 2318,
|
||||||
|
"versionNonce": 1504408670,
|
||||||
|
"isDeleted": false,
|
||||||
|
"id": "TXeK066NA0hvyPSeZl1a5",
|
||||||
|
"fillStyle": "hachure",
|
||||||
|
"strokeWidth": 1,
|
||||||
|
"strokeStyle": "solid",
|
||||||
|
"roughness": 1,
|
||||||
|
"opacity": 100,
|
||||||
|
"angle": 0,
|
||||||
|
"x": 1218.075986617651,
|
||||||
|
"y": 536.86062842149,
|
||||||
|
"strokeColor": "#000000",
|
||||||
|
"backgroundColor": "#4c6ef5",
|
||||||
|
"width": 144.5880126953128,
|
||||||
|
"height": 77.80606079101562,
|
||||||
|
"seed": 1408574372,
|
||||||
|
"groupIds": [],
|
||||||
|
"strokeSharpness": "sharp",
|
||||||
|
"boundElements": [],
|
||||||
|
"updated": 1650567155021,
|
||||||
|
"link": null,
|
||||||
|
"locked": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "rectangle",
|
||||||
|
"version": 2364,
|
||||||
|
"versionNonce": 3868802,
|
||||||
|
"isDeleted": false,
|
||||||
|
"id": "10WjipxoLx2zzSI91pXbR",
|
||||||
|
"fillStyle": "hachure",
|
||||||
|
"strokeWidth": 1,
|
||||||
|
"strokeStyle": "solid",
|
||||||
|
"roughness": 1,
|
||||||
|
"opacity": 100,
|
||||||
|
"angle": 0,
|
||||||
|
"x": 1375.544736617651,
|
||||||
|
"y": 537.04812842149,
|
||||||
|
"strokeColor": "#000000",
|
||||||
|
"backgroundColor": "#fa5252",
|
||||||
|
"width": 144.5880126953128,
|
||||||
|
"height": 77.80606079101562,
|
||||||
|
"seed": 1813731484,
|
||||||
|
"groupIds": [],
|
||||||
|
"strokeSharpness": "sharp",
|
||||||
|
"boundElements": [],
|
||||||
|
"updated": 1650567155021,
|
||||||
|
"link": null,
|
||||||
|
"locked": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "rectangle",
|
||||||
|
"version": 2355,
|
||||||
|
"versionNonce": 2067347614,
|
||||||
|
"isDeleted": false,
|
||||||
|
"id": "M7Cngti6H0_kawKRN8yJ6",
|
||||||
|
"fillStyle": "hachure",
|
||||||
|
"strokeWidth": 1,
|
||||||
|
"strokeStyle": "solid",
|
||||||
|
"roughness": 1,
|
||||||
|
"opacity": 100,
|
||||||
|
"angle": 0,
|
||||||
|
"x": 1528.868955367651,
|
||||||
|
"y": 535.89187842149,
|
||||||
|
"strokeColor": "#000000",
|
||||||
|
"backgroundColor": "#82c91e",
|
||||||
|
"width": 144.5880126953128,
|
||||||
|
"height": 77.80606079101562,
|
||||||
|
"seed": 1260603804,
|
||||||
|
"groupIds": [],
|
||||||
|
"strokeSharpness": "sharp",
|
||||||
|
"boundElements": [],
|
||||||
|
"updated": 1650567155021,
|
||||||
|
"link": null,
|
||||||
|
"locked": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "text",
|
||||||
|
"version": 597,
|
||||||
|
"versionNonce": 1519036482,
|
||||||
|
"isDeleted": false,
|
||||||
|
"id": "GHDrLyBOErQtv_WT5Lx3p",
|
||||||
|
"fillStyle": "hachure",
|
||||||
|
"strokeWidth": 1,
|
||||||
|
"strokeStyle": "solid",
|
||||||
|
"roughness": 1,
|
||||||
|
"opacity": 100,
|
||||||
|
"angle": 0,
|
||||||
|
"x": 614.2293679653073,
|
||||||
|
"y": 565.5605338169978,
|
||||||
"strokeColor": "#000000",
|
"strokeColor": "#000000",
|
||||||
"backgroundColor": "#82c91e",
|
"backgroundColor": "#82c91e",
|
||||||
"width": 114,
|
"width": 114,
|
||||||
"height": 25,
|
"height": 25,
|
||||||
"seed": 1131832750,
|
"seed": 13297180,
|
||||||
"groupIds": [],
|
"groupIds": [],
|
||||||
"strokeSharpness": "sharp",
|
"strokeSharpness": "sharp",
|
||||||
"boundElementIds": [],
|
"boundElements": [],
|
||||||
|
"updated": 1650567155021,
|
||||||
|
"link": null,
|
||||||
|
"locked": false,
|
||||||
"fontSize": 20,
|
"fontSize": 20,
|
||||||
"fontFamily": 1,
|
"fontFamily": 1,
|
||||||
"text": "Vulnerability",
|
"text": "Vulnerability",
|
||||||
"baseline": 18,
|
"baseline": 18,
|
||||||
"textAlign": "center",
|
"textAlign": "center",
|
||||||
"verticalAlign": "middle"
|
"verticalAlign": "middle",
|
||||||
},
|
"containerId": null,
|
||||||
{
|
"originalText": "Vulnerability"
|
||||||
"type": "rectangle",
|
|
||||||
"version": 1072,
|
|
||||||
"versionNonce": 789595566,
|
|
||||||
"isDeleted": false,
|
|
||||||
"id": "0JP6OL7EFfoH4E4vFARFl",
|
|
||||||
"fillStyle": "hachure",
|
|
||||||
"strokeWidth": 1,
|
|
||||||
"strokeStyle": "solid",
|
|
||||||
"roughness": 1,
|
|
||||||
"opacity": 100,
|
|
||||||
"angle": 0,
|
|
||||||
"x": 1508.9087371826172,
|
|
||||||
"y": 170.7038917541504,
|
|
||||||
"strokeColor": "#000000",
|
|
||||||
"backgroundColor": "#82c91e",
|
|
||||||
"width": 169.93957519531259,
|
|
||||||
"height": 77.80606079101562,
|
|
||||||
"seed": 101784622,
|
|
||||||
"groupIds": [],
|
|
||||||
"strokeSharpness": "sharp",
|
|
||||||
"boundElementIds": []
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"type": "text",
|
"type": "text",
|
||||||
"version": 496,
|
"version": 655,
|
||||||
"versionNonce": 1027781682,
|
"versionNonce": 1728345310,
|
||||||
"isDeleted": false,
|
"isDeleted": false,
|
||||||
"id": "jRmlh5MZuRKm3FtbC6qdZ",
|
"id": "Iq57wFRtO1a8AU0rT6lRD",
|
||||||
"fillStyle": "hachure",
|
"fillStyle": "hachure",
|
||||||
"strokeWidth": 1,
|
"strokeWidth": 1,
|
||||||
"strokeStyle": "solid",
|
"strokeStyle": "solid",
|
||||||
"roughness": 1,
|
"roughness": 1,
|
||||||
"opacity": 100,
|
"opacity": 100,
|
||||||
"angle": 0,
|
"angle": 0,
|
||||||
"x": 1517.237319946289,
|
"x": 1533.6317117153076,
|
||||||
"y": 196.91789627075195,
|
"y": 565.2714713169978,
|
||||||
"strokeColor": "#000000",
|
"strokeColor": "#000000",
|
||||||
"backgroundColor": "#82c91e",
|
"backgroundColor": "#82c91e",
|
||||||
"width": 155,
|
"width": 136.25488281249991,
|
||||||
"height": 25,
|
"height": 21.80078124999998,
|
||||||
"seed": 1950385586,
|
"seed": 1329695396,
|
||||||
"groupIds": [],
|
"groupIds": [],
|
||||||
"strokeSharpness": "sharp",
|
"strokeSharpness": "sharp",
|
||||||
"boundElementIds": [],
|
"boundElements": [],
|
||||||
"fontSize": 20,
|
"updated": 1650567155021,
|
||||||
|
"link": null,
|
||||||
|
"locked": false,
|
||||||
|
"fontSize": 17.440624999999976,
|
||||||
"fontFamily": 1,
|
"fontFamily": 1,
|
||||||
"text": "Misconfiguration",
|
"text": "Misconfiguration",
|
||||||
"baseline": 18,
|
"baseline": 14.800781249999979,
|
||||||
"textAlign": "center",
|
"textAlign": "center",
|
||||||
"verticalAlign": "middle"
|
"verticalAlign": "middle",
|
||||||
},
|
"containerId": null,
|
||||||
{
|
"originalText": "Misconfiguration"
|
||||||
"type": "rectangle",
|
|
||||||
"version": 1133,
|
|
||||||
"versionNonce": 882335726,
|
|
||||||
"isDeleted": false,
|
|
||||||
"id": "EQRF92xU4o9CfeHHvbd-a",
|
|
||||||
"fillStyle": "hachure",
|
|
||||||
"strokeWidth": 1,
|
|
||||||
"strokeStyle": "solid",
|
|
||||||
"roughness": 1,
|
|
||||||
"opacity": 100,
|
|
||||||
"angle": 0,
|
|
||||||
"x": 1327.384536743164,
|
|
||||||
"y": 170.0898323059082,
|
|
||||||
"strokeColor": "#000000",
|
|
||||||
"backgroundColor": "#fa5252",
|
|
||||||
"width": 169.93957519531259,
|
|
||||||
"height": 77.80606079101562,
|
|
||||||
"seed": 1379493486,
|
|
||||||
"groupIds": [],
|
|
||||||
"strokeSharpness": "sharp",
|
|
||||||
"boundElementIds": []
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"type": "text",
|
"type": "text",
|
||||||
"version": 569,
|
"version": 666,
|
||||||
"versionNonce": 184638962,
|
"versionNonce": 1364217858,
|
||||||
"isDeleted": false,
|
"isDeleted": false,
|
||||||
"id": "_04YR8geM-ar9vZhNZtSj",
|
"id": "gjnZl9nxrqzliwPk8sbK-",
|
||||||
"fillStyle": "hachure",
|
"fillStyle": "hachure",
|
||||||
"strokeWidth": 1,
|
"strokeWidth": 1,
|
||||||
"strokeStyle": "solid",
|
"strokeStyle": "solid",
|
||||||
"roughness": 1,
|
"roughness": 1,
|
||||||
"opacity": 100,
|
"opacity": 100,
|
||||||
"angle": 0,
|
"angle": 0,
|
||||||
"x": 1356.213119506836,
|
"x": 1067.4339578090576,
|
||||||
"y": 196.30383682250977,
|
"y": 565.8827994419978,
|
||||||
|
"strokeColor": "#000000",
|
||||||
|
"backgroundColor": "#82c91e",
|
||||||
|
"width": 136.25488281249991,
|
||||||
|
"height": 21.80078124999998,
|
||||||
|
"seed": 290336932,
|
||||||
|
"groupIds": [],
|
||||||
|
"strokeSharpness": "sharp",
|
||||||
|
"boundElements": [],
|
||||||
|
"updated": 1650567155021,
|
||||||
|
"link": null,
|
||||||
|
"locked": false,
|
||||||
|
"fontSize": 17.440624999999976,
|
||||||
|
"fontFamily": 1,
|
||||||
|
"text": "Misconfiguration",
|
||||||
|
"baseline": 14.800781249999979,
|
||||||
|
"textAlign": "center",
|
||||||
|
"verticalAlign": "middle",
|
||||||
|
"containerId": null,
|
||||||
|
"originalText": "Misconfiguration"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "text",
|
||||||
|
"version": 613,
|
||||||
|
"versionNonce": 1721641246,
|
||||||
|
"isDeleted": false,
|
||||||
|
"id": "_cm6xpfcL9Yv2XBK5MBZF",
|
||||||
|
"fillStyle": "hachure",
|
||||||
|
"strokeWidth": 1,
|
||||||
|
"strokeStyle": "solid",
|
||||||
|
"roughness": 1,
|
||||||
|
"opacity": 100,
|
||||||
|
"angle": 0,
|
||||||
|
"x": 1390.1199929653073,
|
||||||
|
"y": 563.8456900669978,
|
||||||
"strokeColor": "#000000",
|
"strokeColor": "#000000",
|
||||||
"backgroundColor": "#82c91e",
|
"backgroundColor": "#82c91e",
|
||||||
"width": 114,
|
"width": 114,
|
||||||
"height": 25,
|
"height": 25,
|
||||||
"seed": 357105522,
|
"seed": 807441828,
|
||||||
"groupIds": [],
|
"groupIds": [],
|
||||||
"strokeSharpness": "sharp",
|
"strokeSharpness": "sharp",
|
||||||
"boundElementIds": [],
|
"boundElements": [],
|
||||||
|
"updated": 1650567155021,
|
||||||
|
"link": null,
|
||||||
|
"locked": false,
|
||||||
"fontSize": 20,
|
"fontSize": 20,
|
||||||
"fontFamily": 1,
|
"fontFamily": 1,
|
||||||
"text": "Vulnerability",
|
"text": "Vulnerability",
|
||||||
"baseline": 18,
|
"baseline": 18,
|
||||||
"textAlign": "center",
|
"textAlign": "center",
|
||||||
"verticalAlign": "middle"
|
"verticalAlign": "middle",
|
||||||
},
|
"containerId": null,
|
||||||
{
|
"originalText": "Vulnerability"
|
||||||
"type": "rectangle",
|
|
||||||
"version": 1215,
|
|
||||||
"versionNonce": 650195502,
|
|
||||||
"isDeleted": false,
|
|
||||||
"id": "8SHSNGf7PNddFLi2ZA3Vi",
|
|
||||||
"fillStyle": "hachure",
|
|
||||||
"strokeWidth": 1,
|
|
||||||
"strokeStyle": "solid",
|
|
||||||
"roughness": 1,
|
|
||||||
"opacity": 100,
|
|
||||||
"angle": 0,
|
|
||||||
"x": 599.9767150878906,
|
|
||||||
"y": 169.0025749206543,
|
|
||||||
"strokeColor": "#000000",
|
|
||||||
"backgroundColor": "#fa5252",
|
|
||||||
"width": 344.1738281250001,
|
|
||||||
"height": 77.80606079101562,
|
|
||||||
"seed": 1986948530,
|
|
||||||
"groupIds": [],
|
|
||||||
"strokeSharpness": "sharp",
|
|
||||||
"boundElementIds": []
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"type": "text",
|
"type": "text",
|
||||||
"version": 680,
|
"version": 635,
|
||||||
"versionNonce": 113561522,
|
"versionNonce": 2022375362,
|
||||||
"isDeleted": false,
|
"isDeleted": false,
|
||||||
"id": "3Z5w3RXdgpvP43dlHqq26",
|
"id": "An4-igVUkLzCwSdvDmtZl",
|
||||||
"fillStyle": "hachure",
|
"fillStyle": "hachure",
|
||||||
"strokeWidth": 1,
|
"strokeWidth": 1,
|
||||||
"strokeStyle": "solid",
|
"strokeStyle": "solid",
|
||||||
"roughness": 1,
|
"roughness": 1,
|
||||||
"opacity": 100,
|
"opacity": 100,
|
||||||
"angle": 0,
|
"angle": 0,
|
||||||
"x": 700.3721618652344,
|
"x": 925.6707742153073,
|
||||||
"y": 190.79421615600586,
|
"y": 560.4550650669978,
|
||||||
"strokeColor": "#000000",
|
"strokeColor": "#000000",
|
||||||
"backgroundColor": "#82c91e",
|
"backgroundColor": "#82c91e",
|
||||||
"width": 160,
|
"width": 114,
|
||||||
"height": 35,
|
"height": 25,
|
||||||
"seed": 1077804654,
|
"seed": 1262859164,
|
||||||
"groupIds": [],
|
"groupIds": [],
|
||||||
"strokeSharpness": "sharp",
|
"strokeSharpness": "sharp",
|
||||||
"boundElementIds": [],
|
"boundElements": [],
|
||||||
"fontSize": 28,
|
"updated": 1650567155021,
|
||||||
|
"link": null,
|
||||||
|
"locked": false,
|
||||||
|
"fontSize": 20,
|
||||||
"fontFamily": 1,
|
"fontFamily": 1,
|
||||||
"text": "Vulnerability",
|
"text": "Vulnerability",
|
||||||
"baseline": 25,
|
"baseline": 18,
|
||||||
"textAlign": "center",
|
"textAlign": "center",
|
||||||
"verticalAlign": "middle"
|
"verticalAlign": "middle",
|
||||||
|
"containerId": null,
|
||||||
|
"originalText": "Vulnerability"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "text",
|
||||||
|
"version": 681,
|
||||||
|
"versionNonce": 1813371650,
|
||||||
|
"isDeleted": false,
|
||||||
|
"id": "p3-AVxdx5KP6eNViMVTLq",
|
||||||
|
"fillStyle": "hachure",
|
||||||
|
"strokeWidth": 1,
|
||||||
|
"strokeStyle": "solid",
|
||||||
|
"roughness": 1,
|
||||||
|
"opacity": 100,
|
||||||
|
"angle": 0,
|
||||||
|
"x": 792.0184304653073,
|
||||||
|
"y": 564.4160025669978,
|
||||||
|
"strokeColor": "#000000",
|
||||||
|
"backgroundColor": "#82c91e",
|
||||||
|
"width": 65,
|
||||||
|
"height": 25,
|
||||||
|
"seed": 729823772,
|
||||||
|
"groupIds": [],
|
||||||
|
"strokeSharpness": "sharp",
|
||||||
|
"boundElements": [],
|
||||||
|
"updated": 1650567236437,
|
||||||
|
"link": null,
|
||||||
|
"locked": false,
|
||||||
|
"fontSize": 20,
|
||||||
|
"fontFamily": 1,
|
||||||
|
"text": "Secret",
|
||||||
|
"baseline": 18,
|
||||||
|
"textAlign": "center",
|
||||||
|
"verticalAlign": "middle",
|
||||||
|
"containerId": null,
|
||||||
|
"originalText": "Secret"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "text",
|
||||||
|
"version": 692,
|
||||||
|
"versionNonce": 621238878,
|
||||||
|
"isDeleted": false,
|
||||||
|
"id": "7fe9NOM7QTEEW7nyXAMjh",
|
||||||
|
"fillStyle": "hachure",
|
||||||
|
"strokeWidth": 1,
|
||||||
|
"strokeStyle": "solid",
|
||||||
|
"roughness": 1,
|
||||||
|
"opacity": 100,
|
||||||
|
"angle": 0,
|
||||||
|
"x": 1259.0613992153073,
|
||||||
|
"y": 562.4238150669978,
|
||||||
|
"strokeColor": "#000000",
|
||||||
|
"backgroundColor": "#82c91e",
|
||||||
|
"width": 65,
|
||||||
|
"height": 25,
|
||||||
|
"seed": 968541220,
|
||||||
|
"groupIds": [],
|
||||||
|
"strokeSharpness": "sharp",
|
||||||
|
"boundElements": [],
|
||||||
|
"updated": 1650567238433,
|
||||||
|
"link": null,
|
||||||
|
"locked": false,
|
||||||
|
"fontSize": 20,
|
||||||
|
"fontFamily": 1,
|
||||||
|
"text": "Secret",
|
||||||
|
"baseline": 18,
|
||||||
|
"textAlign": "center",
|
||||||
|
"verticalAlign": "middle",
|
||||||
|
"containerId": null,
|
||||||
|
"originalText": "Secret"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "rectangle",
|
||||||
|
"version": 2417,
|
||||||
|
"versionNonce": 1222703518,
|
||||||
|
"isDeleted": false,
|
||||||
|
"id": "Fq7meULupm1A9leboPlko",
|
||||||
|
"fillStyle": "hachure",
|
||||||
|
"strokeWidth": 1,
|
||||||
|
"strokeStyle": "solid",
|
||||||
|
"roughness": 1,
|
||||||
|
"opacity": 100,
|
||||||
|
"angle": 0,
|
||||||
|
"x": 1684.2588079543348,
|
||||||
|
"y": 536.1830067815082,
|
||||||
|
"strokeColor": "#000000",
|
||||||
|
"backgroundColor": "#4c6ef5",
|
||||||
|
"width": 144.5880126953128,
|
||||||
|
"height": 77.80606079101562,
|
||||||
|
"seed": 230693534,
|
||||||
|
"groupIds": [],
|
||||||
|
"strokeSharpness": "sharp",
|
||||||
|
"boundElements": [],
|
||||||
|
"updated": 1650567155021,
|
||||||
|
"link": null,
|
||||||
|
"locked": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "text",
|
||||||
|
"version": 760,
|
||||||
|
"versionNonce": 503898690,
|
||||||
|
"isDeleted": false,
|
||||||
|
"id": "OUGk8nZzvgcKUHhKUcQov",
|
||||||
|
"fillStyle": "hachure",
|
||||||
|
"strokeWidth": 1,
|
||||||
|
"strokeStyle": "solid",
|
||||||
|
"roughness": 1,
|
||||||
|
"opacity": 100,
|
||||||
|
"angle": 0,
|
||||||
|
"x": 1723.2672240242127,
|
||||||
|
"y": 561.8650424396028,
|
||||||
|
"strokeColor": "#000000",
|
||||||
|
"backgroundColor": "#82c91e",
|
||||||
|
"width": 65,
|
||||||
|
"height": 25,
|
||||||
|
"seed": 2044527454,
|
||||||
|
"groupIds": [],
|
||||||
|
"strokeSharpness": "sharp",
|
||||||
|
"boundElements": [],
|
||||||
|
"updated": 1650567240607,
|
||||||
|
"link": null,
|
||||||
|
"locked": false,
|
||||||
|
"fontSize": 20,
|
||||||
|
"fontFamily": 1,
|
||||||
|
"text": "Secret",
|
||||||
|
"baseline": 18,
|
||||||
|
"textAlign": "center",
|
||||||
|
"verticalAlign": "middle",
|
||||||
|
"containerId": null,
|
||||||
|
"originalText": "Secret"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"appState": {
|
"appState": {
|
||||||
"gridSize": null,
|
"gridSize": null,
|
||||||
"viewBackgroundColor": "#ffffff"
|
"viewBackgroundColor": "#ffffff"
|
||||||
}
|
},
|
||||||
|
"files": {}
|
||||||
}
|
}
|
||||||
BIN
docs/imgs/excalidraw/overview.png
Normal file
BIN
docs/imgs/excalidraw/overview.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 2.1 MiB |
Binary file not shown.
|
Before Width: | Height: | Size: 878 KiB After Width: | Height: | Size: 2.1 MiB |
@@ -6,10 +6,10 @@ hide:
|
|||||||
|
|
||||||
{ align=left }
|
{ align=left }
|
||||||
|
|
||||||
`Trivy` (`tri` pronounced like **tri**gger, `vy` pronounced like en**vy**) is a simple and comprehensive [vulnerability][vulnerability]/[misconfiguration][misconf] scanner for containers and other artifacts.
|
`Trivy` (`tri` pronounced like **tri**gger, `vy` pronounced like en**vy**) is a simple and comprehensive [vulnerability][vulnerability]/[misconfiguration][misconf]/[secret][secret] scanner for containers and other artifacts.
|
||||||
A software vulnerability is a glitch, flaw, or weakness present in the software or in an Operating System.
|
|
||||||
`Trivy` detects vulnerabilities of [OS packages][os] (Alpine, RHEL, CentOS, etc.) and [language-specific packages][lang] (Bundler, Composer, npm, yarn, etc.).
|
`Trivy` detects vulnerabilities of [OS packages][os] (Alpine, RHEL, CentOS, etc.) and [language-specific packages][lang] (Bundler, Composer, npm, yarn, etc.).
|
||||||
In addition, `Trivy` scans [Infrastructure as Code (IaC) files][iac] such as Terraform and Kubernetes, to detect potential configuration issues that expose your deployments to the risk of attack.
|
In addition, `Trivy` scans [Infrastructure as Code (IaC) files][iac] such as Terraform and Kubernetes, to detect potential configuration issues that expose your deployments to the risk of attack.
|
||||||
|
`Trivy` also scans [hardcoded secrets][secret] like passwords, api keys, and tokens.
|
||||||
`Trivy` is easy to use. Just install the binary and you're ready to scan.
|
`Trivy` is easy to use. Just install the binary and you're ready to scan.
|
||||||
All you need to do for scanning is to specify a target such as an image name of the container.
|
All you need to do for scanning is to specify a target such as an image name of the container.
|
||||||
|
|
||||||
@@ -40,6 +40,7 @@ Contact us about any matter by opening a GitHub Discussion [here][discussions]
|
|||||||
|
|
||||||
[vulnerability]: docs/vulnerability/scanning/index.md
|
[vulnerability]: docs/vulnerability/scanning/index.md
|
||||||
[misconf]: docs/misconfiguration/index.md
|
[misconf]: docs/misconfiguration/index.md
|
||||||
|
[secret]: docs/secret/scanning.md
|
||||||
[os]: docs/vulnerability/detection/os.md
|
[os]: docs/vulnerability/detection/os.md
|
||||||
[lang]: docs/vulnerability/detection/language.md
|
[lang]: docs/vulnerability/detection/language.md
|
||||||
[iac]: docs/misconfiguration/iac.md
|
[iac]: docs/misconfiguration/iac.md
|
||||||
|
|||||||
2
go.mod
2
go.mod
@@ -7,7 +7,7 @@ require (
|
|||||||
github.com/Masterminds/sprig/v3 v3.2.2
|
github.com/Masterminds/sprig/v3 v3.2.2
|
||||||
github.com/NYTimes/gziphandler v0.0.0-20170623195520-56545f4a5d46
|
github.com/NYTimes/gziphandler v0.0.0-20170623195520-56545f4a5d46
|
||||||
github.com/aquasecurity/bolt-fixtures v0.0.0-20200903104109-d34e7f983986
|
github.com/aquasecurity/bolt-fixtures v0.0.0-20200903104109-d34e7f983986
|
||||||
github.com/aquasecurity/fanal v0.0.0-20220421095103-63f3f8193fa8
|
github.com/aquasecurity/fanal v0.0.0-20220421211205-bf8b076b6bf1
|
||||||
github.com/aquasecurity/go-dep-parser v0.0.0-20220412145205-d0501f906d90
|
github.com/aquasecurity/go-dep-parser v0.0.0-20220412145205-d0501f906d90
|
||||||
github.com/aquasecurity/go-gem-version v0.0.0-20201115065557-8eed6fe000ce
|
github.com/aquasecurity/go-gem-version v0.0.0-20201115065557-8eed6fe000ce
|
||||||
github.com/aquasecurity/go-npm-version v0.0.0-20201110091526-0b796d180798
|
github.com/aquasecurity/go-npm-version v0.0.0-20201110091526-0b796d180798
|
||||||
|
|||||||
4
go.sum
4
go.sum
@@ -237,8 +237,8 @@ github.com/aquasecurity/bolt-fixtures v0.0.0-20200903104109-d34e7f983986 h1:2a30
|
|||||||
github.com/aquasecurity/bolt-fixtures v0.0.0-20200903104109-d34e7f983986/go.mod h1:NT+jyeCzXk6vXR5MTkdn4z64TgGfE5HMLC8qfj5unl8=
|
github.com/aquasecurity/bolt-fixtures v0.0.0-20200903104109-d34e7f983986/go.mod h1:NT+jyeCzXk6vXR5MTkdn4z64TgGfE5HMLC8qfj5unl8=
|
||||||
github.com/aquasecurity/defsec v0.28.5-0.20220416075528-0f0c8fdf63b8 h1:TQOc6oTNT1943KbsivdxBnNHlZbp6cF3AcMzVLJCotg=
|
github.com/aquasecurity/defsec v0.28.5-0.20220416075528-0f0c8fdf63b8 h1:TQOc6oTNT1943KbsivdxBnNHlZbp6cF3AcMzVLJCotg=
|
||||||
github.com/aquasecurity/defsec v0.28.5-0.20220416075528-0f0c8fdf63b8/go.mod h1:vUdThwusBM7y1gJ7CVX3+h3bsPvpmOIEp3NEdzTDkhA=
|
github.com/aquasecurity/defsec v0.28.5-0.20220416075528-0f0c8fdf63b8/go.mod h1:vUdThwusBM7y1gJ7CVX3+h3bsPvpmOIEp3NEdzTDkhA=
|
||||||
github.com/aquasecurity/fanal v0.0.0-20220421095103-63f3f8193fa8 h1:3kXo5widBEz1euPnd292X5JSq0kEDuobi3YAXl4DbhU=
|
github.com/aquasecurity/fanal v0.0.0-20220421211205-bf8b076b6bf1 h1:57WZwnbs6hC38uhHu88T6WYqEsbmgvhsA+r81a5P13Q=
|
||||||
github.com/aquasecurity/fanal v0.0.0-20220421095103-63f3f8193fa8/go.mod h1:PYU7igSuHlhOFTVNhMlv/P9oTYbcgMb0wn5+Sz+xkMs=
|
github.com/aquasecurity/fanal v0.0.0-20220421211205-bf8b076b6bf1/go.mod h1:zDhHI2dChX5My7gGtY6PGgKTfhJ6y8c6cDI+y38rVk8=
|
||||||
github.com/aquasecurity/go-dep-parser v0.0.0-20220412145205-d0501f906d90 h1:uZcI5qV7J1pzOc6W49l7iEey/KtEVlaqsNU5l65vZLk=
|
github.com/aquasecurity/go-dep-parser v0.0.0-20220412145205-d0501f906d90 h1:uZcI5qV7J1pzOc6W49l7iEey/KtEVlaqsNU5l65vZLk=
|
||||||
github.com/aquasecurity/go-dep-parser v0.0.0-20220412145205-d0501f906d90/go.mod h1:rK/5BoRt8/D7xXydoVVeBaQuk6zDJ6W+FWz/RqFuJxI=
|
github.com/aquasecurity/go-dep-parser v0.0.0-20220412145205-d0501f906d90/go.mod h1:rK/5BoRt8/D7xXydoVVeBaQuk6zDJ6W+FWz/RqFuJxI=
|
||||||
github.com/aquasecurity/go-gem-version v0.0.0-20201115065557-8eed6fe000ce h1:QgBRgJvtEOBtUXilDb1MLi1p1MWoyFDXAu5DEUl5nwM=
|
github.com/aquasecurity/go-gem-version v0.0.0-20201115065557-8eed6fe000ce h1:QgBRgJvtEOBtUXilDb1MLi1p1MWoyFDXAu5DEUl5nwM=
|
||||||
|
|||||||
@@ -24,6 +24,7 @@ func TestFilesystem(t *testing.T) {
|
|||||||
namespaces []string
|
namespaces []string
|
||||||
listAllPkgs bool
|
listAllPkgs bool
|
||||||
input string
|
input string
|
||||||
|
secretConfig string
|
||||||
}
|
}
|
||||||
tests := []struct {
|
tests := []struct {
|
||||||
name string
|
name string
|
||||||
@@ -100,6 +101,15 @@ func TestFilesystem(t *testing.T) {
|
|||||||
},
|
},
|
||||||
golden: "testdata/dockerfile-custom-policies.json.golden",
|
golden: "testdata/dockerfile-custom-policies.json.golden",
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
name: "secrets",
|
||||||
|
args: args{
|
||||||
|
securityChecks: "vuln,secret",
|
||||||
|
input: "testdata/fixtures/fs/secrets",
|
||||||
|
secretConfig: "testdata/fixtures/fs/secrets/trivy-secret.yaml",
|
||||||
|
},
|
||||||
|
golden: "testdata/secrets.json.golden",
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set up testing DB
|
// Set up testing DB
|
||||||
@@ -143,6 +153,10 @@ func TestFilesystem(t *testing.T) {
|
|||||||
osArgs = append(osArgs, "--list-all-pkgs")
|
osArgs = append(osArgs, "--list-all-pkgs")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if tt.args.secretConfig != "" {
|
||||||
|
osArgs = append(osArgs, "--secret-config", tt.args.secretConfig)
|
||||||
|
}
|
||||||
|
|
||||||
osArgs = append(osArgs, "--output", outputFile)
|
osArgs = append(osArgs, "--output", outputFile)
|
||||||
osArgs = append(osArgs, tt.args.input)
|
osArgs = append(osArgs, tt.args.input)
|
||||||
|
|
||||||
|
|||||||
7
integration/testdata/fixtures/fs/secrets/deploy.sh
vendored
Normal file
7
integration/testdata/fixtures/fs/secrets/deploy.sh
vendored
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
export AWS_ACCESS_KEY_ID=AKIAABCDEFGHI1234567
|
||||||
|
|
||||||
|
export GITHUB_PAT=ghp_0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ
|
||||||
|
|
||||||
|
echo mysecret
|
||||||
8
integration/testdata/fixtures/fs/secrets/trivy-secret.yaml
vendored
Normal file
8
integration/testdata/fixtures/fs/secrets/trivy-secret.yaml
vendored
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
rules:
|
||||||
|
- id: mysecret
|
||||||
|
category: Custom
|
||||||
|
title: My Secret
|
||||||
|
severity: HIGH
|
||||||
|
regex: mysecret
|
||||||
|
disable-rules:
|
||||||
|
- github-pat
|
||||||
31
integration/testdata/secrets.json.golden
vendored
Normal file
31
integration/testdata/secrets.json.golden
vendored
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
{
|
||||||
|
"SchemaVersion": 2,
|
||||||
|
"ArtifactName": "testdata/fixtures/fs/secrets",
|
||||||
|
"ArtifactType": "filesystem",
|
||||||
|
"Results": [
|
||||||
|
{
|
||||||
|
"Target": "deploy.sh",
|
||||||
|
"Class": "secret",
|
||||||
|
"Secrets": [
|
||||||
|
{
|
||||||
|
"RuleID": "aws-access-key-id",
|
||||||
|
"Category": "AWS",
|
||||||
|
"Severity": "CRITICAL",
|
||||||
|
"Title": "AWS Access Key ID",
|
||||||
|
"StartLine": 3,
|
||||||
|
"EndLine": 3,
|
||||||
|
"Match": "export AWS_ACCESS_KEY_ID=*****"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"RuleID": "mysecret",
|
||||||
|
"Category": "Custom",
|
||||||
|
"Severity": "HIGH",
|
||||||
|
"Title": "My Secret",
|
||||||
|
"StartLine": 7,
|
||||||
|
"EndLine": 7,
|
||||||
|
"Match": "echo *****"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
@@ -60,6 +60,9 @@ nav:
|
|||||||
- vs Conftest: docs/misconfiguration/comparison/conftest.md
|
- vs Conftest: docs/misconfiguration/comparison/conftest.md
|
||||||
- vs tfsec: docs/misconfiguration/comparison/tfsec.md
|
- vs tfsec: docs/misconfiguration/comparison/tfsec.md
|
||||||
- vs cfsec: docs/misconfiguration/comparison/cfsec.md
|
- vs cfsec: docs/misconfiguration/comparison/cfsec.md
|
||||||
|
- Secret:
|
||||||
|
- Scanning: docs/secret/scanning.md
|
||||||
|
- Configuration: docs/secret/configuration.md
|
||||||
- SBOM:
|
- SBOM:
|
||||||
- Overview: docs/sbom/index.md
|
- Overview: docs/sbom/index.md
|
||||||
- CycloneDX: docs/sbom/cyclonedx.md
|
- CycloneDX: docs/sbom/cyclonedx.md
|
||||||
|
|||||||
@@ -147,8 +147,8 @@ var (
|
|||||||
|
|
||||||
securityChecksFlag = cli.StringFlag{
|
securityChecksFlag = cli.StringFlag{
|
||||||
Name: "security-checks",
|
Name: "security-checks",
|
||||||
Value: types.SecurityCheckVulnerability,
|
Value: fmt.Sprintf("%s,%s", types.SecurityCheckVulnerability, types.SecurityCheckSecret),
|
||||||
Usage: "comma-separated list of what security issues to detect (vuln,config)",
|
Usage: "comma-separated list of what security issues to detect (vuln,config,secret)",
|
||||||
EnvVars: []string{"TRIVY_SECURITY_CHECKS"},
|
EnvVars: []string{"TRIVY_SECURITY_CHECKS"},
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -332,6 +332,13 @@ var (
|
|||||||
EnvVars: []string{"TRIVY_DB_REPOSITORY"},
|
EnvVars: []string{"TRIVY_DB_REPOSITORY"},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
secretConfig = cli.StringFlag{
|
||||||
|
Name: "secret-config",
|
||||||
|
Usage: "specify a path to config file for secret scanning",
|
||||||
|
Value: "trivy-secret.yaml",
|
||||||
|
EnvVars: []string{"TRIVY_SECRET_CONFIG"},
|
||||||
|
}
|
||||||
|
|
||||||
// Global flags
|
// Global flags
|
||||||
globalFlags = []cli.Flag{
|
globalFlags = []cli.Flag{
|
||||||
&quietFlag,
|
&quietFlag,
|
||||||
@@ -456,6 +463,7 @@ func NewImageCommand() *cli.Command {
|
|||||||
&offlineScan,
|
&offlineScan,
|
||||||
&insecureFlag,
|
&insecureFlag,
|
||||||
&dbRepositoryFlag,
|
&dbRepositoryFlag,
|
||||||
|
&secretConfig,
|
||||||
stringSliceFlag(skipFiles),
|
stringSliceFlag(skipFiles),
|
||||||
stringSliceFlag(skipDirs),
|
stringSliceFlag(skipDirs),
|
||||||
},
|
},
|
||||||
@@ -493,6 +501,7 @@ func NewFilesystemCommand() *cli.Command {
|
|||||||
&listAllPackages,
|
&listAllPackages,
|
||||||
&offlineScan,
|
&offlineScan,
|
||||||
&dbRepositoryFlag,
|
&dbRepositoryFlag,
|
||||||
|
&secretConfig,
|
||||||
stringSliceFlag(skipFiles),
|
stringSliceFlag(skipFiles),
|
||||||
stringSliceFlag(skipDirs),
|
stringSliceFlag(skipDirs),
|
||||||
|
|
||||||
@@ -540,6 +549,7 @@ func NewRootfsCommand() *cli.Command {
|
|||||||
&listAllPackages,
|
&listAllPackages,
|
||||||
&offlineScan,
|
&offlineScan,
|
||||||
&dbRepositoryFlag,
|
&dbRepositoryFlag,
|
||||||
|
&secretConfig,
|
||||||
stringSliceFlag(skipFiles),
|
stringSliceFlag(skipFiles),
|
||||||
stringSliceFlag(skipDirs),
|
stringSliceFlag(skipDirs),
|
||||||
stringSliceFlag(configPolicy),
|
stringSliceFlag(configPolicy),
|
||||||
@@ -584,6 +594,7 @@ func NewRepositoryCommand() *cli.Command {
|
|||||||
&offlineScan,
|
&offlineScan,
|
||||||
&insecureFlag,
|
&insecureFlag,
|
||||||
&dbRepositoryFlag,
|
&dbRepositoryFlag,
|
||||||
|
&secretConfig,
|
||||||
stringSliceFlag(skipFiles),
|
stringSliceFlag(skipFiles),
|
||||||
stringSliceFlag(skipDirs),
|
stringSliceFlag(skipDirs),
|
||||||
},
|
},
|
||||||
@@ -620,6 +631,7 @@ func NewClientCommand() *cli.Command {
|
|||||||
&listAllPackages,
|
&listAllPackages,
|
||||||
&offlineScan,
|
&offlineScan,
|
||||||
&insecureFlag,
|
&insecureFlag,
|
||||||
|
&secretConfig,
|
||||||
|
|
||||||
&token,
|
&token,
|
||||||
&tokenHeader,
|
&tokenHeader,
|
||||||
|
|||||||
@@ -12,8 +12,7 @@ import (
|
|||||||
|
|
||||||
// filesystemStandaloneScanner initializes a filesystem scanner in standalone mode
|
// filesystemStandaloneScanner initializes a filesystem scanner in standalone mode
|
||||||
func filesystemStandaloneScanner(ctx context.Context, conf scannerConfig) (scanner.Scanner, func(), error) {
|
func filesystemStandaloneScanner(ctx context.Context, conf scannerConfig) (scanner.Scanner, func(), error) {
|
||||||
s, cleanup, err := initializeFilesystemScanner(ctx, conf.Target, conf.ArtifactCache, conf.LocalArtifactCache,
|
s, cleanup, err := initializeFilesystemScanner(ctx, conf.Target, conf.ArtifactCache, conf.LocalArtifactCache, conf.ArtifactOption)
|
||||||
conf.ArtifactOption, conf.MisconfOption)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return scanner.Scanner{}, func() {}, xerrors.Errorf("unable to initialize a filesystem scanner: %w", err)
|
return scanner.Scanner{}, func() {}, xerrors.Errorf("unable to initialize a filesystem scanner: %w", err)
|
||||||
}
|
}
|
||||||
@@ -22,8 +21,7 @@ func filesystemStandaloneScanner(ctx context.Context, conf scannerConfig) (scann
|
|||||||
|
|
||||||
// filesystemRemoteScanner initializes a filesystem scanner in client/server mode
|
// filesystemRemoteScanner initializes a filesystem scanner in client/server mode
|
||||||
func filesystemRemoteScanner(ctx context.Context, conf scannerConfig) (scanner.Scanner, func(), error) {
|
func filesystemRemoteScanner(ctx context.Context, conf scannerConfig) (scanner.Scanner, func(), error) {
|
||||||
s, cleanup, err := initializeRemoteFilesystemScanner(ctx, conf.Target, conf.ArtifactCache, conf.RemoteOption,
|
s, cleanup, err := initializeRemoteFilesystemScanner(ctx, conf.Target, conf.ArtifactCache, conf.RemoteOption, conf.ArtifactOption)
|
||||||
conf.ArtifactOption, conf.MisconfOption)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return scanner.Scanner{}, func() {}, xerrors.Errorf("unable to initialize a filesystem scanner: %w", err)
|
return scanner.Scanner{}, func() {}, xerrors.Errorf("unable to initialize a filesystem scanner: %w", err)
|
||||||
}
|
}
|
||||||
@@ -39,6 +37,7 @@ func FilesystemRun(ctx *cli.Context) error {
|
|||||||
|
|
||||||
// Disable the individual package scanning
|
// Disable the individual package scanning
|
||||||
opt.DisabledAnalyzers = analyzer.TypeIndividualPkgs
|
opt.DisabledAnalyzers = analyzer.TypeIndividualPkgs
|
||||||
|
//opt.DisabledAnalyzers = append(opt.DisabledAnalyzers, analyzer.TypeSecret)
|
||||||
|
|
||||||
// client/server mode
|
// client/server mode
|
||||||
if opt.RemoteAddr != "" {
|
if opt.RemoteAddr != "" {
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ func imageScanner(ctx context.Context, conf scannerConfig) (scanner.Scanner, fun
|
|||||||
return scanner.Scanner{}, nil, err
|
return scanner.Scanner{}, nil, err
|
||||||
}
|
}
|
||||||
s, cleanup, err := initializeDockerScanner(ctx, conf.Target, conf.ArtifactCache, conf.LocalArtifactCache,
|
s, cleanup, err := initializeDockerScanner(ctx, conf.Target, conf.ArtifactCache, conf.LocalArtifactCache,
|
||||||
dockerOpt, conf.ArtifactOption, conf.MisconfOption)
|
dockerOpt, conf.ArtifactOption)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return scanner.Scanner{}, func() {}, xerrors.Errorf("unable to initialize a docker scanner: %w", err)
|
return scanner.Scanner{}, func() {}, xerrors.Errorf("unable to initialize a docker scanner: %w", err)
|
||||||
}
|
}
|
||||||
@@ -29,8 +29,7 @@ func imageScanner(ctx context.Context, conf scannerConfig) (scanner.Scanner, fun
|
|||||||
// archiveScanner initializes an image archive scanner in standalone mode
|
// archiveScanner initializes an image archive scanner in standalone mode
|
||||||
// $ trivy image --input alpine.tar
|
// $ trivy image --input alpine.tar
|
||||||
func archiveScanner(ctx context.Context, conf scannerConfig) (scanner.Scanner, func(), error) {
|
func archiveScanner(ctx context.Context, conf scannerConfig) (scanner.Scanner, func(), error) {
|
||||||
s, err := initializeArchiveScanner(ctx, conf.Target, conf.ArtifactCache, conf.LocalArtifactCache,
|
s, err := initializeArchiveScanner(ctx, conf.Target, conf.ArtifactCache, conf.LocalArtifactCache, conf.ArtifactOption)
|
||||||
conf.ArtifactOption, conf.MisconfOption)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return scanner.Scanner{}, func() {}, xerrors.Errorf("unable to initialize the archive scanner: %w", err)
|
return scanner.Scanner{}, func() {}, xerrors.Errorf("unable to initialize the archive scanner: %w", err)
|
||||||
}
|
}
|
||||||
@@ -48,7 +47,7 @@ func remoteImageScanner(ctx context.Context, conf scannerConfig) (
|
|||||||
}
|
}
|
||||||
|
|
||||||
s, cleanup, err := initializeRemoteDockerScanner(ctx, conf.Target, conf.ArtifactCache, conf.RemoteOption,
|
s, cleanup, err := initializeRemoteDockerScanner(ctx, conf.Target, conf.ArtifactCache, conf.RemoteOption,
|
||||||
dockerOpt, conf.ArtifactOption, conf.MisconfOption)
|
dockerOpt, conf.ArtifactOption)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return scanner.Scanner{}, nil, xerrors.Errorf("unable to initialize the docker scanner: %w", err)
|
return scanner.Scanner{}, nil, xerrors.Errorf("unable to initialize the docker scanner: %w", err)
|
||||||
}
|
}
|
||||||
@@ -59,8 +58,7 @@ func remoteImageScanner(ctx context.Context, conf scannerConfig) (
|
|||||||
// $ trivy image --server localhost:4954 --input alpine.tar
|
// $ trivy image --server localhost:4954 --input alpine.tar
|
||||||
func remoteArchiveScanner(ctx context.Context, conf scannerConfig) (scanner.Scanner, func(), error) {
|
func remoteArchiveScanner(ctx context.Context, conf scannerConfig) (scanner.Scanner, func(), error) {
|
||||||
// Scan tar file
|
// Scan tar file
|
||||||
s, err := initializeRemoteArchiveScanner(ctx, conf.Target, conf.ArtifactCache, conf.RemoteOption,
|
s, err := initializeRemoteArchiveScanner(ctx, conf.Target, conf.ArtifactCache, conf.RemoteOption, conf.ArtifactOption)
|
||||||
conf.ArtifactOption, conf.MisconfOption)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return scanner.Scanner{}, nil, xerrors.Errorf("unable to initialize the archive scanner: %w", err)
|
return scanner.Scanner{}, nil, xerrors.Errorf("unable to initialize the archive scanner: %w", err)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,7 +8,6 @@ import (
|
|||||||
|
|
||||||
"github.com/google/wire"
|
"github.com/google/wire"
|
||||||
|
|
||||||
"github.com/aquasecurity/fanal/analyzer/config"
|
|
||||||
"github.com/aquasecurity/fanal/artifact"
|
"github.com/aquasecurity/fanal/artifact"
|
||||||
"github.com/aquasecurity/fanal/cache"
|
"github.com/aquasecurity/fanal/cache"
|
||||||
"github.com/aquasecurity/fanal/types"
|
"github.com/aquasecurity/fanal/types"
|
||||||
@@ -24,8 +23,8 @@ import (
|
|||||||
// initializeDockerScanner is for container image scanning in standalone mode
|
// initializeDockerScanner is for container image scanning in standalone mode
|
||||||
// e.g. dockerd, container registry, podman, etc.
|
// e.g. dockerd, container registry, podman, etc.
|
||||||
func initializeDockerScanner(ctx context.Context, imageName string, artifactCache cache.ArtifactCache,
|
func initializeDockerScanner(ctx context.Context, imageName string, artifactCache cache.ArtifactCache,
|
||||||
localArtifactCache cache.LocalArtifactCache, dockerOpt types.DockerOption, artifactOption artifact.Option,
|
localArtifactCache cache.LocalArtifactCache, dockerOpt types.DockerOption, artifactOption artifact.Option) (
|
||||||
configScannerOption config.ScannerOption) (scanner.Scanner, func(), error) {
|
scanner.Scanner, func(), error) {
|
||||||
wire.Build(scanner.StandaloneDockerSet)
|
wire.Build(scanner.StandaloneDockerSet)
|
||||||
return scanner.Scanner{}, nil, nil
|
return scanner.Scanner{}, nil, nil
|
||||||
}
|
}
|
||||||
@@ -33,23 +32,20 @@ func initializeDockerScanner(ctx context.Context, imageName string, artifactCach
|
|||||||
// initializeArchiveScanner is for container image archive scanning in standalone mode
|
// initializeArchiveScanner is for container image archive scanning in standalone mode
|
||||||
// e.g. docker save -o alpine.tar alpine:3.15
|
// e.g. docker save -o alpine.tar alpine:3.15
|
||||||
func initializeArchiveScanner(ctx context.Context, filePath string, artifactCache cache.ArtifactCache,
|
func initializeArchiveScanner(ctx context.Context, filePath string, artifactCache cache.ArtifactCache,
|
||||||
localArtifactCache cache.LocalArtifactCache, artifactOption artifact.Option,
|
localArtifactCache cache.LocalArtifactCache, artifactOption artifact.Option) (scanner.Scanner, error) {
|
||||||
configScannerOption config.ScannerOption) (scanner.Scanner, error) {
|
|
||||||
wire.Build(scanner.StandaloneArchiveSet)
|
wire.Build(scanner.StandaloneArchiveSet)
|
||||||
return scanner.Scanner{}, nil
|
return scanner.Scanner{}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// initializeFilesystemScanner is for filesystem scanning in standalone mode
|
// initializeFilesystemScanner is for filesystem scanning in standalone mode
|
||||||
func initializeFilesystemScanner(ctx context.Context, path string, artifactCache cache.ArtifactCache,
|
func initializeFilesystemScanner(ctx context.Context, path string, artifactCache cache.ArtifactCache,
|
||||||
localArtifactCache cache.LocalArtifactCache, artifactOption artifact.Option,
|
localArtifactCache cache.LocalArtifactCache, artifactOption artifact.Option) (scanner.Scanner, func(), error) {
|
||||||
configScannerOption config.ScannerOption) (scanner.Scanner, func(), error) {
|
|
||||||
wire.Build(scanner.StandaloneFilesystemSet)
|
wire.Build(scanner.StandaloneFilesystemSet)
|
||||||
return scanner.Scanner{}, nil, nil
|
return scanner.Scanner{}, nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func initializeRepositoryScanner(ctx context.Context, url string, artifactCache cache.ArtifactCache,
|
func initializeRepositoryScanner(ctx context.Context, url string, artifactCache cache.ArtifactCache,
|
||||||
localArtifactCache cache.LocalArtifactCache, artifactOption artifact.Option,
|
localArtifactCache cache.LocalArtifactCache, artifactOption artifact.Option) (scanner.Scanner, func(), error) {
|
||||||
configScannerOption config.ScannerOption) (scanner.Scanner, func(), error) {
|
|
||||||
wire.Build(scanner.StandaloneRepositorySet)
|
wire.Build(scanner.StandaloneRepositorySet)
|
||||||
return scanner.Scanner{}, nil, nil
|
return scanner.Scanner{}, nil, nil
|
||||||
}
|
}
|
||||||
@@ -66,8 +62,7 @@ func initializeResultClient() result.Client {
|
|||||||
// initializeRemoteDockerScanner is for container image scanning in client/server mode
|
// initializeRemoteDockerScanner is for container image scanning in client/server mode
|
||||||
// e.g. dockerd, container registry, podman, etc.
|
// e.g. dockerd, container registry, podman, etc.
|
||||||
func initializeRemoteDockerScanner(ctx context.Context, imageName string, artifactCache cache.ArtifactCache,
|
func initializeRemoteDockerScanner(ctx context.Context, imageName string, artifactCache cache.ArtifactCache,
|
||||||
remoteScanOptions client.ScannerOption, dockerOpt types.DockerOption, artifactOption artifact.Option,
|
remoteScanOptions client.ScannerOption, dockerOpt types.DockerOption, artifactOption artifact.Option) (
|
||||||
configScannerOption config.ScannerOption) (
|
|
||||||
scanner.Scanner, func(), error) {
|
scanner.Scanner, func(), error) {
|
||||||
wire.Build(scanner.RemoteDockerSet)
|
wire.Build(scanner.RemoteDockerSet)
|
||||||
return scanner.Scanner{}, nil, nil
|
return scanner.Scanner{}, nil, nil
|
||||||
@@ -76,16 +71,14 @@ func initializeRemoteDockerScanner(ctx context.Context, imageName string, artifa
|
|||||||
// initializeRemoteArchiveScanner is for container image archive scanning in client/server mode
|
// initializeRemoteArchiveScanner is for container image archive scanning in client/server mode
|
||||||
// e.g. docker save -o alpine.tar alpine:3.15
|
// e.g. docker save -o alpine.tar alpine:3.15
|
||||||
func initializeRemoteArchiveScanner(ctx context.Context, filePath string, artifactCache cache.ArtifactCache,
|
func initializeRemoteArchiveScanner(ctx context.Context, filePath string, artifactCache cache.ArtifactCache,
|
||||||
remoteScanOptions client.ScannerOption, artifactOption artifact.Option, configScannerOption config.ScannerOption) (
|
remoteScanOptions client.ScannerOption, artifactOption artifact.Option) (scanner.Scanner, error) {
|
||||||
scanner.Scanner, error) {
|
|
||||||
wire.Build(scanner.RemoteArchiveSet)
|
wire.Build(scanner.RemoteArchiveSet)
|
||||||
return scanner.Scanner{}, nil
|
return scanner.Scanner{}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// initializeRemoteFilesystemScanner is for filesystem scanning in client/server mode
|
// initializeRemoteFilesystemScanner is for filesystem scanning in client/server mode
|
||||||
func initializeRemoteFilesystemScanner(ctx context.Context, path string, artifactCache cache.ArtifactCache,
|
func initializeRemoteFilesystemScanner(ctx context.Context, path string, artifactCache cache.ArtifactCache,
|
||||||
remoteScanOptions client.ScannerOption, artifactOption artifact.Option, configScannerOption config.ScannerOption) (
|
remoteScanOptions client.ScannerOption, artifactOption artifact.Option) (scanner.Scanner, func(), error) {
|
||||||
scanner.Scanner, func(), error) {
|
|
||||||
wire.Build(scanner.RemoteFilesystemSet)
|
wire.Build(scanner.RemoteFilesystemSet)
|
||||||
return scanner.Scanner{}, nil, nil
|
return scanner.Scanner{}, nil, nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -19,6 +19,7 @@ type Option struct {
|
|||||||
option.ConfigOption
|
option.ConfigOption
|
||||||
option.RemoteOption
|
option.RemoteOption
|
||||||
option.SbomOption
|
option.SbomOption
|
||||||
|
option.SecretOption
|
||||||
|
|
||||||
// We don't want to allow disabled analyzers to be passed by users,
|
// We don't want to allow disabled analyzers to be passed by users,
|
||||||
// but it differs depending on scanning modes.
|
// but it differs depending on scanning modes.
|
||||||
@@ -42,6 +43,7 @@ func NewOption(c *cli.Context) (Option, error) {
|
|||||||
ConfigOption: option.NewConfigOption(c),
|
ConfigOption: option.NewConfigOption(c),
|
||||||
RemoteOption: option.NewRemoteOption(c),
|
RemoteOption: option.NewRemoteOption(c),
|
||||||
SbomOption: option.NewSbomOption(c),
|
SbomOption: option.NewSbomOption(c),
|
||||||
|
SecretOption: option.NewSecretOption(c),
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -13,8 +13,7 @@ import (
|
|||||||
|
|
||||||
// filesystemStandaloneScanner initializes a repository scanner in standalone mode
|
// filesystemStandaloneScanner initializes a repository scanner in standalone mode
|
||||||
func repositoryScanner(ctx context.Context, conf scannerConfig) (scanner.Scanner, func(), error) {
|
func repositoryScanner(ctx context.Context, conf scannerConfig) (scanner.Scanner, func(), error) {
|
||||||
s, cleanup, err := initializeRepositoryScanner(ctx, conf.Target, conf.ArtifactCache, conf.LocalArtifactCache,
|
s, cleanup, err := initializeRepositoryScanner(ctx, conf.Target, conf.ArtifactCache, conf.LocalArtifactCache, conf.ArtifactOption)
|
||||||
conf.ArtifactOption, conf.MisconfOption)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return scanner.Scanner{}, func() {}, xerrors.Errorf("unable to initialize a filesystem scanner: %w", err)
|
return scanner.Scanner{}, func() {}, xerrors.Errorf("unable to initialize a filesystem scanner: %w", err)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ import (
|
|||||||
|
|
||||||
"github.com/aquasecurity/fanal/analyzer"
|
"github.com/aquasecurity/fanal/analyzer"
|
||||||
"github.com/aquasecurity/fanal/analyzer/config"
|
"github.com/aquasecurity/fanal/analyzer/config"
|
||||||
|
"github.com/aquasecurity/fanal/analyzer/secret"
|
||||||
"github.com/aquasecurity/fanal/artifact"
|
"github.com/aquasecurity/fanal/artifact"
|
||||||
"github.com/aquasecurity/fanal/cache"
|
"github.com/aquasecurity/fanal/cache"
|
||||||
"github.com/aquasecurity/trivy-db/pkg/db"
|
"github.com/aquasecurity/trivy-db/pkg/db"
|
||||||
@@ -41,9 +42,6 @@ type scannerConfig struct {
|
|||||||
|
|
||||||
// Artifact options
|
// Artifact options
|
||||||
ArtifactOption artifact.Option
|
ArtifactOption artifact.Option
|
||||||
|
|
||||||
// Misconfiguration scanning options
|
|
||||||
MisconfOption config.ScannerOption
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// InitializeScanner defines the initialize function signature of scanner
|
// InitializeScanner defines the initialize function signature of scanner
|
||||||
@@ -189,11 +187,16 @@ func disabledAnalyzers(opt Option) []analyzer.Type {
|
|||||||
analyzers = append(analyzers, analyzer.TypeApkCommand)
|
analyzers = append(analyzers, analyzer.TypeApkCommand)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Don't analyze programming language packages when not running in 'library' mode
|
// Do not analyze programming language packages when not running in 'library' mode
|
||||||
if !slices.Contains(opt.VulnType, types.VulnTypeLibrary) {
|
if !slices.Contains(opt.VulnType, types.VulnTypeLibrary) {
|
||||||
analyzers = append(analyzers, analyzer.TypeLanguages...)
|
analyzers = append(analyzers, analyzer.TypeLanguages...)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Do not perform secret scanning when it is not specified.
|
||||||
|
if !slices.Contains(opt.SecurityChecks, types.SecurityCheckSecret) {
|
||||||
|
analyzers = append(analyzers, analyzer.TypeSecret)
|
||||||
|
}
|
||||||
|
|
||||||
return analyzers
|
return analyzers
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -246,8 +249,15 @@ func scan(ctx context.Context, opt Option, initializeScanner InitializeScanner,
|
|||||||
InsecureSkipTLS: opt.Insecure,
|
InsecureSkipTLS: opt.Insecure,
|
||||||
Offline: opt.OfflineScan,
|
Offline: opt.OfflineScan,
|
||||||
NoProgress: opt.NoProgress || opt.Quiet,
|
NoProgress: opt.NoProgress || opt.Quiet,
|
||||||
|
|
||||||
|
// For misconfiguration scanning
|
||||||
|
MisconfScannerOption: configScannerOptions,
|
||||||
|
|
||||||
|
// For secret scanning
|
||||||
|
SecretScannerOption: secret.ScannerOption{
|
||||||
|
ConfigPath: opt.SecretConfigPath,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
MisconfOption: configScannerOptions,
|
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return types.Report{}, xerrors.Errorf("unable to initialize a scanner: %w", err)
|
return types.Report{}, xerrors.Errorf("unable to initialize a scanner: %w", err)
|
||||||
@@ -269,7 +279,7 @@ func filter(ctx context.Context, opt Option, report types.Report) (types.Report,
|
|||||||
if opt.RemoteAddr == "" {
|
if opt.RemoteAddr == "" {
|
||||||
resultClient.FillVulnerabilityInfo(results[i].Vulnerabilities, results[i].Type)
|
resultClient.FillVulnerabilityInfo(results[i].Vulnerabilities, results[i].Type)
|
||||||
}
|
}
|
||||||
vulns, misconfSummary, misconfs, err := resultClient.Filter(ctx, results[i].Vulnerabilities, results[i].Misconfigurations,
|
vulns, misconfSummary, misconfs, secrets, err := resultClient.Filter(ctx, results[i].Vulnerabilities, results[i].Misconfigurations, results[i].Secrets,
|
||||||
opt.Severities, opt.IgnoreUnfixed, opt.IncludeNonFailures, opt.IgnoreFile, opt.IgnorePolicy)
|
opt.Severities, opt.IgnoreUnfixed, opt.IncludeNonFailures, opt.IgnoreFile, opt.IgnorePolicy)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return types.Report{}, xerrors.Errorf("unable to filter vulnerabilities: %w", err)
|
return types.Report{}, xerrors.Errorf("unable to filter vulnerabilities: %w", err)
|
||||||
@@ -277,6 +287,7 @@ func filter(ctx context.Context, opt Option, report types.Report) (types.Report,
|
|||||||
results[i].Vulnerabilities = vulns
|
results[i].Vulnerabilities = vulns
|
||||||
results[i].Misconfigurations = misconfs
|
results[i].Misconfigurations = misconfs
|
||||||
results[i].MisconfSummary = misconfSummary
|
results[i].MisconfSummary = misconfSummary
|
||||||
|
results[i].Secrets = secrets
|
||||||
}
|
}
|
||||||
return report, nil
|
return report, nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,7 +8,6 @@ package artifact
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"github.com/aquasecurity/fanal/analyzer/config"
|
|
||||||
"github.com/aquasecurity/fanal/applier"
|
"github.com/aquasecurity/fanal/applier"
|
||||||
"github.com/aquasecurity/fanal/artifact"
|
"github.com/aquasecurity/fanal/artifact"
|
||||||
image2 "github.com/aquasecurity/fanal/artifact/image"
|
image2 "github.com/aquasecurity/fanal/artifact/image"
|
||||||
@@ -29,7 +28,7 @@ import (
|
|||||||
|
|
||||||
// initializeDockerScanner is for container image scanning in standalone mode
|
// initializeDockerScanner is for container image scanning in standalone mode
|
||||||
// e.g. dockerd, container registry, podman, etc.
|
// e.g. dockerd, container registry, podman, etc.
|
||||||
func initializeDockerScanner(ctx context.Context, imageName string, artifactCache cache.ArtifactCache, localArtifactCache cache.LocalArtifactCache, dockerOpt types.DockerOption, artifactOption artifact.Option, configScannerOption config.ScannerOption) (scanner.Scanner, func(), error) {
|
func initializeDockerScanner(ctx context.Context, imageName string, artifactCache cache.ArtifactCache, localArtifactCache cache.LocalArtifactCache, dockerOpt types.DockerOption, artifactOption artifact.Option) (scanner.Scanner, func(), error) {
|
||||||
applierApplier := applier.NewApplier(localArtifactCache)
|
applierApplier := applier.NewApplier(localArtifactCache)
|
||||||
detector := ospkg.Detector{}
|
detector := ospkg.Detector{}
|
||||||
localScanner := local.NewScanner(applierApplier, detector)
|
localScanner := local.NewScanner(applierApplier, detector)
|
||||||
@@ -37,7 +36,7 @@ func initializeDockerScanner(ctx context.Context, imageName string, artifactCach
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return scanner.Scanner{}, nil, err
|
return scanner.Scanner{}, nil, err
|
||||||
}
|
}
|
||||||
artifactArtifact, err := image2.NewArtifact(typesImage, artifactCache, artifactOption, configScannerOption)
|
artifactArtifact, err := image2.NewArtifact(typesImage, artifactCache, artifactOption)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
cleanup()
|
cleanup()
|
||||||
return scanner.Scanner{}, nil, err
|
return scanner.Scanner{}, nil, err
|
||||||
@@ -50,7 +49,7 @@ func initializeDockerScanner(ctx context.Context, imageName string, artifactCach
|
|||||||
|
|
||||||
// initializeArchiveScanner is for container image archive scanning in standalone mode
|
// initializeArchiveScanner is for container image archive scanning in standalone mode
|
||||||
// e.g. docker save -o alpine.tar alpine:3.15
|
// e.g. docker save -o alpine.tar alpine:3.15
|
||||||
func initializeArchiveScanner(ctx context.Context, filePath string, artifactCache cache.ArtifactCache, localArtifactCache cache.LocalArtifactCache, artifactOption artifact.Option, configScannerOption config.ScannerOption) (scanner.Scanner, error) {
|
func initializeArchiveScanner(ctx context.Context, filePath string, artifactCache cache.ArtifactCache, localArtifactCache cache.LocalArtifactCache, artifactOption artifact.Option) (scanner.Scanner, error) {
|
||||||
applierApplier := applier.NewApplier(localArtifactCache)
|
applierApplier := applier.NewApplier(localArtifactCache)
|
||||||
detector := ospkg.Detector{}
|
detector := ospkg.Detector{}
|
||||||
localScanner := local.NewScanner(applierApplier, detector)
|
localScanner := local.NewScanner(applierApplier, detector)
|
||||||
@@ -58,7 +57,7 @@ func initializeArchiveScanner(ctx context.Context, filePath string, artifactCach
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return scanner.Scanner{}, err
|
return scanner.Scanner{}, err
|
||||||
}
|
}
|
||||||
artifactArtifact, err := image2.NewArtifact(typesImage, artifactCache, artifactOption, configScannerOption)
|
artifactArtifact, err := image2.NewArtifact(typesImage, artifactCache, artifactOption)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return scanner.Scanner{}, err
|
return scanner.Scanner{}, err
|
||||||
}
|
}
|
||||||
@@ -67,11 +66,11 @@ func initializeArchiveScanner(ctx context.Context, filePath string, artifactCach
|
|||||||
}
|
}
|
||||||
|
|
||||||
// initializeFilesystemScanner is for filesystem scanning in standalone mode
|
// initializeFilesystemScanner is for filesystem scanning in standalone mode
|
||||||
func initializeFilesystemScanner(ctx context.Context, path string, artifactCache cache.ArtifactCache, localArtifactCache cache.LocalArtifactCache, artifactOption artifact.Option, configScannerOption config.ScannerOption) (scanner.Scanner, func(), error) {
|
func initializeFilesystemScanner(ctx context.Context, path string, artifactCache cache.ArtifactCache, localArtifactCache cache.LocalArtifactCache, artifactOption artifact.Option) (scanner.Scanner, func(), error) {
|
||||||
applierApplier := applier.NewApplier(localArtifactCache)
|
applierApplier := applier.NewApplier(localArtifactCache)
|
||||||
detector := ospkg.Detector{}
|
detector := ospkg.Detector{}
|
||||||
localScanner := local.NewScanner(applierApplier, detector)
|
localScanner := local.NewScanner(applierApplier, detector)
|
||||||
artifactArtifact, err := local2.NewArtifact(path, artifactCache, artifactOption, configScannerOption)
|
artifactArtifact, err := local2.NewArtifact(path, artifactCache, artifactOption)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return scanner.Scanner{}, nil, err
|
return scanner.Scanner{}, nil, err
|
||||||
}
|
}
|
||||||
@@ -80,11 +79,11 @@ func initializeFilesystemScanner(ctx context.Context, path string, artifactCache
|
|||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func initializeRepositoryScanner(ctx context.Context, url string, artifactCache cache.ArtifactCache, localArtifactCache cache.LocalArtifactCache, artifactOption artifact.Option, configScannerOption config.ScannerOption) (scanner.Scanner, func(), error) {
|
func initializeRepositoryScanner(ctx context.Context, url string, artifactCache cache.ArtifactCache, localArtifactCache cache.LocalArtifactCache, artifactOption artifact.Option) (scanner.Scanner, func(), error) {
|
||||||
applierApplier := applier.NewApplier(localArtifactCache)
|
applierApplier := applier.NewApplier(localArtifactCache)
|
||||||
detector := ospkg.Detector{}
|
detector := ospkg.Detector{}
|
||||||
localScanner := local.NewScanner(applierApplier, detector)
|
localScanner := local.NewScanner(applierApplier, detector)
|
||||||
artifactArtifact, cleanup, err := remote.NewArtifact(url, artifactCache, artifactOption, configScannerOption)
|
artifactArtifact, cleanup, err := remote.NewArtifact(url, artifactCache, artifactOption)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return scanner.Scanner{}, nil, err
|
return scanner.Scanner{}, nil, err
|
||||||
}
|
}
|
||||||
@@ -95,20 +94,21 @@ func initializeRepositoryScanner(ctx context.Context, url string, artifactCache
|
|||||||
}
|
}
|
||||||
|
|
||||||
func initializeResultClient() result.Client {
|
func initializeResultClient() result.Client {
|
||||||
dbConfig := db.Config{}
|
config := db.Config{}
|
||||||
client := result.NewClient(dbConfig)
|
client := result.NewClient(config)
|
||||||
return client
|
return client
|
||||||
}
|
}
|
||||||
|
|
||||||
// initializeRemoteDockerScanner is for container image scanning in client/server mode
|
// initializeRemoteDockerScanner is for container image scanning in client/server mode
|
||||||
// e.g. dockerd, container registry, podman, etc.
|
// e.g. dockerd, container registry, podman, etc.
|
||||||
func initializeRemoteDockerScanner(ctx context.Context, imageName string, artifactCache cache.ArtifactCache, remoteScanOptions client.ScannerOption, dockerOpt types.DockerOption, artifactOption artifact.Option, configScannerOption config.ScannerOption) (scanner.Scanner, func(), error) {
|
func initializeRemoteDockerScanner(ctx context.Context, imageName string, artifactCache cache.ArtifactCache, remoteScanOptions client.ScannerOption, dockerOpt types.DockerOption, artifactOption artifact.Option) (scanner.Scanner, func(), error) {
|
||||||
clientScanner := client.NewScanner(remoteScanOptions)
|
v := _wireValue
|
||||||
|
clientScanner := client.NewScanner(remoteScanOptions, v...)
|
||||||
typesImage, cleanup, err := image.NewDockerImage(ctx, imageName, dockerOpt)
|
typesImage, cleanup, err := image.NewDockerImage(ctx, imageName, dockerOpt)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return scanner.Scanner{}, nil, err
|
return scanner.Scanner{}, nil, err
|
||||||
}
|
}
|
||||||
artifactArtifact, err := image2.NewArtifact(typesImage, artifactCache, artifactOption, configScannerOption)
|
artifactArtifact, err := image2.NewArtifact(typesImage, artifactCache, artifactOption)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
cleanup()
|
cleanup()
|
||||||
return scanner.Scanner{}, nil, err
|
return scanner.Scanner{}, nil, err
|
||||||
@@ -119,15 +119,20 @@ func initializeRemoteDockerScanner(ctx context.Context, imageName string, artifa
|
|||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
_wireValue = []client.Option(nil)
|
||||||
|
)
|
||||||
|
|
||||||
// initializeRemoteArchiveScanner is for container image archive scanning in client/server mode
|
// initializeRemoteArchiveScanner is for container image archive scanning in client/server mode
|
||||||
// e.g. docker save -o alpine.tar alpine:3.15
|
// e.g. docker save -o alpine.tar alpine:3.15
|
||||||
func initializeRemoteArchiveScanner(ctx context.Context, filePath string, artifactCache cache.ArtifactCache, remoteScanOptions client.ScannerOption, artifactOption artifact.Option, configScannerOption config.ScannerOption) (scanner.Scanner, error) {
|
func initializeRemoteArchiveScanner(ctx context.Context, filePath string, artifactCache cache.ArtifactCache, remoteScanOptions client.ScannerOption, artifactOption artifact.Option) (scanner.Scanner, error) {
|
||||||
clientScanner := client.NewScanner(remoteScanOptions)
|
v := _wireValue
|
||||||
|
clientScanner := client.NewScanner(remoteScanOptions, v...)
|
||||||
typesImage, err := image.NewArchiveImage(filePath)
|
typesImage, err := image.NewArchiveImage(filePath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return scanner.Scanner{}, err
|
return scanner.Scanner{}, err
|
||||||
}
|
}
|
||||||
artifactArtifact, err := image2.NewArtifact(typesImage, artifactCache, artifactOption, configScannerOption)
|
artifactArtifact, err := image2.NewArtifact(typesImage, artifactCache, artifactOption)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return scanner.Scanner{}, err
|
return scanner.Scanner{}, err
|
||||||
}
|
}
|
||||||
@@ -136,9 +141,10 @@ func initializeRemoteArchiveScanner(ctx context.Context, filePath string, artifa
|
|||||||
}
|
}
|
||||||
|
|
||||||
// initializeRemoteFilesystemScanner is for filesystem scanning in client/server mode
|
// initializeRemoteFilesystemScanner is for filesystem scanning in client/server mode
|
||||||
func initializeRemoteFilesystemScanner(ctx context.Context, path string, artifactCache cache.ArtifactCache, remoteScanOptions client.ScannerOption, artifactOption artifact.Option, configScannerOption config.ScannerOption) (scanner.Scanner, func(), error) {
|
func initializeRemoteFilesystemScanner(ctx context.Context, path string, artifactCache cache.ArtifactCache, remoteScanOptions client.ScannerOption, artifactOption artifact.Option) (scanner.Scanner, func(), error) {
|
||||||
clientScanner := client.NewScanner(remoteScanOptions)
|
v := _wireValue
|
||||||
artifactArtifact, err := local2.NewArtifact(path, artifactCache, artifactOption, configScannerOption)
|
clientScanner := client.NewScanner(remoteScanOptions, v...)
|
||||||
|
artifactArtifact, err := local2.NewArtifact(path, artifactCache, artifactOption)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return scanner.Scanner{}, nil, err
|
return scanner.Scanner{}, nil, err
|
||||||
}
|
}
|
||||||
@@ -148,7 +154,7 @@ func initializeRemoteFilesystemScanner(ctx context.Context, path string, artifac
|
|||||||
}
|
}
|
||||||
|
|
||||||
func initializeRemoteResultClient() result.Client {
|
func initializeRemoteResultClient() result.Client {
|
||||||
dbConfig := db.Config{}
|
config := db.Config{}
|
||||||
resultClient := result.NewClient(dbConfig)
|
resultClient := result.NewClient(config)
|
||||||
return resultClient
|
return resultClient
|
||||||
}
|
}
|
||||||
|
|||||||
17
pkg/commands/option/secret.go
Normal file
17
pkg/commands/option/secret.go
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
package option
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/urfave/cli/v2"
|
||||||
|
)
|
||||||
|
|
||||||
|
// SecretOption holds the options for secret scanning
|
||||||
|
type SecretOption struct {
|
||||||
|
SecretConfigPath string
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewSecretOption is the factory method to return secret options
|
||||||
|
func NewSecretOption(c *cli.Context) SecretOption {
|
||||||
|
return SecretOption{
|
||||||
|
SecretConfigPath: c.String("secret-config"),
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -12,6 +12,7 @@ import (
|
|||||||
"github.com/olekukonko/tablewriter"
|
"github.com/olekukonko/tablewriter"
|
||||||
"golang.org/x/exp/slices"
|
"golang.org/x/exp/slices"
|
||||||
|
|
||||||
|
ftypes "github.com/aquasecurity/fanal/types"
|
||||||
dbTypes "github.com/aquasecurity/trivy-db/pkg/types"
|
dbTypes "github.com/aquasecurity/trivy-db/pkg/types"
|
||||||
"github.com/aquasecurity/trivy/pkg/log"
|
"github.com/aquasecurity/trivy/pkg/log"
|
||||||
"github.com/aquasecurity/trivy/pkg/types"
|
"github.com/aquasecurity/trivy/pkg/types"
|
||||||
@@ -42,33 +43,41 @@ func (tw TableWriter) write(result types.Result) {
|
|||||||
table := tablewriter.NewWriter(tw.Output)
|
table := tablewriter.NewWriter(tw.Output)
|
||||||
|
|
||||||
var severityCount map[string]int
|
var severityCount map[string]int
|
||||||
if len(result.Vulnerabilities) != 0 {
|
switch {
|
||||||
|
case len(result.Vulnerabilities) != 0:
|
||||||
severityCount = tw.writeVulnerabilities(table, result.Vulnerabilities)
|
severityCount = tw.writeVulnerabilities(table, result.Vulnerabilities)
|
||||||
} else if len(result.Misconfigurations) != 0 {
|
case len(result.Misconfigurations) != 0:
|
||||||
severityCount = tw.writeMisconfigurations(table, result.Misconfigurations)
|
severityCount = tw.writeMisconfigurations(table, result.Misconfigurations)
|
||||||
|
case len(result.Secrets) != 0:
|
||||||
|
severityCount = tw.writeSecrets(table, result.Secrets)
|
||||||
}
|
}
|
||||||
|
|
||||||
total, summaries := tw.summary(severityCount)
|
total, summaries := tw.summary(severityCount)
|
||||||
|
|
||||||
target := result.Target
|
target := result.Target
|
||||||
if result.Class != types.ClassOSPkg {
|
if result.Class == types.ClassSecret {
|
||||||
|
if len(result.Secrets) == 0 {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
target += " (secrets)"
|
||||||
|
} else if result.Class != types.ClassOSPkg {
|
||||||
target += fmt.Sprintf(" (%s)", result.Type)
|
target += fmt.Sprintf(" (%s)", result.Type)
|
||||||
}
|
}
|
||||||
|
|
||||||
fmt.Printf("\n%s\n", target)
|
fmt.Printf("\n%s\n", target)
|
||||||
fmt.Println(strings.Repeat("=", len(target)))
|
fmt.Println(strings.Repeat("=", len(target)))
|
||||||
if result.MisconfSummary != nil {
|
if result.Class == types.ClassConfig {
|
||||||
// for misconfigurations
|
// for misconfigurations
|
||||||
summary := result.MisconfSummary
|
summary := result.MisconfSummary
|
||||||
fmt.Printf("Tests: %d (SUCCESSES: %d, FAILURES: %d, EXCEPTIONS: %d)\n",
|
fmt.Printf("Tests: %d (SUCCESSES: %d, FAILURES: %d, EXCEPTIONS: %d)\n",
|
||||||
summary.Successes+summary.Failures+summary.Exceptions, summary.Successes, summary.Failures, summary.Exceptions)
|
summary.Successes+summary.Failures+summary.Exceptions, summary.Successes, summary.Failures, summary.Exceptions)
|
||||||
fmt.Printf("Failures: %d (%s)\n\n", total, strings.Join(summaries, ", "))
|
fmt.Printf("Failures: %d (%s)\n\n", total, strings.Join(summaries, ", "))
|
||||||
} else {
|
} else {
|
||||||
// for vulnerabilities
|
// for vulnerabilities and secrets
|
||||||
fmt.Printf("Total: %d (%s)\n\n", total, strings.Join(summaries, ", "))
|
fmt.Printf("Total: %d (%s)\n\n", total, strings.Join(summaries, ", "))
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(result.Vulnerabilities) == 0 && len(result.Misconfigurations) == 0 {
|
if len(result.Vulnerabilities) == 0 && len(result.Misconfigurations) == 0 && len(result.Secrets) == 0 {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -134,6 +143,20 @@ func (tw TableWriter) writeMisconfigurations(table *tablewriter.Table, misconfs
|
|||||||
return severityCount
|
return severityCount
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (tw TableWriter) writeSecrets(table *tablewriter.Table, secrets []ftypes.SecretFinding) map[string]int {
|
||||||
|
table.SetColWidth(80)
|
||||||
|
|
||||||
|
alignment := []int{tablewriter.ALIGN_CENTER, tablewriter.ALIGN_CENTER, tablewriter.ALIGN_CENTER,
|
||||||
|
tablewriter.ALIGN_CENTER, tablewriter.ALIGN_LEFT}
|
||||||
|
header := []string{"Category", "Description", "Severity", "Line No", "Match"}
|
||||||
|
|
||||||
|
table.SetColumnAlignment(alignment)
|
||||||
|
table.SetHeader(header)
|
||||||
|
severityCount := tw.setSecretRows(table, secrets)
|
||||||
|
|
||||||
|
return severityCount
|
||||||
|
}
|
||||||
|
|
||||||
func (tw TableWriter) setVulnerabilityRows(table *tablewriter.Table, vulns []types.DetectedVulnerability) map[string]int {
|
func (tw TableWriter) setVulnerabilityRows(table *tablewriter.Table, vulns []types.DetectedVulnerability) map[string]int {
|
||||||
severityCount := map[string]int{}
|
severityCount := map[string]int{}
|
||||||
for _, v := range vulns {
|
for _, v := range vulns {
|
||||||
@@ -212,6 +235,24 @@ func (tw TableWriter) setMisconfRows(table *tablewriter.Table, misconfs []types.
|
|||||||
return severityCount
|
return severityCount
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (tw TableWriter) setSecretRows(table *tablewriter.Table, secrets []ftypes.SecretFinding) map[string]int {
|
||||||
|
severityCount := map[string]int{}
|
||||||
|
for _, secret := range secrets {
|
||||||
|
severity := secret.Severity
|
||||||
|
severityCount[severity]++
|
||||||
|
if tw.Output == os.Stdout {
|
||||||
|
severity = dbTypes.ColorizeSeverity(severity)
|
||||||
|
}
|
||||||
|
|
||||||
|
row := []string{string(secret.Category), secret.Title, severity,
|
||||||
|
fmt.Sprint(secret.StartLine), // multi-line is not supported for now.
|
||||||
|
secret.Match}
|
||||||
|
|
||||||
|
table.Append(row)
|
||||||
|
}
|
||||||
|
return severityCount
|
||||||
|
}
|
||||||
|
|
||||||
func (tw TableWriter) outputTrace(result types.Result) {
|
func (tw TableWriter) outputTrace(result types.Result) {
|
||||||
blue := color.New(color.FgBlue).SprintFunc()
|
blue := color.New(color.FgBlue).SprintFunc()
|
||||||
green := color.New(color.FgGreen).SprintfFunc()
|
green := color.New(color.FgGreen).SprintfFunc()
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ import (
|
|||||||
"golang.org/x/exp/slices"
|
"golang.org/x/exp/slices"
|
||||||
"golang.org/x/xerrors"
|
"golang.org/x/xerrors"
|
||||||
|
|
||||||
|
ftypes "github.com/aquasecurity/fanal/types"
|
||||||
"github.com/aquasecurity/trivy-db/pkg/db"
|
"github.com/aquasecurity/trivy-db/pkg/db"
|
||||||
dbTypes "github.com/aquasecurity/trivy-db/pkg/types"
|
dbTypes "github.com/aquasecurity/trivy-db/pkg/types"
|
||||||
"github.com/aquasecurity/trivy-db/pkg/vulnsrc/vulnerability"
|
"github.com/aquasecurity/trivy-db/pkg/vulnsrc/vulnerability"
|
||||||
@@ -131,24 +132,25 @@ func (c Client) getPrimaryURL(vulnID string, refs []string, source dbTypes.Sourc
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Filter filter out the vulnerabilities
|
// Filter filter out the vulnerabilities
|
||||||
func (c Client) Filter(ctx context.Context, vulns []types.DetectedVulnerability, misconfs []types.DetectedMisconfiguration,
|
func (c Client) Filter(ctx context.Context, vulns []types.DetectedVulnerability, misconfs []types.DetectedMisconfiguration, secrets []ftypes.SecretFinding,
|
||||||
severities []dbTypes.Severity, ignoreUnfixed, includeNonFailures bool, ignoreFile, policyFile string) (
|
severities []dbTypes.Severity, ignoreUnfixed, includeNonFailures bool, ignoreFile, policyFile string) (
|
||||||
[]types.DetectedVulnerability, *types.MisconfSummary, []types.DetectedMisconfiguration, error) {
|
[]types.DetectedVulnerability, *types.MisconfSummary, []types.DetectedMisconfiguration, []ftypes.SecretFinding, error) {
|
||||||
ignoredIDs := getIgnoredIDs(ignoreFile)
|
ignoredIDs := getIgnoredIDs(ignoreFile)
|
||||||
|
|
||||||
filteredVulns := filterVulnerabilities(vulns, severities, ignoreUnfixed, ignoredIDs)
|
filteredVulns := filterVulnerabilities(vulns, severities, ignoreUnfixed, ignoredIDs)
|
||||||
misconfSummary, filteredMisconfs := filterMisconfigurations(misconfs, severities, includeNonFailures, ignoredIDs)
|
misconfSummary, filteredMisconfs := filterMisconfigurations(misconfs, severities, includeNonFailures, ignoredIDs)
|
||||||
|
filteredSecrets := filterSecrets(secrets, severities)
|
||||||
|
|
||||||
if policyFile != "" {
|
if policyFile != "" {
|
||||||
var err error
|
var err error
|
||||||
filteredVulns, filteredMisconfs, err = applyPolicy(ctx, filteredVulns, filteredMisconfs, policyFile)
|
filteredVulns, filteredMisconfs, err = applyPolicy(ctx, filteredVulns, filteredMisconfs, policyFile)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, nil, xerrors.Errorf("failed to apply the policy: %w", err)
|
return nil, nil, nil, nil, xerrors.Errorf("failed to apply the policy: %w", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
sort.Sort(types.BySeverity(filteredVulns))
|
sort.Sort(types.BySeverity(filteredVulns))
|
||||||
|
|
||||||
return filteredVulns, misconfSummary, filteredMisconfs, nil
|
return filteredVulns, misconfSummary, filteredMisconfs, filteredSecrets, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func filterVulnerabilities(vulns []types.DetectedVulnerability, severities []dbTypes.Severity,
|
func filterVulnerabilities(vulns []types.DetectedVulnerability, severities []dbTypes.Severity,
|
||||||
@@ -215,6 +217,20 @@ func filterMisconfigurations(misconfs []types.DetectedMisconfiguration, severiti
|
|||||||
return summary, filtered
|
return summary, filtered
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func filterSecrets(secrets []ftypes.SecretFinding, severities []dbTypes.Severity) []ftypes.SecretFinding {
|
||||||
|
var filtered []ftypes.SecretFinding
|
||||||
|
for _, secret := range secrets {
|
||||||
|
// Filter secrets by severity
|
||||||
|
for _, s := range severities {
|
||||||
|
if s.String() == secret.Severity {
|
||||||
|
filtered = append(filtered, secret)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return filtered
|
||||||
|
}
|
||||||
|
|
||||||
func summarize(status types.MisconfStatus, summary *types.MisconfSummary) {
|
func summarize(status types.MisconfStatus, summary *types.MisconfSummary) {
|
||||||
switch status {
|
switch status {
|
||||||
case types.StatusFailure:
|
case types.StatusFailure:
|
||||||
|
|||||||
@@ -363,6 +363,7 @@ func TestClient_Filter(t *testing.T) {
|
|||||||
type args struct {
|
type args struct {
|
||||||
vulns []types.DetectedVulnerability
|
vulns []types.DetectedVulnerability
|
||||||
misconfs []types.DetectedMisconfiguration
|
misconfs []types.DetectedMisconfiguration
|
||||||
|
secrets []ftypes.SecretFinding
|
||||||
severities []dbTypes.Severity
|
severities []dbTypes.Severity
|
||||||
ignoreUnfixed bool
|
ignoreUnfixed bool
|
||||||
ignoreFile string
|
ignoreFile string
|
||||||
@@ -374,6 +375,7 @@ func TestClient_Filter(t *testing.T) {
|
|||||||
wantVulns []types.DetectedVulnerability
|
wantVulns []types.DetectedVulnerability
|
||||||
wantMisconfSummary *types.MisconfSummary
|
wantMisconfSummary *types.MisconfSummary
|
||||||
wantMisconfs []types.DetectedMisconfiguration
|
wantMisconfs []types.DetectedMisconfiguration
|
||||||
|
wantSecrets []ftypes.SecretFinding
|
||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
name: "happy path",
|
name: "happy path",
|
||||||
@@ -443,6 +445,24 @@ func TestClient_Filter(t *testing.T) {
|
|||||||
Status: types.StatusPassed,
|
Status: types.StatusPassed,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
secrets: []ftypes.SecretFinding{
|
||||||
|
{
|
||||||
|
RuleID: "generic-critical-rule",
|
||||||
|
Severity: dbTypes.SeverityCritical.String(),
|
||||||
|
Title: "Critical Secret should pass filter",
|
||||||
|
StartLine: 1,
|
||||||
|
EndLine: 2,
|
||||||
|
Match: "*****",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
RuleID: "generic-low-rule",
|
||||||
|
Severity: dbTypes.SeverityLow.String(),
|
||||||
|
Title: "Low Secret should be ignored",
|
||||||
|
StartLine: 3,
|
||||||
|
EndLine: 4,
|
||||||
|
Match: "*****",
|
||||||
|
},
|
||||||
|
},
|
||||||
severities: []dbTypes.Severity{dbTypes.SeverityCritical, dbTypes.SeverityHigh, dbTypes.SeverityUnknown},
|
severities: []dbTypes.Severity{dbTypes.SeverityCritical, dbTypes.SeverityHigh, dbTypes.SeverityUnknown},
|
||||||
ignoreUnfixed: false,
|
ignoreUnfixed: false,
|
||||||
},
|
},
|
||||||
@@ -499,6 +519,16 @@ func TestClient_Filter(t *testing.T) {
|
|||||||
Status: types.StatusFailure,
|
Status: types.StatusFailure,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
wantSecrets: []ftypes.SecretFinding{
|
||||||
|
{
|
||||||
|
RuleID: "generic-critical-rule",
|
||||||
|
Severity: dbTypes.SeverityCritical.String(),
|
||||||
|
Title: "Critical Secret should pass filter",
|
||||||
|
StartLine: 1,
|
||||||
|
EndLine: 2,
|
||||||
|
Match: "*****",
|
||||||
|
},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "happy path with ignore-unfixed",
|
name: "happy path with ignore-unfixed",
|
||||||
@@ -770,12 +800,13 @@ func TestClient_Filter(t *testing.T) {
|
|||||||
for _, tt := range tests {
|
for _, tt := range tests {
|
||||||
t.Run(tt.name, func(t *testing.T) {
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
c := Client{}
|
c := Client{}
|
||||||
gotVulns, gotMisconfSummary, gotMisconfs, err := c.Filter(context.Background(), tt.args.vulns, tt.args.misconfs,
|
gotVulns, gotMisconfSummary, gotMisconfs, gotSecrets, err := c.Filter(context.Background(), tt.args.vulns, tt.args.misconfs, tt.args.secrets,
|
||||||
tt.args.severities, tt.args.ignoreUnfixed, false, tt.args.ignoreFile, tt.args.policyFile)
|
tt.args.severities, tt.args.ignoreUnfixed, false, tt.args.ignoreFile, tt.args.policyFile)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
assert.Equal(t, tt.wantVulns, gotVulns)
|
assert.Equal(t, tt.wantVulns, gotVulns)
|
||||||
assert.Equal(t, tt.wantMisconfSummary, gotMisconfSummary)
|
assert.Equal(t, tt.wantMisconfSummary, gotMisconfSummary)
|
||||||
assert.Equal(t, tt.wantMisconfs, gotMisconfs)
|
assert.Equal(t, tt.wantMisconfs, gotMisconfs)
|
||||||
|
assert.Equal(t, tt.wantSecrets, gotSecrets)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,10 +17,10 @@ type options struct {
|
|||||||
rpcClient rpc.Scanner
|
rpcClient rpc.Scanner
|
||||||
}
|
}
|
||||||
|
|
||||||
type option func(*options)
|
type Option func(*options)
|
||||||
|
|
||||||
// WithRPCClient takes rpc client for testability
|
// WithRPCClient takes rpc client for testability
|
||||||
func WithRPCClient(c rpc.Scanner) option {
|
func WithRPCClient(c rpc.Scanner) Option {
|
||||||
return func(opts *options) {
|
return func(opts *options) {
|
||||||
opts.rpcClient = c
|
opts.rpcClient = c
|
||||||
}
|
}
|
||||||
@@ -40,7 +40,7 @@ type Scanner struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// NewScanner is the factory method to return RPC Scanner
|
// NewScanner is the factory method to return RPC Scanner
|
||||||
func NewScanner(scannerOptions ScannerOption, opts ...option) Scanner {
|
func NewScanner(scannerOptions ScannerOption, opts ...Option) Scanner {
|
||||||
httpClient := &http.Client{
|
httpClient := &http.Client{
|
||||||
Transport: &http.Transport{
|
Transport: &http.Transport{
|
||||||
Proxy: http.ProxyFromEnvironment,
|
Proxy: http.ProxyFromEnvironment,
|
||||||
|
|||||||
@@ -104,10 +104,16 @@ func (s Scanner) Scan(target string, artifactKey string, blobKeys []string, opti
|
|||||||
|
|
||||||
// Scan IaC config files
|
// Scan IaC config files
|
||||||
if slices.Contains(options.SecurityChecks, types.SecurityCheckConfig) {
|
if slices.Contains(options.SecurityChecks, types.SecurityCheckConfig) {
|
||||||
configResults := s.misconfsToResults(artifactDetail.Misconfigurations, options)
|
configResults := s.misconfsToResults(artifactDetail.Misconfigurations)
|
||||||
results = append(results, configResults...)
|
results = append(results, configResults...)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Scan secrets
|
||||||
|
if slices.Contains(options.SecurityChecks, types.SecurityCheckSecret) {
|
||||||
|
secretResults := s.secretsToResults(artifactDetail.Secrets)
|
||||||
|
results = append(results, secretResults...)
|
||||||
|
}
|
||||||
|
|
||||||
return results, artifactDetail.OS, nil
|
return results, artifactDetail.OS, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -236,7 +242,7 @@ func (s Scanner) scanLibrary(apps []ftypes.Application, options types.ScanOption
|
|||||||
return results, nil
|
return results, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s Scanner) misconfsToResults(misconfs []ftypes.Misconfiguration, options types.ScanOptions) types.Results {
|
func (s Scanner) misconfsToResults(misconfs []ftypes.Misconfiguration) types.Results {
|
||||||
log.Logger.Infof("Detected config files: %d", len(misconfs))
|
log.Logger.Infof("Detected config files: %d", len(misconfs))
|
||||||
var results types.Results
|
var results types.Results
|
||||||
for _, misconf := range misconfs {
|
for _, misconf := range misconfs {
|
||||||
@@ -272,6 +278,20 @@ func (s Scanner) misconfsToResults(misconfs []ftypes.Misconfiguration, options t
|
|||||||
return results
|
return results
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s Scanner) secretsToResults(secrets []ftypes.Secret) types.Results {
|
||||||
|
var results types.Results
|
||||||
|
for _, secret := range secrets {
|
||||||
|
log.Logger.Debugf("Secret file: %s", secret.FilePath)
|
||||||
|
|
||||||
|
results = append(results, types.Result{
|
||||||
|
Target: secret.FilePath,
|
||||||
|
Class: types.ClassSecret,
|
||||||
|
Secrets: secret.Findings,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
return results
|
||||||
|
}
|
||||||
|
|
||||||
func toDetectedMisconfiguration(res ftypes.MisconfResult, defaultSeverity dbTypes.Severity,
|
func toDetectedMisconfiguration(res ftypes.MisconfResult, defaultSeverity dbTypes.Severity,
|
||||||
status types.MisconfStatus, layer ftypes.Layer) types.DetectedMisconfiguration {
|
status types.MisconfStatus, layer ftypes.Layer) types.DetectedMisconfiguration {
|
||||||
|
|
||||||
|
|||||||
@@ -63,6 +63,7 @@ var StandaloneRepositorySet = wire.NewSet(
|
|||||||
// RemoteSuperSet is used in the client mode
|
// RemoteSuperSet is used in the client mode
|
||||||
var RemoteSuperSet = wire.NewSet(
|
var RemoteSuperSet = wire.NewSet(
|
||||||
client.NewScanner,
|
client.NewScanner,
|
||||||
|
wire.Value([]client.Option(nil)),
|
||||||
wire.Bind(new(Driver), new(client.Scanner)),
|
wire.Bind(new(Driver), new(client.Scanner)),
|
||||||
NewScanner,
|
NewScanner,
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -37,6 +37,7 @@ const (
|
|||||||
ClassOSPkg = "os-pkgs"
|
ClassOSPkg = "os-pkgs"
|
||||||
ClassLangPkg = "lang-pkgs"
|
ClassLangPkg = "lang-pkgs"
|
||||||
ClassConfig = "config"
|
ClassConfig = "config"
|
||||||
|
ClassSecret = "secret"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Result holds a target and detected vulnerabilities
|
// Result holds a target and detected vulnerabilities
|
||||||
@@ -48,6 +49,7 @@ type Result struct {
|
|||||||
Vulnerabilities []DetectedVulnerability `json:"Vulnerabilities,omitempty"`
|
Vulnerabilities []DetectedVulnerability `json:"Vulnerabilities,omitempty"`
|
||||||
MisconfSummary *MisconfSummary `json:"MisconfSummary,omitempty"`
|
MisconfSummary *MisconfSummary `json:"MisconfSummary,omitempty"`
|
||||||
Misconfigurations []DetectedMisconfiguration `json:"Misconfigurations,omitempty"`
|
Misconfigurations []DetectedMisconfiguration `json:"Misconfigurations,omitempty"`
|
||||||
|
Secrets []ftypes.SecretFinding `json:"Secrets,omitempty"`
|
||||||
CustomResources []ftypes.CustomResource `json:"CustomResources,omitempty"`
|
CustomResources []ftypes.CustomResource `json:"CustomResources,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -28,11 +28,14 @@ const (
|
|||||||
|
|
||||||
// SecurityCheckConfig is a security check of misconfigurations
|
// SecurityCheckConfig is a security check of misconfigurations
|
||||||
SecurityCheckConfig = SecurityCheck("config")
|
SecurityCheckConfig = SecurityCheck("config")
|
||||||
|
|
||||||
|
// SecurityCheckSecret is a security check of secrets
|
||||||
|
SecurityCheckSecret = SecurityCheck("secret")
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
vulnTypes = []string{VulnTypeOS, VulnTypeLibrary}
|
vulnTypes = []string{VulnTypeOS, VulnTypeLibrary}
|
||||||
securityChecks = []string{SecurityCheckVulnerability, SecurityCheckConfig}
|
securityChecks = []string{SecurityCheckVulnerability, SecurityCheckConfig, SecurityCheckSecret}
|
||||||
)
|
)
|
||||||
|
|
||||||
// NewVulnType returns an instance of VulnType
|
// NewVulnType returns an instance of VulnType
|
||||||
|
|||||||
Reference in New Issue
Block a user