diff --git a/docs/docs/coverage/iac/cloudformation.md b/docs/docs/coverage/iac/cloudformation.md index f0ba21acdb2b..5665e1e77acd 100644 --- a/docs/docs/coverage/iac/cloudformation.md +++ b/docs/docs/coverage/iac/cloudformation.md @@ -2,14 +2,14 @@ Trivy supports the scanners listed in the table below. | Scanner | Supported | -| :----------------: | :-------: | +|:------------------:|:---------:| | [Misconfiguration] | ✓ | | [Secret] | ✓ | It supports the following formats. | Format | Supported | -| :----: | :-------: | +|:------:|:---------:| | JSON | ✓ | | YAML | ✓ | @@ -17,8 +17,19 @@ It supports the following formats. Trivy recursively searches directories and scans all found CloudFormation files. It evaluates properties, functions, and other elements within CloudFormation files to detect misconfigurations. +### Value Overrides +You can provide `cf-params` with path to [CloudFormation Parameters] file to Trivy to scan your CloudFormation code with parameters. + +```bash +trivy conf --cf-params params.json ./infrastructure/cf +``` + +You can check a [CloudFormation Parameters Example] + ## Secret The secret scan is performed on plain text files, with no special treatment for CloudFormation. [Misconfiguration]: ../../scanner/misconfiguration/index.md -[Secret]: ../../scanner/secret.md \ No newline at end of file +[Secret]: ../../scanner/secret.md +[CloudFormation Parameters]: https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/parameters-section-structure.html +[CloudFormation Parameters Example]: https://awscli.amazonaws.com/v2/documentation/api/latest/reference/cloudformation/deploy.html#supported-json-syntax \ No newline at end of file diff --git a/docs/docs/references/configuration/cli/trivy_aws.md b/docs/docs/references/configuration/cli/trivy_aws.md index bd00afbeadf5..590162972b39 100644 --- a/docs/docs/references/configuration/cli/trivy_aws.md +++ b/docs/docs/references/configuration/cli/trivy_aws.md @@ -68,6 +68,7 @@ trivy aws [flags] ``` --account string The AWS account to scan. It's useful to specify this when reviewing cached results for multiple accounts. --arn string The AWS ARN to show results for. Useful to filter results once a scan is cached. + --cf-params strings specify paths to override the CloudFormation parameters files --compliance string compliance report to generate (aws-cis-1.2,aws-cis-1.4) --config-data strings specify paths from which data for the Rego policies will be recursively loaded --config-policy strings specify the paths to the Rego policy files or to the directories containing them, applying config files diff --git a/docs/docs/references/configuration/cli/trivy_config.md b/docs/docs/references/configuration/cli/trivy_config.md index e2c6110b13fa..0d26452a10b1 100644 --- a/docs/docs/references/configuration/cli/trivy_config.md +++ b/docs/docs/references/configuration/cli/trivy_config.md @@ -11,6 +11,7 @@ trivy config [flags] DIR ``` --cache-backend string cache backend (e.g. redis://localhost:6379) (default "fs") --cache-ttl duration cache TTL when using redis as cache backend + --cf-params strings specify paths to override the CloudFormation parameters files --clear-cache clear image caches without scanning --compliance string compliance report to generate --config-data strings specify paths from which data for the Rego policies will be recursively loaded diff --git a/docs/docs/references/configuration/cli/trivy_filesystem.md b/docs/docs/references/configuration/cli/trivy_filesystem.md index 57d2414ddc23..89d034caaa4d 100644 --- a/docs/docs/references/configuration/cli/trivy_filesystem.md +++ b/docs/docs/references/configuration/cli/trivy_filesystem.md @@ -21,6 +21,7 @@ trivy filesystem [flags] PATH ``` --cache-backend string cache backend (e.g. redis://localhost:6379) (default "fs") --cache-ttl duration cache TTL when using redis as cache backend + --cf-params strings specify paths to override the CloudFormation parameters files --clear-cache clear image caches without scanning --compliance string compliance report to generate --config-data strings specify paths from which data for the Rego policies will be recursively loaded diff --git a/docs/docs/references/configuration/cli/trivy_image.md b/docs/docs/references/configuration/cli/trivy_image.md index 3105bdaa3025..10ac0518944b 100644 --- a/docs/docs/references/configuration/cli/trivy_image.md +++ b/docs/docs/references/configuration/cli/trivy_image.md @@ -100,7 +100,6 @@ trivy image [flags] IMAGE_NAME --skip-policy-update skip fetching rego policy updates -t, --template string output template --tf-exclude-downloaded-modules exclude misconfigurations for downloaded terraform modules - --tf-vars strings specify paths to override the Terraform tfvars files --token string for authentication in client/server mode --token-header string specify a header name for token in client/server mode (default "Trivy-Token") --trace enable more verbose trace output for custom queries diff --git a/docs/docs/references/configuration/cli/trivy_kubernetes.md b/docs/docs/references/configuration/cli/trivy_kubernetes.md index a460641d2f15..93d44ad04c3e 100644 --- a/docs/docs/references/configuration/cli/trivy_kubernetes.md +++ b/docs/docs/references/configuration/cli/trivy_kubernetes.md @@ -89,7 +89,6 @@ trivy kubernetes [flags] { cluster | all | specific resources like kubectl. eg: --skip-policy-update skip fetching rego policy updates -t, --template string output template --tf-exclude-downloaded-modules exclude misconfigurations for downloaded terraform modules - --tf-vars strings specify paths to override the Terraform tfvars files --tolerations strings specify node-collector job tolerations (example: key1=value1:NoExecute,key2=value2:NoSchedule) --trace enable more verbose trace output for custom queries --username strings username. Comma-separated usernames allowed. diff --git a/docs/docs/references/configuration/cli/trivy_repository.md b/docs/docs/references/configuration/cli/trivy_repository.md index 4cf4638e99ac..a88e9be5bf30 100644 --- a/docs/docs/references/configuration/cli/trivy_repository.md +++ b/docs/docs/references/configuration/cli/trivy_repository.md @@ -21,6 +21,7 @@ trivy repository [flags] (REPO_PATH | REPO_URL) --branch string pass the branch name to be scanned --cache-backend string cache backend (e.g. redis://localhost:6379) (default "fs") --cache-ttl duration cache TTL when using redis as cache backend + --cf-params strings specify paths to override the CloudFormation parameters files --clear-cache clear image caches without scanning --commit string pass the commit hash to be scanned --config-data strings specify paths from which data for the Rego policies will be recursively loaded diff --git a/docs/docs/references/configuration/cli/trivy_rootfs.md b/docs/docs/references/configuration/cli/trivy_rootfs.md index 31046603d594..d04ee44ba113 100644 --- a/docs/docs/references/configuration/cli/trivy_rootfs.md +++ b/docs/docs/references/configuration/cli/trivy_rootfs.md @@ -24,6 +24,7 @@ trivy rootfs [flags] ROOTDIR ``` --cache-backend string cache backend (e.g. redis://localhost:6379) (default "fs") --cache-ttl duration cache TTL when using redis as cache backend + --cf-params strings specify paths to override the CloudFormation parameters files --clear-cache clear image caches without scanning --config-data strings specify paths from which data for the Rego policies will be recursively loaded --config-policy strings specify the paths to the Rego policy files or to the directories containing them, applying config files diff --git a/docs/docs/references/configuration/cli/trivy_vm.md b/docs/docs/references/configuration/cli/trivy_vm.md index 2028e3ed188d..eb6506c7585d 100644 --- a/docs/docs/references/configuration/cli/trivy_vm.md +++ b/docs/docs/references/configuration/cli/trivy_vm.md @@ -71,7 +71,6 @@ trivy vm [flags] VM_IMAGE --skip-java-db-update skip updating Java index database -t, --template string output template --tf-exclude-downloaded-modules exclude misconfigurations for downloaded terraform modules - --tf-vars strings specify paths to override the Terraform tfvars files --token string for authentication in client/server mode --token-header string specify a header name for token in client/server mode (default "Trivy-Token") --vuln-type strings comma-separated list of vulnerability types (os,library) (default [os,library]) diff --git a/go.mod b/go.mod index 3432b55c25a5..a47cd5f944ca 100644 --- a/go.mod +++ b/go.mod @@ -28,7 +28,7 @@ require ( github.com/aquasecurity/trivy-iac v0.5.2 github.com/aquasecurity/trivy-java-db v0.0.0-20230209231723-7cddb1406728 github.com/aquasecurity/trivy-kubernetes v0.5.9-0.20231023143623-130fa1a0e44a - github.com/aquasecurity/trivy-policies v0.4.0 + github.com/aquasecurity/trivy-policies v0.5.0 github.com/aws/aws-sdk-go-v2 v1.22.1 github.com/aws/aws-sdk-go-v2/config v1.18.45 github.com/aws/aws-sdk-go-v2/credentials v1.13.43 diff --git a/go.sum b/go.sum index 0c784649cb61..603ccf233384 100644 --- a/go.sum +++ b/go.sum @@ -352,8 +352,8 @@ github.com/aquasecurity/trivy-java-db v0.0.0-20230209231723-7cddb1406728 h1:0eS+ github.com/aquasecurity/trivy-java-db v0.0.0-20230209231723-7cddb1406728/go.mod h1:Ldya37FLi0e/5Cjq2T5Bty7cFkzUDwTcPeQua+2M8i8= github.com/aquasecurity/trivy-kubernetes v0.5.9-0.20231023143623-130fa1a0e44a h1:x1Z+k7snLeDjTLnvTd4UPNo0HPMP6SNWxZTVU5smuA0= github.com/aquasecurity/trivy-kubernetes v0.5.9-0.20231023143623-130fa1a0e44a/go.mod h1:e3iMAeJ1V/iPsNcRBVd9aDqj1YAXeURzv3qLurbloUk= -github.com/aquasecurity/trivy-policies v0.4.0 h1:20dEiWkiTrFXAiPLVshfJ/x1i9LvDDsBJ/CAb4fNEBI= -github.com/aquasecurity/trivy-policies v0.4.0/go.mod h1:Wqj81EIp4lDQGVzbPalKLNucR7c96YLQbfdA60KpEkQ= +github.com/aquasecurity/trivy-policies v0.5.0 h1:7GukJhiEQpKg8VQH3PkwZOyFqO0J6hGmUbt7jne5mhU= +github.com/aquasecurity/trivy-policies v0.5.0/go.mod h1:YPefENNCAcbPxMDgKBWxjLmhyzYnlAY/HIH89VFaogY= github.com/arbovm/levenshtein v0.0.0-20160628152529-48b4e1c0c4d0 h1:jfIu9sQUG6Ig+0+Ap1h4unLjW6YQJpKZVmUzxsD4E/Q= github.com/arbovm/levenshtein v0.0.0-20160628152529-48b4e1c0c4d0/go.mod h1:t2tdKJDJF9BV14lnkjHmOQgcvEKgtqs5a1N3LNdJhGE= github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o= diff --git a/pkg/commands/app.go b/pkg/commands/app.go index c6ae0ed7a212..fe39fb57925c 100644 --- a/pkg/commands/app.go +++ b/pkg/commands/app.go @@ -232,12 +232,16 @@ func NewImageCommand(globalFlags *flag.GlobalFlagGroup) *cobra.Command { compliance.Values = []string{types.ComplianceDockerCIS} reportFlagGroup.Compliance = &compliance // override usage as the accepted values differ for each subcommand. + misconfFlagGroup := flag.NewMisconfFlagGroup() + misconfFlagGroup.CloudformationParamVars = nil // disable '--cf-params' + misconfFlagGroup.TerraformTFVars = nil // disable '--tf-vars' + imageFlags := &flag.Flags{ CacheFlagGroup: flag.NewCacheFlagGroup(), DBFlagGroup: flag.NewDBFlagGroup(), ImageFlagGroup: flag.NewImageFlagGroup(), // container image specific LicenseFlagGroup: flag.NewLicenseFlagGroup(), - MisconfFlagGroup: flag.NewMisconfFlagGroup(), + MisconfFlagGroup: misconfFlagGroup, ModuleFlagGroup: flag.NewModuleFlagGroup(), RemoteFlagGroup: flag.NewClientFlags(), // for client/server mode RegistryFlagGroup: flag.NewRegistryFlagGroup(), @@ -896,12 +900,16 @@ func NewKubernetesCommand(globalFlags *flag.GlobalFlagGroup) *cobra.Command { }) reportFlagGroup.Format = &formatFlag + misconfFlagGroup := flag.NewMisconfFlagGroup() + misconfFlagGroup.CloudformationParamVars = nil // disable '--cf-params' + misconfFlagGroup.TerraformTFVars = nil // disable '--tf-vars' + k8sFlags := &flag.Flags{ CacheFlagGroup: flag.NewCacheFlagGroup(), DBFlagGroup: flag.NewDBFlagGroup(), ImageFlagGroup: imageFlags, K8sFlagGroup: flag.NewK8sFlagGroup(), // kubernetes-specific flags - MisconfFlagGroup: flag.NewMisconfFlagGroup(), + MisconfFlagGroup: misconfFlagGroup, RegoFlagGroup: flag.NewRegoFlagGroup(), ReportFlagGroup: reportFlagGroup, ScanFlagGroup: scanFlags, @@ -1046,8 +1054,10 @@ func NewVMCommand(globalFlags *flag.GlobalFlagGroup) *cobra.Command { }, }, } - vmFlags.ReportFlagGroup.ReportFormat = nil // disable '--report' - vmFlags.ScanFlagGroup.IncludeDevDeps = nil // disable '--include-dev-deps' + vmFlags.ReportFlagGroup.ReportFormat = nil // disable '--report' + vmFlags.ScanFlagGroup.IncludeDevDeps = nil // disable '--include-dev-deps' + vmFlags.MisconfFlagGroup.CloudformationParamVars = nil // disable '--cf-params' + vmFlags.MisconfFlagGroup.TerraformTFVars = nil // disable '--tf-vars' cmd := &cobra.Command{ Use: "vm [flags] VM_IMAGE", diff --git a/pkg/commands/artifact/run.go b/pkg/commands/artifact/run.go index b36897ffc3bb..638677206243 100644 --- a/pkg/commands/artifact/run.go +++ b/pkg/commands/artifact/run.go @@ -583,6 +583,7 @@ func initScannerConfig(opts flag.Options, cacheClient cache.Cache) (ScannerConfi HelmFileValues: opts.HelmFileValues, HelmStringValues: opts.HelmStringValues, TerraformTFVars: opts.TerraformTFVars, + CloudFormationParamVars: opts.CloudFormationParamVars, K8sVersion: opts.K8sVersion, DisableEmbeddedPolicies: disableEmbedded, DisableEmbeddedLibraries: disableEmbedded, diff --git a/pkg/fanal/artifact/local/fs_test.go b/pkg/fanal/artifact/local/fs_test.go index e83bb0b8a7c0..21049d566f2a 100644 --- a/pkg/fanal/artifact/local/fs_test.go +++ b/pkg/fanal/artifact/local/fs_test.go @@ -854,7 +854,7 @@ func TestCloudFormationMisconfigurationScan(t *testing.T) { Args: cache.ArtifactCachePutBlobArgs{ BlobIDAnything: true, BlobInfo: types.BlobInfo{ - SchemaVersion: 2, + SchemaVersion: types.BlobJSONSchemaVersion, Misconfigurations: []types.Misconfiguration{ { FileType: "cloudformation", @@ -1014,6 +1014,64 @@ func TestCloudFormationMisconfigurationScan(t *testing.T) { }, }, }, + { + name: "CloudFormation parameters outside the scan directory", + fields: fields{ + dir: "./testdata/misconfig/cloudformation/params/code/src", + }, + artifactOpt: artifact.Option{ + MisconfScannerOption: misconf.ScannerOption{ + RegoOnly: true, + Namespaces: []string{"user"}, + PolicyPaths: []string{"./testdata/misconfig/cloudformation/params/code/rego"}, + CloudFormationParamVars: []string{"./testdata/misconfig/cloudformation/params/cfparams.json"}, + DisableEmbeddedPolicies: true, + DisableEmbeddedLibraries: true, + }, + }, + putBlobExpectation: cache.ArtifactCachePutBlobExpectation{ + Args: cache.ArtifactCachePutBlobArgs{ + BlobIDAnything: true, + BlobInfo: types.BlobInfo{ + SchemaVersion: types.BlobJSONSchemaVersion, + Misconfigurations: []types.Misconfiguration{ + { + FileType: "cloudformation", + FilePath: "main.yaml", + Successes: types.MisconfResults{ + { + Namespace: "user.something", + Query: "data.user.something.deny", + PolicyMetadata: types.PolicyMetadata{ + ID: "TEST001", + AVDID: "AVD-TEST-0001", + Type: "CloudFormation Security Check", + Title: "Bad stuff is bad", + Description: "Its not good!", + Severity: "HIGH", + RecommendedActions: "Remove bad stuff", + }, + CauseMetadata: types.CauseMetadata{ + Provider: "AWS", + Service: "sqs", + }, + }, + }, + }, + }, + }, + }, + Returns: cache.ArtifactCachePutBlobReturns{}, + }, + want: types.ArtifactReference{ + Name: "testdata/misconfig/cloudformation/params/code/src", + Type: types.ArtifactFilesystem, + ID: "sha256:0c66c19a4df3ecc11db9f90fbc921f1050325c05c480847369e07ee309e8a897", + BlobIDs: []string{ + "sha256:0c66c19a4df3ecc11db9f90fbc921f1050325c05c480847369e07ee309e8a897", + }, + }, + }, { name: "passed", fields: fields{ @@ -1032,7 +1090,7 @@ func TestCloudFormationMisconfigurationScan(t *testing.T) { Args: cache.ArtifactCachePutBlobArgs{ BlobIDAnything: true, BlobInfo: types.BlobInfo{ - SchemaVersion: 2, + SchemaVersion: types.BlobJSONSchemaVersion, Misconfigurations: []types.Misconfiguration{ { FileType: "cloudformation", diff --git a/pkg/fanal/artifact/local/testdata/misconfig/cloudformation/params/cfparams.json b/pkg/fanal/artifact/local/testdata/misconfig/cloudformation/params/cfparams.json new file mode 100644 index 000000000000..b9276cb36eb2 --- /dev/null +++ b/pkg/fanal/artifact/local/testdata/misconfig/cloudformation/params/cfparams.json @@ -0,0 +1,6 @@ +[ + { + "ParameterKey": "KmsMasterKeyId", + "ParameterValue": "some_id" + } +] \ No newline at end of file diff --git a/pkg/fanal/artifact/local/testdata/misconfig/cloudformation/params/code/rego/policy.rego b/pkg/fanal/artifact/local/testdata/misconfig/cloudformation/params/code/rego/policy.rego new file mode 100644 index 000000000000..1a94609aaa8b --- /dev/null +++ b/pkg/fanal/artifact/local/testdata/misconfig/cloudformation/params/code/rego/policy.rego @@ -0,0 +1,22 @@ +# METADATA +# title: "Bad stuff is bad" +# description: "Its not good!" +# scope: package +# schemas: +# - input: schema["cloud"] +# custom: +# avd_id: AVD-TEST-0001 +# id: TEST001 +# provider: aws +# service: sqs +# severity: HIGH +# short_code: foo-bar-baz +# recommended_action: "Remove bad stuff" + +package user.something + +deny[res] { + qs := input.aws.sqs.queues[_] + qs.encryption.kmskeyid.value == "" + res := "No unencrypted queues allowed!" +} \ No newline at end of file diff --git a/pkg/fanal/artifact/local/testdata/misconfig/cloudformation/params/code/src/main.yaml b/pkg/fanal/artifact/local/testdata/misconfig/cloudformation/params/code/src/main.yaml new file mode 100644 index 000000000000..45047944d8c9 --- /dev/null +++ b/pkg/fanal/artifact/local/testdata/misconfig/cloudformation/params/code/src/main.yaml @@ -0,0 +1,10 @@ +AWSTemplateFormatVersion: 2010-09-09 +Parameters: + KmsMasterKeyId: + Type: String +Resources: + TestQueue: + Type: 'AWS::SQS::Queue' + Properties: + QueueName: worst-possible-queue + KmsMasterKeyId: !Ref KmsMasterKeyId \ No newline at end of file diff --git a/pkg/flag/misconf_flags.go b/pkg/flag/misconf_flags.go index 3023ed48615a..38f8c837fa4a 100644 --- a/pkg/flag/misconf_flags.go +++ b/pkg/flag/misconf_flags.go @@ -55,6 +55,12 @@ var ( Default: []string{}, Usage: "specify paths to override the Terraform tfvars files", } + CfParamsFlag = Flag{ + Name: "cf-params", + ConfigName: "misconfiguration.cloudformation.params", + Default: []string{}, + Usage: "specify paths to override the CloudFormation parameters files", + } TerraformExcludeDownloaded = Flag{ Name: "tf-exclude-downloaded-modules", ConfigName: "misconfiguration.terraform.exclude-downloaded-modules", @@ -69,7 +75,7 @@ var ( } ) -// MisconfFlagGroup composes common printer flag structs used for commands providing misconfinguration scanning. +// MisconfFlagGroup composes common printer flag structs used for commands providing misconfiguration scanning. type MisconfFlagGroup struct { IncludeNonFailures *Flag ResetPolicyBundle *Flag @@ -81,6 +87,7 @@ type MisconfFlagGroup struct { HelmFileValues *Flag HelmStringValues *Flag TerraformTFVars *Flag + CloudformationParamVars *Flag TerraformExcludeDownloaded *Flag } @@ -90,12 +97,13 @@ type MisconfOptions struct { PolicyBundleRepository string // Values Files - HelmValues []string - HelmValueFiles []string - HelmFileValues []string - HelmStringValues []string - TerraformTFVars []string - TfExcludeDownloaded bool + HelmValues []string + HelmValueFiles []string + HelmFileValues []string + HelmStringValues []string + TerraformTFVars []string + CloudFormationParamVars []string + TfExcludeDownloaded bool } func NewMisconfFlagGroup() *MisconfFlagGroup { @@ -109,6 +117,7 @@ func NewMisconfFlagGroup() *MisconfFlagGroup { HelmStringValues: &HelmSetStringFlag, HelmValueFiles: &HelmValuesFileFlag, TerraformTFVars: &TfVarsFlag, + CloudformationParamVars: &CfParamsFlag, TerraformExcludeDownloaded: &TerraformExcludeDownloaded, } } @@ -128,19 +137,21 @@ func (f *MisconfFlagGroup) Flags() []*Flag { f.HelmStringValues, f.TerraformTFVars, f.TerraformExcludeDownloaded, + f.CloudformationParamVars, } } func (f *MisconfFlagGroup) ToOptions() (MisconfOptions, error) { return MisconfOptions{ - IncludeNonFailures: getBool(f.IncludeNonFailures), - ResetPolicyBundle: getBool(f.ResetPolicyBundle), - PolicyBundleRepository: getString(f.PolicyBundleRepository), - HelmValues: getStringSlice(f.HelmValues), - HelmValueFiles: getStringSlice(f.HelmValueFiles), - HelmFileValues: getStringSlice(f.HelmFileValues), - HelmStringValues: getStringSlice(f.HelmStringValues), - TerraformTFVars: getStringSlice(f.TerraformTFVars), - TfExcludeDownloaded: getBool(f.TerraformExcludeDownloaded), + IncludeNonFailures: getBool(f.IncludeNonFailures), + ResetPolicyBundle: getBool(f.ResetPolicyBundle), + PolicyBundleRepository: getString(f.PolicyBundleRepository), + HelmValues: getStringSlice(f.HelmValues), + HelmValueFiles: getStringSlice(f.HelmValueFiles), + HelmFileValues: getStringSlice(f.HelmFileValues), + HelmStringValues: getStringSlice(f.HelmStringValues), + TerraformTFVars: getStringSlice(f.TerraformTFVars), + CloudFormationParamVars: getStringSlice(f.CloudformationParamVars), + TfExcludeDownloaded: getBool(f.TerraformExcludeDownloaded), }, nil } diff --git a/pkg/misconf/scanner.go b/pkg/misconf/scanner.go index 39e6030e6d44..1308e683ab17 100644 --- a/pkg/misconf/scanner.go +++ b/pkg/misconf/scanner.go @@ -52,13 +52,14 @@ type ScannerOption struct { DisableEmbeddedPolicies bool DisableEmbeddedLibraries bool - HelmValues []string - HelmValueFiles []string - HelmFileValues []string - HelmStringValues []string - TerraformTFVars []string - TfExcludeDownloaded bool - K8sVersion string + HelmValues []string + HelmValueFiles []string + HelmFileValues []string + HelmStringValues []string + TerraformTFVars []string + CloudFormationParamVars []string + TfExcludeDownloaded bool + K8sVersion string } func (o *ScannerOption) Sort() { @@ -71,7 +72,6 @@ type Scanner struct { fileType detection.FileType scanner scanners.FSScanner hasFilePattern bool - configFiles []string } func NewAzureARMScanner(filePatterns []string, opt ScannerOption) (*Scanner, error) { @@ -109,7 +109,6 @@ func newScanner(t detection.FileType, filePatterns []string, opt ScannerOption) } var scanner scanners.FSScanner - var configFiles []string switch t { case detection.FileTypeAzureARM: scanner = arm.New(opts...) @@ -119,12 +118,10 @@ func newScanner(t detection.FileType, filePatterns []string, opt ScannerOption) scanner = dfscanner.NewScanner(opts...) case detection.FileTypeHelm: scanner = helm.New(opts...) - configFiles = append(opt.HelmFileValues, opt.HelmValueFiles...) case detection.FileTypeKubernetes: scanner = k8sscanner.NewScanner(opts...) case detection.FileTypeTerraform: scanner = tfscanner.New(opts...) - configFiles = opt.TerraformTFVars case detection.FileTypeTerraformPlan: scanner = tfpscanner.New(opts...) } @@ -133,7 +130,6 @@ func newScanner(t detection.FileType, filePatterns []string, opt ScannerOption) fileType: t, scanner: scanner, hasFilePattern: hasFilePattern(t, filePatterns), - configFiles: configFiles, }, nil } @@ -146,10 +142,6 @@ func (s *Scanner) Scan(ctx context.Context, fsys fs.FS) ([]types.Misconfiguratio return nil, nil } - if err := addConfigFilesToFS(newfs, s.configFiles); err != nil { - return nil, xerrors.Errorf("failed to add config files to fs: %w", err) - } - log.Logger.Debugf("Scanning %s files for misconfigurations...", s.scanner.Name()) results, err := s.scanner.ScanFS(ctx, newfs, ".") if err != nil { @@ -174,30 +166,6 @@ func (s *Scanner) Scan(ctx context.Context, fsys fs.FS) ([]types.Misconfiguratio return misconfs, nil } -func addConfigFilesToFS(fsys fs.FS, configFiles []string) error { - if len(configFiles) == 0 { - return nil - } - - mfs, ok := fsys.(*mapfs.FS) - if !ok { - return xerrors.Errorf("type assertion error: %T is not a *mapfs.FS", fsys) - } - for _, configFile := range configFiles { - if _, err := os.Stat(configFile); err != nil { - return xerrors.Errorf("config file %q not found: %w", configFile, err) - } - if err := mfs.MkdirAll(filepath.Dir(configFile), os.ModePerm); err != nil && !errors.Is(err, fs.ErrExist) { - return xerrors.Errorf("mkdir error: %w", err) - } - if err := mfs.WriteFile(configFile, configFile); err != nil { - return xerrors.Errorf("write file error: %w", err) - } - } - - return nil -} - func (s *Scanner) filterFS(fsys fs.FS) (fs.FS, error) { mfs, ok := fsys.(*mapfs.FS) if !ok { @@ -281,7 +249,9 @@ func scannerOptions(t detection.FileType, opt ScannerOption) ([]options.ScannerO case detection.FileTypeHelm: return addHelmOpts(opts, opt), nil case detection.FileTypeTerraform: - return addTFOpts(opts, opt), nil + return addTFOpts(opts, opt) + case detection.FileTypeCloudFormation: + return addCFOpts(opts, opt) default: return opts, nil } @@ -296,9 +266,17 @@ func hasFilePattern(t detection.FileType, filePatterns []string) bool { return false } -func addTFOpts(opts []options.ScannerOption, scannerOption ScannerOption) []options.ScannerOption { +func addTFOpts(opts []options.ScannerOption, scannerOption ScannerOption) ([]options.ScannerOption, error) { if len(scannerOption.TerraformTFVars) > 0 { - opts = append(opts, tfscanner.ScannerWithTFVarsPaths(scannerOption.TerraformTFVars...)) + configFS, err := createConfigFS(scannerOption.TerraformTFVars) + if err != nil { + return nil, xerrors.Errorf("failed to create Terraform config FS: %w", err) + } + opts = append( + opts, + tfscanner.ScannerWithTFVarsPaths(scannerOption.TerraformTFVars...), + tfscanner.ScannerWithConfigsFileSystem(configFS), + ) } opts = append(opts, @@ -306,7 +284,22 @@ func addTFOpts(opts []options.ScannerOption, scannerOption ScannerOption) []opti tfscanner.ScannerWithSkipDownloaded(scannerOption.TfExcludeDownloaded), ) - return opts + return opts, nil +} + +func addCFOpts(opts []options.ScannerOption, scannerOption ScannerOption) ([]options.ScannerOption, error) { + if len(scannerOption.CloudFormationParamVars) > 0 { + configFS, err := createConfigFS(scannerOption.CloudFormationParamVars) + if err != nil { + return nil, xerrors.Errorf("failed to create CloudFormation config FS: %w", err) + } + opts = append( + opts, + cfscanner.WithParameterFiles(scannerOption.CloudFormationParamVars...), + cfscanner.WithConfigsFS(configFS), + ) + } + return opts, nil } func addHelmOpts(opts []options.ScannerOption, scannerOption ScannerOption) []options.ScannerOption { @@ -329,6 +322,19 @@ func addHelmOpts(opts []options.ScannerOption, scannerOption ScannerOption) []op return opts } +func createConfigFS(paths []string) (fs.FS, error) { + mfs := mapfs.New() + for _, path := range paths { + if err := mfs.MkdirAll(filepath.Dir(path), os.ModePerm); err != nil && !errors.Is(err, fs.ErrExist) { + return nil, xerrors.Errorf("create dir error: %w", err) + } + if err := mfs.WriteFile(path, path); err != nil { + return nil, xerrors.Errorf("write file error: %w", err) + } + } + return mfs, nil +} + func CreatePolicyFS(policyPaths []string) (fs.FS, []string, error) { if len(policyPaths) == 0 { return nil, nil, nil