Skip to content

Commit efdbd8f

Browse files
authored
feat(misconf): scanning support for YAML and JSON (#7311)
Signed-off-by: nikpivkin <[email protected]>
1 parent c5c62d5 commit efdbd8f

File tree

86 files changed

+1516
-443
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

86 files changed

+1516
-443
lines changed

docs/docs/coverage/iac/index.md

+3
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,9 @@ Trivy scans Infrastructure as Code (IaC) files for
1717
| [CloudFormation](cloudformation.md) | \*.yml, \*.yaml, \*.json |
1818
| [Azure ARM Template](azure-arm.md) | \*.json |
1919
| [Helm](helm.md) | \*.yaml, \*.tpl, \*.tar.gz, etc. |
20+
| [YAML][json-and-yaml] | \*.yaml, \*.yml |
21+
| [JSON][json-and-yaml] | \*.json |
2022

2123
[misconf]: ../../scanner/misconfiguration/index.md
2224
[secret]: ../../scanner/secret.md
25+
[json-and-yaml]: ../../scanner/misconfiguration/index.md#scan-arbitrary-json-and-yaml-configurations

docs/docs/references/configuration/cli/trivy_config.md

+1
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ trivy config [flags] DIR
1717
--compliance string compliance report to generate
1818
--config-check strings specify the paths to the Rego check files or to the directories containing them, applying config files
1919
--config-data strings specify paths from which data for the Rego checks will be recursively loaded
20+
--config-file-schemas strings specify paths to JSON configuration file schemas to determine that a file matches some configuration and pass the schema to Rego checks for type checking
2021
--enable-modules strings [EXPERIMENTAL] module names to enable
2122
--exit-code int specify exit code when any security issues are found
2223
--file-patterns strings specify config file patterns

docs/docs/references/configuration/cli/trivy_filesystem.md

+1
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ trivy filesystem [flags] PATH
2727
--compliance string compliance report to generate
2828
--config-check strings specify the paths to the Rego check files or to the directories containing them, applying config files
2929
--config-data strings specify paths from which data for the Rego checks will be recursively loaded
30+
--config-file-schemas strings specify paths to JSON configuration file schemas to determine that a file matches some configuration and pass the schema to Rego checks for type checking
3031
--custom-headers strings custom headers in client mode
3132
--db-repository string OCI repository to retrieve trivy-db from (default "ghcr.io/aquasecurity/trivy-db:2")
3233
--dependency-tree [EXPERIMENTAL] show dependency origin tree of vulnerable packages

docs/docs/references/configuration/cli/trivy_image.md

+1
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ trivy image [flags] IMAGE_NAME
4141
--compliance string compliance report to generate (docker-cis-1.6.0)
4242
--config-check strings specify the paths to the Rego check files or to the directories containing them, applying config files
4343
--config-data strings specify paths from which data for the Rego checks will be recursively loaded
44+
--config-file-schemas strings specify paths to JSON configuration file schemas to determine that a file matches some configuration and pass the schema to Rego checks for type checking
4445
--custom-headers strings custom headers in client mode
4546
--db-repository string OCI repository to retrieve trivy-db from (default "ghcr.io/aquasecurity/trivy-db:2")
4647
--dependency-tree [EXPERIMENTAL] show dependency origin tree of vulnerable packages

docs/docs/references/configuration/cli/trivy_kubernetes.md

+1
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ trivy kubernetes [flags] [CONTEXT]
3737
--compliance string compliance report to generate (k8s-nsa-1.0,k8s-cis-1.23,eks-cis-1.4,rke2-cis-1.24,k8s-pss-baseline-0.1,k8s-pss-restricted-0.1)
3838
--config-check strings specify the paths to the Rego check files or to the directories containing them, applying config files
3939
--config-data strings specify paths from which data for the Rego checks will be recursively loaded
40+
--config-file-schemas strings specify paths to JSON configuration file schemas to determine that a file matches some configuration and pass the schema to Rego checks for type checking
4041
--db-repository string OCI repository to retrieve trivy-db from (default "ghcr.io/aquasecurity/trivy-db:2")
4142
--dependency-tree [EXPERIMENTAL] show dependency origin tree of vulnerable packages
4243
--detection-priority string specify the detection priority:

docs/docs/references/configuration/cli/trivy_repository.md

+1
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ trivy repository [flags] (REPO_PATH | REPO_URL)
2727
--commit string pass the commit hash to be scanned
2828
--config-check strings specify the paths to the Rego check files or to the directories containing them, applying config files
2929
--config-data strings specify paths from which data for the Rego checks will be recursively loaded
30+
--config-file-schemas strings specify paths to JSON configuration file schemas to determine that a file matches some configuration and pass the schema to Rego checks for type checking
3031
--custom-headers strings custom headers in client mode
3132
--db-repository string OCI repository to retrieve trivy-db from (default "ghcr.io/aquasecurity/trivy-db:2")
3233
--dependency-tree [EXPERIMENTAL] show dependency origin tree of vulnerable packages

docs/docs/references/configuration/cli/trivy_rootfs.md

+1
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ trivy rootfs [flags] ROOTDIR
2929
--checks-bundle-repository string OCI registry URL to retrieve checks bundle from (default "ghcr.io/aquasecurity/trivy-checks:0")
3030
--config-check strings specify the paths to the Rego check files or to the directories containing them, applying config files
3131
--config-data strings specify paths from which data for the Rego checks will be recursively loaded
32+
--config-file-schemas strings specify paths to JSON configuration file schemas to determine that a file matches some configuration and pass the schema to Rego checks for type checking
3233
--custom-headers strings custom headers in client mode
3334
--db-repository string OCI repository to retrieve trivy-db from (default "ghcr.io/aquasecurity/trivy-db:2")
3435
--dependency-tree [EXPERIMENTAL] show dependency origin tree of vulnerable packages

docs/docs/references/configuration/cli/trivy_vm.md

+1
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ trivy vm [flags] VM_IMAGE
2525
--cache-ttl duration cache TTL when using redis as cache backend
2626
--checks-bundle-repository string OCI registry URL to retrieve checks bundle from (default "ghcr.io/aquasecurity/trivy-checks:0")
2727
--compliance string compliance report to generate
28+
--config-file-schemas strings specify paths to JSON configuration file schemas to determine that a file matches some configuration and pass the schema to Rego checks for type checking
2829
--custom-headers strings custom headers in client mode
2930
--db-repository string OCI repository to retrieve trivy-db from (default "ghcr.io/aquasecurity/trivy-db:2")
3031
--dependency-tree [EXPERIMENTAL] show dependency origin tree of vulnerable packages

docs/docs/references/configuration/config-file.md

+3
Original file line numberDiff line numberDiff line change
@@ -386,6 +386,9 @@ misconfiguration:
386386
# Same as '--cf-params'
387387
params: []
388388

389+
# Same as '--config-file-schemas'
390+
config-file-schemas: []
391+
389392
helm:
390393
# Same as '--helm-api-versions'
391394
api-versions: []

docs/docs/scanner/misconfiguration/index.md

+59-4
Original file line numberDiff line numberDiff line change
@@ -107,7 +107,7 @@ $ trivy config --severity HIGH,CRITICAL ./iac
107107
<details>
108108
<summary>Result</summary>
109109

110-
```
110+
```bash
111111
2022-06-06T11:01:21.142+0100 INFO Detected config files: 8
112112

113113
Dockerfile (dockerfile)
@@ -343,6 +343,61 @@ You can load checks bundle as OCI Image from a Container Registry using the `--c
343343
trivy config --checks-bundle-repository myregistry.local/mychecks --namespaces user myapp
344344
```
345345
346+
347+
### Scan arbitrary JSON and YAML configurations
348+
By default, scanning JSON and YAML configurations is disabled, since Trivy does not contain built-in checks for these configurations. To enable it, pass the `json` or `yaml` to `--misconfig-scanners`. See [Enabling a subset of misconfiguration scanners](#enabling-a-subset-of-misconfiguration-scanners) for more information. Trivy will pass each file as is to the checks input.
349+
350+
351+
!!! example
352+
```bash
353+
$ cat iac/serverless.yaml
354+
service: serverless-rest-api-with-pynamodb
355+
356+
frameworkVersion: ">=2.24.0"
357+
358+
plugins:
359+
- serverless-python-requirements
360+
...
361+
362+
$ cat serverless.rego
363+
# METADATA
364+
# title: Serverless Framework service name not starting with "aws-"
365+
# description: Ensure that Serverless Framework service names start with "aws-"
366+
# schemas:
367+
# - input: schema["serverless-schema"]
368+
# custom:
369+
# id: SF001
370+
# severity: LOW
371+
package user.serverless001
372+
373+
deny[res] {
374+
not startswith(input.service, "aws-")
375+
res := result.new(
376+
sprintf("Service name %q is not allowed", [input.service]),
377+
input.service
378+
)
379+
}
380+
381+
$ trivy config --misconfig-scanners=json,yaml --config-check ./serverless.rego --check-namespaces user ./iac
382+
serverless.yaml (yaml)
383+
384+
Tests: 4 (SUCCESSES: 3, FAILURES: 1, EXCEPTIONS: 0)
385+
Failures: 1 (UNKNOWN: 0, LOW: 1, MEDIUM: 0, HIGH: 0, CRITICAL: 0)
386+
387+
LOW: Service name "serverless-rest-api-with-pynamodb" is not allowed
388+
═════════════════════════════════════════════════════════════════════════════════════════════════════════
389+
Ensure that Serverless Framework service names start with "aws-"
390+
```
391+
392+
You can also pass schemas using the `config-file-schemas` flag. Trivy will use these schemas for file filtering and type checking in Rego checks. If the file does not match any of the passed schemas, it will be ignored.
393+
394+
!!! example
395+
```bash
396+
$ trivy config --misconfig-scanners=json,yaml --config-check ./serverless.rego --check-namespaces user --config-file-schemas ./serverless-schema.json ./iac
397+
```
398+
399+
If the schema is specified in the check metadata and is in the directory specified in the `--config-check` argument, it will be automatically loaded as specified [here](./custom/schema.md#custom-checks-with-custom-schemas), and will only be used for type checking in Rego.
400+
346401
### Passing custom data
347402
You can pass directories including your custom data through `--data` option.
348403
This can be repeated for specifying multiple directories.
@@ -363,12 +418,12 @@ This can be repeated for specifying multiple packages.
363418
trivy config --config-check ./my-check --namespaces main --namespaces user ./configs
364419
```
365420
366-
### Private terraform registries
367-
Trivy can download terraform code from private registries.
421+
### Private Terraform registries
422+
Trivy can download Terraform code from private registries.
368423
To pass credentials you must use the `TF_TOKEN_` environment variables.
369424
You cannot use a `.terraformrc` or `terraform.rc` file, these are not supported by trivy yet.
370425
371-
From the terraform [docs](https://developer.hashicorp.com/terraform/cli/config/config-file#environment-variable-credentials):
426+
From the Terraform [docs](https://developer.hashicorp.com/terraform/cli/config/config-file#environment-variable-credentials):
372427
373428
> Environment variable names should have the prefix TF_TOKEN_ added to the domain name, with periods encoded as underscores.
374429
> For example, the value of a variable named `TF_TOKEN_app_terraform_io` will be used as a bearer authorization token when the CLI makes service requests to the hostname `app.terraform.io`.

pkg/commands/artifact/run.go

+50-34
Original file line numberDiff line numberDiff line change
@@ -501,43 +501,13 @@ func (r *runner) initScannerConfig(opts flag.Options) (ScannerConfig, types.Scan
501501
log.WithPrefix(log.PrefixVulnerability).Info("Vulnerability scanning is enabled")
502502
}
503503

504-
// ScannerOption is filled only when config scanning is enabled.
504+
// Misconfig ScannerOption is filled only when config scanning is enabled.
505505
var configScannerOptions misconf.ScannerOption
506506
if opts.Scanners.Enabled(types.MisconfigScanner) || opts.ImageConfigScanners.Enabled(types.MisconfigScanner) {
507-
logger := log.WithPrefix(log.PrefixMisconfiguration)
508-
logger.Info("Misconfiguration scanning is enabled")
509-
510-
var downloadedPolicyPaths []string
511-
var disableEmbedded bool
512-
513-
downloadedPolicyPaths, err := operation.InitBuiltinPolicies(context.Background(), opts.CacheDir, opts.Quiet, opts.SkipCheckUpdate, opts.MisconfOptions.ChecksBundleRepository, opts.RegistryOpts())
507+
var err error
508+
configScannerOptions, err = initMisconfScannerOption(opts)
514509
if err != nil {
515-
if !opts.SkipCheckUpdate {
516-
logger.Error("Falling back to embedded checks", log.Err(err))
517-
}
518-
} else {
519-
logger.Debug("Policies successfully loaded from disk")
520-
disableEmbedded = true
521-
}
522-
configScannerOptions = misconf.ScannerOption{
523-
Debug: opts.Debug,
524-
Trace: opts.Trace,
525-
Namespaces: append(opts.CheckNamespaces, rego.BuiltinNamespaces()...),
526-
PolicyPaths: append(opts.CheckPaths, downloadedPolicyPaths...),
527-
DataPaths: opts.DataPaths,
528-
HelmValues: opts.HelmValues,
529-
HelmValueFiles: opts.HelmValueFiles,
530-
HelmFileValues: opts.HelmFileValues,
531-
HelmStringValues: opts.HelmStringValues,
532-
HelmAPIVersions: opts.HelmAPIVersions,
533-
HelmKubeVersion: opts.HelmKubeVersion,
534-
TerraformTFVars: opts.TerraformTFVars,
535-
CloudFormationParamVars: opts.CloudFormationParamVars,
536-
K8sVersion: opts.K8sVersion,
537-
DisableEmbeddedPolicies: disableEmbedded,
538-
DisableEmbeddedLibraries: disableEmbedded,
539-
IncludeDeprecatedChecks: opts.IncludeDeprecatedChecks,
540-
TfExcludeDownloaded: opts.TfExcludeDownloaded,
510+
return ScannerConfig{}, types.ScanOptions{}, err
541511
}
542512
}
543513

@@ -650,3 +620,49 @@ func (r *runner) scan(ctx context.Context, opts flag.Options, initializeScanner
650620
}
651621
return report, nil
652622
}
623+
624+
func initMisconfScannerOption(opts flag.Options) (misconf.ScannerOption, error) {
625+
logger := log.WithPrefix(log.PrefixMisconfiguration)
626+
logger.Info("Misconfiguration scanning is enabled")
627+
628+
var downloadedPolicyPaths []string
629+
var disableEmbedded bool
630+
631+
downloadedPolicyPaths, err := operation.InitBuiltinPolicies(context.Background(), opts.CacheDir, opts.Quiet, opts.SkipCheckUpdate, opts.MisconfOptions.ChecksBundleRepository, opts.RegistryOpts())
632+
if err != nil {
633+
if !opts.SkipCheckUpdate {
634+
logger.Error("Falling back to embedded checks", log.Err(err))
635+
}
636+
} else {
637+
logger.Debug("Checks successfully loaded from disk")
638+
disableEmbedded = true
639+
}
640+
641+
configSchemas, err := misconf.LoadConfigSchemas(opts.ConfigFileSchemas)
642+
if err != nil {
643+
return misconf.ScannerOption{}, xerrors.Errorf("load schemas error: %w", err)
644+
}
645+
646+
return misconf.ScannerOption{
647+
Debug: opts.Debug,
648+
Trace: opts.Trace,
649+
Namespaces: append(opts.CheckNamespaces, rego.BuiltinNamespaces()...),
650+
PolicyPaths: append(opts.CheckPaths, downloadedPolicyPaths...),
651+
DataPaths: opts.DataPaths,
652+
HelmValues: opts.HelmValues,
653+
HelmValueFiles: opts.HelmValueFiles,
654+
HelmFileValues: opts.HelmFileValues,
655+
HelmStringValues: opts.HelmStringValues,
656+
HelmAPIVersions: opts.HelmAPIVersions,
657+
HelmKubeVersion: opts.HelmKubeVersion,
658+
TerraformTFVars: opts.TerraformTFVars,
659+
CloudFormationParamVars: opts.CloudFormationParamVars,
660+
K8sVersion: opts.K8sVersion,
661+
DisableEmbeddedPolicies: disableEmbedded,
662+
DisableEmbeddedLibraries: disableEmbedded,
663+
IncludeDeprecatedChecks: opts.IncludeDeprecatedChecks,
664+
TfExcludeDownloaded: opts.TfExcludeDownloaded,
665+
FilePatterns: opts.FilePatterns,
666+
ConfigFileSchemas: configSchemas,
667+
}, nil
668+
}

pkg/fanal/analyzer/analyzer.go

+5-1
Original file line numberDiff line numberDiff line change
@@ -214,7 +214,11 @@ func (r *AnalysisResult) Sort() {
214214

215215
// Misconfigurations
216216
sort.Slice(r.Misconfigurations, func(i, j int) bool {
217-
return r.Misconfigurations[i].FilePath < r.Misconfigurations[j].FilePath
217+
if r.Misconfigurations[i].FileType != r.Misconfigurations[j].FileType {
218+
return r.Misconfigurations[i].FileType < r.Misconfigurations[j].FileType
219+
} else {
220+
return r.Misconfigurations[i].FilePath < r.Misconfigurations[j].FilePath
221+
}
218222
})
219223

220224
// Secrets

pkg/fanal/analyzer/config/all/import.go

+2
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,10 @@ import (
55
_ "github.com/aquasecurity/trivy/pkg/fanal/analyzer/config/cloudformation"
66
_ "github.com/aquasecurity/trivy/pkg/fanal/analyzer/config/dockerfile"
77
_ "github.com/aquasecurity/trivy/pkg/fanal/analyzer/config/helm"
8+
_ "github.com/aquasecurity/trivy/pkg/fanal/analyzer/config/json"
89
_ "github.com/aquasecurity/trivy/pkg/fanal/analyzer/config/k8s"
910
_ "github.com/aquasecurity/trivy/pkg/fanal/analyzer/config/terraform"
1011
_ "github.com/aquasecurity/trivy/pkg/fanal/analyzer/config/terraformplan/json"
1112
_ "github.com/aquasecurity/trivy/pkg/fanal/analyzer/config/terraformplan/snapshot"
13+
_ "github.com/aquasecurity/trivy/pkg/fanal/analyzer/config/yaml"
1214
)

pkg/fanal/analyzer/config/azurearm/azurearm.go

+2-2
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import (
66

77
"github.com/aquasecurity/trivy/pkg/fanal/analyzer"
88
"github.com/aquasecurity/trivy/pkg/fanal/analyzer/config"
9-
"github.com/aquasecurity/trivy/pkg/misconf"
9+
"github.com/aquasecurity/trivy/pkg/iac/detection"
1010
)
1111

1212
const (
@@ -25,7 +25,7 @@ type azureARMConfigAnalyzer struct {
2525
}
2626

2727
func newAzureARMConfigAnalyzer(opts analyzer.AnalyzerOptions) (analyzer.PostAnalyzer, error) {
28-
a, err := config.NewAnalyzer(analyzerType, version, misconf.NewAzureARMScanner, opts)
28+
a, err := config.NewAnalyzer(analyzerType, version, detection.FileTypeAzureARM, opts)
2929
if err != nil {
3030
return nil, err
3131
}

pkg/fanal/analyzer/config/cloudformation/cloudformation.go

+2-2
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ package cloudformation
33
import (
44
"github.com/aquasecurity/trivy/pkg/fanal/analyzer"
55
"github.com/aquasecurity/trivy/pkg/fanal/analyzer/config"
6-
"github.com/aquasecurity/trivy/pkg/misconf"
6+
"github.com/aquasecurity/trivy/pkg/iac/detection"
77
)
88

99
const (
@@ -22,7 +22,7 @@ type cloudFormationConfigAnalyzer struct {
2222
}
2323

2424
func newCloudFormationConfigAnalyzer(opts analyzer.AnalyzerOptions) (analyzer.PostAnalyzer, error) {
25-
a, err := config.NewAnalyzer(analyzerType, version, misconf.NewCloudFormationScanner, opts)
25+
a, err := config.NewAnalyzer(analyzerType, version, detection.FileTypeCloudFormation, opts)
2626
if err != nil {
2727
return nil, err
2828
}

pkg/fanal/analyzer/config/config.go

+3-4
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import (
99
"k8s.io/utils/strings/slices"
1010

1111
"github.com/aquasecurity/trivy/pkg/fanal/analyzer"
12+
"github.com/aquasecurity/trivy/pkg/iac/detection"
1213
"github.com/aquasecurity/trivy/pkg/misconf"
1314
)
1415

@@ -26,10 +27,8 @@ type Analyzer struct {
2627
scanner *misconf.Scanner
2728
}
2829

29-
type NewScanner func([]string, misconf.ScannerOption) (*misconf.Scanner, error)
30-
31-
func NewAnalyzer(t analyzer.Type, version int, newScanner NewScanner, opts analyzer.AnalyzerOptions) (*Analyzer, error) {
32-
s, err := newScanner(opts.FilePatterns, opts.MisconfScannerOption)
30+
func NewAnalyzer(t analyzer.Type, version int, fileType detection.FileType, opts analyzer.AnalyzerOptions) (*Analyzer, error) {
31+
s, err := misconf.NewScanner(fileType, opts.MisconfScannerOption)
3332
if err != nil {
3433
return nil, xerrors.Errorf("%s scanner init error: %w", t, err)
3534
}

0 commit comments

Comments
 (0)