Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(misconf): add function of using --file-patterns for terraform misconfiguration #2626

Closed
wants to merge 3 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion docs/docs/references/cli/client.md
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ Vulnerability Flags
Misconfiguration Flags
--config-data strings specify paths from which data for the Rego policies will be recursively loaded
--config-policy strings specify paths to the Rego policy files directory, applying config files
--file-patterns strings specify config file patterns, available with '--security-checks config'
--file-patterns strings specify additional config file mathcing in regex format, available with '--security-checks config'
--include-non-failures include successes and exceptions, available with '--security-checks config'
--policy-namespaces strings Rego namespaces
--trace enable more verbose trace output for custom queries
Expand Down
3 changes: 2 additions & 1 deletion docs/docs/references/cli/config.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

``` bash
Scan config files for misconfigurations
Support: Dockerfile/Containerfile, Yaml, JSON, Helm, Terraform, CloudFormation

Usage:
trivy config [flags] DIR
Expand Down Expand Up @@ -32,7 +33,7 @@ Cache Flags
Misconfiguration Flags
--config-data strings specify paths from which data for the Rego policies will be recursively loaded
--config-policy strings specify paths to the Rego policy files directory, applying config files
--file-patterns strings specify config file patterns, available with '--security-checks config'
--file-patterns strings specify additional config file mathcing in regex format, available with '--security-checks config'
--include-non-failures include successes and exceptions, available with '--security-checks config'
--policy-namespaces strings Rego namespaces
--trace enable more verbose trace output for custom queries
Expand Down
4 changes: 2 additions & 2 deletions docs/docs/references/cli/fs.md
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ Vulnerability Flags
Misconfiguration Flags
--config-data strings specify paths from which data for the Rego policies will be recursively loaded
--config-policy strings specify paths to the Rego policy files directory, applying config files
--file-patterns strings specify config file patterns, available with '--security-checks config'
--file-patterns strings specify additional config file mathcing in regex format, available with '--security-checks config'
--include-non-failures include successes and exceptions, available with '--security-checks config'
--policy-namespaces strings Rego namespaces
--trace enable more verbose trace output for custom queries
Expand All @@ -82,4 +82,4 @@ Global Flags:
-q, --quiet suppress progress bar and log output
--timeout duration timeout (default 5m0s)
-v, --version show version
```
```
2 changes: 1 addition & 1 deletion docs/docs/references/cli/image.md
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ Vulnerability Flags
Misconfiguration Flags
--config-data strings specify paths from which data for the Rego policies will be recursively loaded
--config-policy strings specify paths to the Rego policy files directory, applying config files
--file-patterns strings specify config file patterns, available with '--security-checks config'
--file-patterns strings specify additional config file mathcing in regex format, available with '--security-checks config'
--include-non-failures include successes and exceptions, available with '--security-checks config'
--policy-namespaces strings Rego namespaces
--trace enable more verbose trace output for custom queries
Expand Down
4 changes: 2 additions & 2 deletions docs/docs/references/cli/repo.md
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ Vulnerability Flags
Misconfiguration Flags
--config-data strings specify paths from which data for the Rego policies will be recursively loaded
--config-policy strings specify paths to the Rego policy files directory, applying config files
--file-patterns strings specify config file patterns, available with '--security-checks config'
--file-patterns strings specify additional config file mathcing in regex format, available with '--security-checks config'
--include-non-failures include successes and exceptions, available with '--security-checks config'
--policy-namespaces strings Rego namespaces
--trace enable more verbose trace output for custom queries
Expand Down Expand Up @@ -84,4 +84,4 @@ Global Flags:
-q, --quiet suppress progress bar and log output
--timeout duration timeout (default 5m0s)
-v, --version show version
```
```
4 changes: 2 additions & 2 deletions docs/docs/references/cli/rootfs.md
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ Vulnerability Flags
Misconfiguration Flags
--config-data strings specify paths from which data for the Rego policies will be recursively loaded
--config-policy strings specify paths to the Rego policy files directory, applying config files
--file-patterns strings specify config file patterns, available with '--security-checks config'
--file-patterns strings specify additional config file mathcing in regex format, available with '--security-checks config'
--include-non-failures include successes and exceptions, available with '--security-checks config'
--policy-namespaces strings Rego namespaces
--trace enable more verbose trace output for custom queries
Expand All @@ -76,4 +76,4 @@ Global Flags:
-q, --quiet suppress progress bar and log output
--timeout duration timeout (default 5m0s)
-v, --version show version
```
```
1 change: 1 addition & 0 deletions pkg/commands/app.go
Original file line number Diff line number Diff line change
Expand Up @@ -548,6 +548,7 @@ func NewConfigCommand(globalFlags *flag.GlobalFlagGroup) *cobra.Command {
Use: "config [flags] DIR",
Aliases: []string{"conf"},
Short: "Scan config files for misconfigurations",
Long: "Support: Dockerfile/Containerfile, Yaml, JSON, Helm, Terraform, CloudFormation",
PreRunE: func(cmd *cobra.Command, args []string) error {
if err := configFlags.Bind(cmd); err != nil {
return xerrors.Errorf("flag bind error: %w", err)
Expand Down
6 changes: 4 additions & 2 deletions pkg/fanal/analyzer/config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ func (o *ScannerOption) Sort() {
}

func RegisterConfigAnalyzers(filePatterns []string) error {
var dockerRegexp, jsonRegexp, yamlRegexp, helmRegexp *regexp.Regexp
var dockerRegexp, jsonRegexp, yamlRegexp, helmRegexp, terraformRegexp *regexp.Regexp
for _, p := range filePatterns {
// e.g. "dockerfile:my_dockerfile_*"
s := strings.SplitN(p, separator, 2)
Expand All @@ -65,13 +65,15 @@ func RegisterConfigAnalyzers(filePatterns []string) error {
yamlRegexp = r
case types.Helm:
helmRegexp = r
case types.Terraform:
terraformRegexp = r
default:
return xerrors.Errorf("unknown file type: %s, pattern: %s", fileType, pattern)
}
}

analyzer.RegisterAnalyzer(dockerfile.NewConfigAnalyzer(dockerRegexp))
analyzer.RegisterAnalyzer(terraform.NewConfigAnalyzer())
analyzer.RegisterAnalyzer(terraform.NewConfigAnalyzer(terraformRegexp))
analyzer.RegisterAnalyzer(json.NewConfigAnalyzer(jsonRegexp))
analyzer.RegisterAnalyzer(yaml.NewConfigAnalyzer(yamlRegexp))
analyzer.RegisterAnalyzer(helm.NewConfigAnalyzer(helmRegexp))
Expand Down
5 changes: 5 additions & 0 deletions pkg/fanal/analyzer/config/dockerfile/docker_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,11 @@ func Test_dockerConfigAnalyzer_Required(t *testing.T) {
filePath: "docker/Dockerfile",
want: true,
},
{
name: "Containerfile in dir",
filePath: "docker/Containerfile",
want: true,
},
{
name: "Dockerfile as prefix",
filePath: "Dockerfilebuild",
Expand Down
2 changes: 1 addition & 1 deletion pkg/fanal/analyzer/config/helm/helm.go
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ func (a ConfigAnalyzer) Required(filePath string, info os.FileInfo) bool {
}

name := filepath.Base(filePath)
for _, acceptable := range []string{"Chart.yaml", ".helmignore"} {
for _, acceptable := range []string{".helmignore"} {
if strings.EqualFold(name, acceptable) {
return true
}
Expand Down
21 changes: 18 additions & 3 deletions pkg/fanal/analyzer/config/terraform/terraform.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ import (
"io"
"os"
"path/filepath"
"regexp"
"strings"

"golang.org/x/exp/slices"
"golang.org/x/xerrors"
Expand All @@ -18,10 +20,13 @@ const version = 1
var requiredExts = []string{".tf", ".tf.json"}

type ConfigAnalyzer struct {
filePattern *regexp.Regexp
}

func NewConfigAnalyzer() ConfigAnalyzer {
return ConfigAnalyzer{}
func NewConfigAnalyzer(filePattern *regexp.Regexp) ConfigAnalyzer {
return ConfigAnalyzer{
filePattern: filePattern,
}
}

// Analyze returns a name of Terraform file
Expand All @@ -45,7 +50,17 @@ func (a ConfigAnalyzer) Analyze(_ context.Context, input analyzer.AnalysisInput)
}

func (a ConfigAnalyzer) Required(filePath string, _ os.FileInfo) bool {
return slices.Contains(requiredExts, filepath.Ext(filePath))
// with --file-patterns
if a.filePattern != nil && a.filePattern.MatchString(filePath) {
return true
}

for _, acceptable := range requiredExts {
if strings.HasSuffix(strings.ToLower(filePath), acceptable) {
return true
}
}
return false
}

func (ConfigAnalyzer) Type() analyzer.Type {
Expand Down
57 changes: 48 additions & 9 deletions pkg/fanal/analyzer/config/terraform/terraform_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package terraform_test
import (
"bytes"
"context"
"regexp"
"testing"

"github.com/stretchr/testify/assert"
Expand All @@ -13,14 +14,14 @@ import (
"github.com/aquasecurity/trivy/pkg/fanal/types"
)

func TestConfigAnalyzer_Analyze(t *testing.T) {
func Test_TerraformConfigAnalyzer_Analyze(t *testing.T) {
tests := []struct {
name string
input analyzer.AnalysisInput
want *analyzer.AnalysisResult
}{
{
name: "happy path",
name: "happy path1",
input: analyzer.AnalysisInput{
Dir: "path/to/",
FilePath: "main.tf",
Expand All @@ -38,10 +39,29 @@ func TestConfigAnalyzer_Analyze(t *testing.T) {
},
},
},
{
name: "happy path2",
input: analyzer.AnalysisInput{
Dir: "path/to/",
FilePath: "main.tf.json",
Content: bytes.NewReader(nil),
},
want: &analyzer.AnalysisResult{
Files: map[types.HandlerType][]types.File{
types.MisconfPostHandler: {
{
Type: types.Terraform,
Path: "main.tf.json",
Content: []byte{},
},
},
},
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
a := terraform.ConfigAnalyzer{}
a := terraform.NewConfigAnalyzer(nil)
ctx := context.Background()
got, err := a.Analyze(ctx, tt.input)

Expand All @@ -51,17 +71,23 @@ func TestConfigAnalyzer_Analyze(t *testing.T) {
}
}

func TestConfigAnalyzer_Required(t *testing.T) {
func Test_TerraformConfigAnalyzer_Required(t *testing.T) {
tests := []struct {
name string
filePath string
want bool
name string
filePattern *regexp.Regexp
filePath string
want bool
}{
{
name: "happy path",
name: "happy path1",
filePath: "/path/to/main.tf",
want: true,
},
{
name: "happy path2",
filePath: "/path/to/main.tf.json",
want: true,
},
{
name: "hcl",
filePath: "/path/to/main.hcl",
Expand All @@ -72,12 +98,25 @@ func TestConfigAnalyzer_Required(t *testing.T) {
filePath: "deployment.yaml",
want: false,
},
{
name: "file pattern",
filePattern: regexp.MustCompile(`foo*`),
filePath: "foo_file",
want: true,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
a := terraform.ConfigAnalyzer{}
a := terraform.NewConfigAnalyzer(tt.filePattern)
got := a.Required(tt.filePath, nil)
assert.Equal(t, tt.want, got)
})
}
}

func Test_TerraformConfigAnalyzer_Type(t *testing.T) {
a := terraform.NewConfigAnalyzer(nil)
want := analyzer.TypeTerraform
got := a.Type()
assert.Equal(t, want, got)
}
2 changes: 1 addition & 1 deletion pkg/flag/misconf_flags.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ var (
Name: "file-patterns",
ConfigName: "misconfiguration.file-patterns",
Value: []string{},
Usage: "specify config file patterns, available with '--security-checks config'",
Usage: "specify additional config file mathcing in regex format, available with '--security-checks config'",
}
IncludeNonFailuresFlag = Flag{
Name: "include-non-failures",
Expand Down