diff --git a/cmd/fanal/main.go b/cmd/fanal/main.go index 2e88a988ec..6ad3b5c131 100644 --- a/cmd/fanal/main.go +++ b/cmd/fanal/main.go @@ -60,6 +60,11 @@ func run() (err error) { Aliases: []string{"fs"}, Usage: "inspect a local directory", Flags: []cli.Flag{ + &cli.StringSliceFlag{ + Name: "namespace", + Usage: "namespaces", + Value: cli.NewStringSlice("appshield"), + }, &cli.StringSliceFlag{ Name: "policy", Usage: "policy paths", @@ -141,6 +146,7 @@ func archiveAction(c *cli.Context, fsCache cache.Cache) error { func fsAction(c *cli.Context, fsCache cache.Cache) error { art, err := local.NewArtifact(c.Args().First(), fsCache, nil, config.ScannerOption{ + Namespaces: []string{"appshield"}, PolicyPaths: c.StringSlice("policy"), }) if err != nil { @@ -189,6 +195,9 @@ func inspect(ctx context.Context, art artifact.Artifact, c cache.LocalArtifactCa } for _, misconf := range mergedLayer.Misconfigurations { fmt.Printf(" %s: failures %d, warnings %d\n", misconf.FilePath, len(misconf.Failures), len(misconf.Warnings)) + for _, failure := range misconf.Failures { + fmt.Printf(" %s: %s\n", failure.ID, failure.Message) + } } return nil } diff --git a/policy/engine.go b/policy/engine.go index 82da600a31..9c8a2d05f7 100644 --- a/policy/engine.go +++ b/policy/engine.go @@ -196,13 +196,13 @@ func (e *Engine) Check(ctx context.Context, configs []types.Config, namespaces [ } var selectedConfigs []types.Config - if len(inputOption.Selector.Types) > 0 { + if len(inputOption.Selectors) > 0 { // Pass only the config files that match the selector types - for _, t := range inputOption.Selector.Types { + for _, t := range uniqueSelectorTypes(inputOption.Selectors) { selectedConfigs = append(selectedConfigs, typedConfigs[t]...) } } else { - // When the 'types' is not specified, it means '*'. + // When the 'selector' is not specified, it means '*'. selectedConfigs = configs } @@ -666,6 +666,14 @@ func removeRulePrefix(rule string) string { return rule } +func uniqueSelectorTypes(selectors []types.PolicyInputSelector) []string { + selectorTypes := map[string]struct{}{} + for _, s := range selectors { + selectorTypes[s.Type] = struct{}{} + } + return utils.Keys(selectorTypes) +} + func uniqueResults(results []types.MisconfResult) []types.MisconfResult { uniq := map[string]types.MisconfResult{} for _, result := range results { diff --git a/policy/testdata/combine/combined_deployment.rego b/policy/testdata/combine/combined_deployment.rego index 1162abba76..65bc71395c 100644 --- a/policy/testdata/combine/combined_deployment.rego +++ b/policy/testdata/combine/combined_deployment.rego @@ -11,8 +11,8 @@ __rego_metadata__ := { } __rego_input__ := { - "selector": {"types": ["kubernetes"]}, "combine": true, + "selector": [{"type": "kubernetes"}], } deny[res] { diff --git a/policy/testdata/combine/docker.rego b/policy/testdata/combine/combined_docker.rego similarity index 88% rename from policy/testdata/combine/docker.rego rename to policy/testdata/combine/combined_docker.rego index 9993eeabc8..d022473ca7 100644 --- a/policy/testdata/combine/docker.rego +++ b/policy/testdata/combine/combined_docker.rego @@ -11,8 +11,8 @@ __rego_metadata__ := { } __rego_input__ := { - "selector": {"types": ["dockerfile"]}, "combine": true, + "selector": [{"type": "dockerfile"}], } deny[res] { diff --git a/policy/testdata/combine/combined_pod.rego b/policy/testdata/combine/combined_pod.rego index 5f0cf56d06..e69a6bcfb1 100644 --- a/policy/testdata/combine/combined_pod.rego +++ b/policy/testdata/combine/combined_pod.rego @@ -1,22 +1,20 @@ package testdata.xyz_400 __rego_metadata__ := { - "id": "XYZ-400", - "title": "Bad Combined Pod", - "version": "v1.0.0", - "severity": "LOW", - "type": "Kubernetes Security Check", + "id": "XYZ-400", + "title": "Bad Combined Pod", + "version": "v1.0.0", + "severity": "LOW", + "type": "Kubernetes Security Check", } __rego_input__ := { - "selector": { - "types": ["kubernetes"] - }, - "combine": true, + "combine": true, + "selector": [{"type": "kubernetes"}], } deny[res] { - input[i].contents.kind == "Pod" + input[i].contents.kind == "Pod" res := { "filepath": input[i].path, "msg": sprintf("deny combined %s", [input[i].contents.metadata.name]), diff --git a/policy/testdata/combine/deployment.rego b/policy/testdata/combine/deployment.rego index 8d4eea1383..b28ee6bf45 100644 --- a/policy/testdata/combine/deployment.rego +++ b/policy/testdata/combine/deployment.rego @@ -11,8 +11,8 @@ __rego_metadata__ := { } __rego_input__ := { - "selector": {"types": ["kubernetes"]}, "combine": false, + "selector": [{"type": "kubernetes"}], } warn[msg] { diff --git a/policy/testdata/combine_exception/combined_deployment.rego b/policy/testdata/combine_exception/combined_deployment.rego index 5b1d0c8deb..7bac9d2cc6 100644 --- a/policy/testdata/combine_exception/combined_deployment.rego +++ b/policy/testdata/combine_exception/combined_deployment.rego @@ -11,8 +11,8 @@ __rego_metadata__ := { } __rego_input__ := { - "selector": {"types": ["kubernetes"]}, "combine": true, + "selector": [{"type": "kubernetes"}], } warn[res] { diff --git a/policy/testdata/combine_exception/deployment.rego b/policy/testdata/combine_exception/deployment.rego index 8d4eea1383..b28ee6bf45 100644 --- a/policy/testdata/combine_exception/deployment.rego +++ b/policy/testdata/combine_exception/deployment.rego @@ -11,8 +11,8 @@ __rego_metadata__ := { } __rego_input__ := { - "selector": {"types": ["kubernetes"]}, "combine": false, + "selector": [{"type": "kubernetes"}], } warn[msg] { diff --git a/policy/testdata/combine_exception/exceptions.rego b/policy/testdata/combine_exception/exceptions.rego index 170311f06e..d1adb5b14a 100644 --- a/policy/testdata/combine_exception/exceptions.rego +++ b/policy/testdata/combine_exception/exceptions.rego @@ -3,6 +3,6 @@ package namespace.exceptions import data.namespaces exception[ns] { - ns := data.namespaces[_] - ns == "testdata.xyz_300" + ns := data.namespaces[_] + ns == "testdata.xyz_300" } diff --git a/policy/testdata/combine_exception/fail.rego b/policy/testdata/combine_exception/fail.rego index 729f344448..8529b9cce9 100644 --- a/policy/testdata/combine_exception/fail.rego +++ b/policy/testdata/combine_exception/fail.rego @@ -11,8 +11,8 @@ __rego_metadata__ := { } __rego_input__ := { - "selector": {"types": ["kubernetes"]}, "combine": true, + "selector": [{"type": "kubernetes"}], } deny[res] { diff --git a/policy/testdata/happy/deployment.rego b/policy/testdata/happy/deployment.rego index 37df78f512..239ecc6b61 100644 --- a/policy/testdata/happy/deployment.rego +++ b/policy/testdata/happy/deployment.rego @@ -3,22 +3,20 @@ package testdata.xyz_100 import data.services __rego_metadata__ := { - "id": "XYZ-100", - "title": "Bad Deployment", - "version": "v1.0.0", - "severity": "HIGH", - "type": "Kubernetes Security Check", + "id": "XYZ-100", + "title": "Bad Deployment", + "version": "v1.0.0", + "severity": "HIGH", + "type": "Kubernetes Security Check", } __rego_input__ := { - "selector": { - "types": ["kubernetes"] - }, - "combine": false, + "combine": false, + "selector": [{"type": "kubernetes"}], } deny[msg] { - input.kind == "Deployment" - services.ports[_] == 22 - msg := sprintf("deny %s", [input.metadata.name]) + input.kind == "Deployment" + services.ports[_] == 22 + msg := sprintf("deny %s", [input.metadata.name]) } diff --git a/policy/testdata/happy/docker.rego b/policy/testdata/happy/docker.rego index 3672b75d19..aad584af16 100644 --- a/policy/testdata/happy/docker.rego +++ b/policy/testdata/happy/docker.rego @@ -1,20 +1,18 @@ package testdata.xyz_200 __rego_metadata__ := { - "id": "XYZ-200", - "title": "Bad FROM", - "version": "v1.0.0", - "severity": "LOW", - "type": "Docker Security Check", + "id": "XYZ-200", + "title": "Bad FROM", + "version": "v1.0.0", + "severity": "LOW", + "type": "Docker Security Check", } __rego_input__ := { - "selector": { - "types": ["dockerfile"] - }, - "combine": false, + "combine": false, + "selector": [{"type": "dockerfile"}], } deny[msg] { - msg := "bad Dockerfile" + msg := "bad Dockerfile" } diff --git a/policy/testdata/happy/pod.rego b/policy/testdata/happy/pod.rego index 90a5edf2da..c335710a36 100644 --- a/policy/testdata/happy/pod.rego +++ b/policy/testdata/happy/pod.rego @@ -1,21 +1,19 @@ package testdata.xyz_300 __rego_metadata__ := { - "id": "XYZ-300", - "title": "Bad Pod", - "version": "v1.0.0", - "severity": "CRITICAL", - "type": "Kubernetes Security Check", + "id": "XYZ-300", + "title": "Bad Pod", + "version": "v1.0.0", + "severity": "CRITICAL", + "type": "Kubernetes Security Check", } __rego_input__ := { - "selector": { - "types": ["kubernetes"] - }, - "combine": false, + "combine": false, + "selector": [{"type": "kubernetes"}], } deny[msg] { - input.kind == "Pod" - msg := sprintf("deny %s", [input.metadata.name]) + input.kind == "Pod" + msg := sprintf("deny %s", [input.metadata.name]) } diff --git a/policy/testdata/namespace_exception/100.rego b/policy/testdata/namespace_exception/100.rego index 54f71a99f8..d90fd2f6c8 100644 --- a/policy/testdata/namespace_exception/100.rego +++ b/policy/testdata/namespace_exception/100.rego @@ -1,14 +1,14 @@ package testdata.kubernetes.xyz_100 __rego_metadata__ := { - "id": "XYZ-100", - "title": "Bad Deployment", - "version": "v1.0.0", - "severity": "HIGH", - "type": "Kubernetes Security Check", + "id": "XYZ-100", + "title": "Bad Deployment", + "version": "v1.0.0", + "severity": "HIGH", + "type": "Kubernetes Security Check", } deny[msg] { - input.kind == "Deployment" - msg := sprintf("deny 100 %s", [input.metadata.name]) -} \ No newline at end of file + input.kind == "Deployment" + msg := sprintf("deny 100 %s", [input.metadata.name]) +} diff --git a/policy/testdata/namespace_exception/200.rego b/policy/testdata/namespace_exception/200.rego index 2dad145c20..0739d4b852 100644 --- a/policy/testdata/namespace_exception/200.rego +++ b/policy/testdata/namespace_exception/200.rego @@ -1,14 +1,14 @@ package testdata.kubernetes.xyz_200 __rego_metadata__ := { - "id": "XYZ-200", - "title": "Bad Deployment", - "version": "v1.0.0", - "severity": "HIGH", - "type": "Kubernetes Security Check", + "id": "XYZ-200", + "title": "Bad Deployment", + "version": "v1.0.0", + "severity": "HIGH", + "type": "Kubernetes Security Check", } deny[res] { - input.kind == "Deployment" - res := {"msg": sprintf("deny 200 %s", [input.metadata.name])} -} \ No newline at end of file + input.kind == "Deployment" + res := {"msg": sprintf("deny 200 %s", [input.metadata.name])} +} diff --git a/policy/testdata/namespace_exception/exceptions.rego b/policy/testdata/namespace_exception/exceptions.rego index cd3e3e9603..2f69480a8b 100644 --- a/policy/testdata/namespace_exception/exceptions.rego +++ b/policy/testdata/namespace_exception/exceptions.rego @@ -3,6 +3,6 @@ package namespace.exceptions import data.namespaces exception[ns] { - ns := data.namespaces[_] - ns == "testdata.kubernetes.xyz_100" + ns := data.namespaces[_] + ns == "testdata.kubernetes.xyz_100" } diff --git a/policy/testdata/rule_exception/deployment.rego b/policy/testdata/rule_exception/deployment.rego index dd1980832e..69f90870da 100644 --- a/policy/testdata/rule_exception/deployment.rego +++ b/policy/testdata/rule_exception/deployment.rego @@ -1,23 +1,23 @@ package testdata.kubernetes.xyz_100 __rego_metadata__ := { - "id": "XYZ-100", - "title": "Bad Deployment", - "version": "v1.0.0", - "severity": "HIGH", - "type": "Kubernetes Security Check", + "id": "XYZ-100", + "title": "Bad Deployment", + "version": "v1.0.0", + "severity": "HIGH", + "type": "Kubernetes Security Check", } deny_foo[msg] { - input.kind == "Deployment" - msg := sprintf("deny foo %s", [input.metadata.name]) + input.kind == "Deployment" + msg := sprintf("deny foo %s", [input.metadata.name]) } deny_bar[msg] { - input.kind == "Deployment" - msg := sprintf("deny bar %s", [input.metadata.name]) + input.kind == "Deployment" + msg := sprintf("deny bar %s", [input.metadata.name]) } exception[rules] { - rules = ["foo"] -} \ No newline at end of file + rules = ["foo"] +} diff --git a/policy/testdata/sad/broken_metadata.rego b/policy/testdata/sad/broken_metadata.rego index c958f781a2..3e64d8e9fa 100644 --- a/policy/testdata/sad/broken_metadata.rego +++ b/policy/testdata/sad/broken_metadata.rego @@ -3,6 +3,6 @@ package testdata.kubernetes.xyz_100 __rego_metadata__ := "broken" deny[msg] { - input.kind == "Deployment" - msg := sprintf("deny %s", [input.metadata.name]) + input.kind == "Deployment" + msg := sprintf("deny %s", [input.metadata.name]) } diff --git a/policy/testdata/sad/broken_msg.rego b/policy/testdata/sad/broken_msg.rego index 530695b881..a3f420c942 100644 --- a/policy/testdata/sad/broken_msg.rego +++ b/policy/testdata/sad/broken_msg.rego @@ -1,14 +1,14 @@ package testdata.kubernetes.xyz_200 __rego_metadata__ := { - "id": "XYZ-200", - "title": "Bad Deployment", - "version": "v1.0.0", - "severity": "HIGH", - "type": "Kubernetes Security Check", + "id": "XYZ-200", + "title": "Bad Deployment", + "version": "v1.0.0", + "severity": "HIGH", + "type": "Kubernetes Security Check", } deny[res] { - input.kind == "Deployment" - res := {"hello": "world"} -} \ No newline at end of file + input.kind == "Deployment" + res := {"hello": "world"} +} diff --git a/policy/testdata/sad/broken_rule.rego b/policy/testdata/sad/broken_rule.rego index ba91a2c9bd..b27382ed65 100644 --- a/policy/testdata/sad/broken_rule.rego +++ b/policy/testdata/sad/broken_rule.rego @@ -1,5 +1,5 @@ package testdata.kubernetes.xyz_100 deny[msg] { - broken + broken } diff --git a/policy/testdata/sad/missing_filepath.rego b/policy/testdata/sad/missing_filepath.rego index 4f75128232..9c68901c33 100644 --- a/policy/testdata/sad/missing_filepath.rego +++ b/policy/testdata/sad/missing_filepath.rego @@ -11,14 +11,12 @@ __rego_metadata__ := { } __rego_input__ := { - "selector": {"types": ["kubernetes"]}, "combine": true, + "selector": [{"type": "kubernetes"}], } warn[res] { input[i].contents.kind == "Deployment" services.ports[_] == 22 - res := { - "msg": sprintf("deny combined %s", [input[i].contents.metadata.name]), - } + res := {"msg": sprintf("deny combined %s", [input[i].contents.metadata.name])} } diff --git a/policy/testdata/sad/missing_metadata.rego b/policy/testdata/sad/missing_metadata.rego index c45e28e0ff..acf874fa1a 100644 --- a/policy/testdata/sad/missing_metadata.rego +++ b/policy/testdata/sad/missing_metadata.rego @@ -1,6 +1,6 @@ package testdata.kubernetes.xyz_100 deny[msg] { - input.kind == "Deployment" - msg := sprintf("deny %s", [input.metadata.name]) + input.kind == "Deployment" + msg := sprintf("deny %s", [input.metadata.name]) } diff --git a/policy/testdata/sad/missing_metadata_fields.rego b/policy/testdata/sad/missing_metadata_fields.rego index 60967bc0c1..25abb7523f 100644 --- a/policy/testdata/sad/missing_metadata_fields.rego +++ b/policy/testdata/sad/missing_metadata_fields.rego @@ -1,12 +1,12 @@ package testdata.kubernetes.xyz_100 __rego_metadata__ := { - "title": "Bad Deployment", - "version": "v1.0.0", - "type": "Kubernetes Security Check", + "title": "Bad Deployment", + "version": "v1.0.0", + "type": "Kubernetes Security Check", } deny[msg] { - input.kind == "Deployment" - msg := sprintf("deny %s", [input.metadata.name]) + input.kind == "Deployment" + msg := sprintf("deny %s", [input.metadata.name]) } diff --git a/types/misconf.go b/types/misconf.go index c5440aefad..837a2b8845 100644 --- a/types/misconf.go +++ b/types/misconf.go @@ -26,12 +26,12 @@ type PolicyMetadata struct { } type PolicyInputOption struct { - Combine bool - Selector PolicyInputSelector + Combine bool `mapstructure:"combine"` + Selectors []PolicyInputSelector `mapstructure:"selector"` } type PolicyInputSelector struct { - Types []string + Type string `mapstructure:"type"` } func (r MisconfResults) Len() int { diff --git a/utils/utils.go b/utils/utils.go index d406ccce2b..334932efa1 100644 --- a/utils/utils.go +++ b/utils/utils.go @@ -43,3 +43,11 @@ func IsGzip(f *bufio.Reader) bool { } return buf[0] == 0x1F && buf[1] == 0x8B && buf[2] == 0x8 } + +func Keys(m map[string]struct{}) []string { + var keys []string + for k := range m { + keys = append(keys, k) + } + return keys +}