diff --git a/.github/workflows/build.yaml b/.github/workflows/build.yaml index 644dd5b0..ecf6592c 100644 --- a/.github/workflows/build.yaml +++ b/.github/workflows/build.yaml @@ -20,8 +20,8 @@ jobs: env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} with: - tag_name: v1.0.${{ github.run_number }}-beta - release_name: Release v1.0.${{ github.run_number }}-beta + tag_name: v1.0.${{ github.run_number }} + release_name: Release v1.0.${{ github.run_number }} draft: false prerelease: false build: diff --git a/README.md b/README.md index 7cb6764d..70d69013 100644 --- a/README.md +++ b/README.md @@ -124,6 +124,9 @@ Kubescape is running the following tests according to what is defined by [Kubern * Dangerous capabilities * Insecure capabilities * Linux hardening +* Ingress and Egress blocked +* Container hostPort +* Anonymous requests ## Technology diff --git a/cautils/k8sinterface/k8sconfig_test.go b/cautils/k8sinterface/k8sconfig_test.go index 2b29a70f..be057d4f 100644 --- a/cautils/k8sinterface/k8sconfig_test.go +++ b/cautils/k8sinterface/k8sconfig_test.go @@ -23,4 +23,12 @@ func TestGetGroupVersionResource(t *testing.T) { t.Errorf("wrong Resource") } + r2, err := GetGroupVersionResource("NetworkPolicy") + if err != nil { + t.Error(err) + return + } + if r2.Resource != "networkpolicies" { + t.Errorf("wrong Resource") + } } diff --git a/cautils/k8sinterface/resourcegroupmapping.go b/cautils/k8sinterface/resourcegroupmapping.go index cded9d84..e6c0dad4 100644 --- a/cautils/k8sinterface/resourcegroupmapping.go +++ b/cautils/k8sinterface/resourcegroupmapping.go @@ -46,10 +46,7 @@ var GroupsClusterScope = []string{} var ResourceClusterScope = []string{"nodes", "namespaces", "clusterroles", "clusterrolebindings"} func GetGroupVersionResource(resource string) (schema.GroupVersionResource, error) { - resource = strings.ToLower(resource) - if resource != "" && !strings.HasSuffix(resource, "s") { - resource = fmt.Sprintf("%ss", resource) // add 's' at the end of a resource - } + resource = updateResourceKind(resource) if r, ok := ResourceGroupMapping[resource]; ok { gv := strings.Split(r, "/") return schema.GroupVersionResource{Group: gv[0], Version: gv[1], Resource: resource}, nil @@ -116,10 +113,7 @@ func ResourceGroupToString(group, version, resource string) []string { if resource == "*" { resource = "" } - resource = strings.ToLower(resource) - if resource != "" && !strings.HasSuffix(resource, "s") { - resource = fmt.Sprintf("%ss", resource) // add 's' at the end of a resource - } + resource = updateResourceKind(resource) return GetResourceTriplets(group, version, resource) } @@ -132,3 +126,17 @@ func StringToResourceGroup(str string) (string, string, string) { } return splitted[0], splitted[1], splitted[2] } + +func updateResourceKind(resource string) string { + resource = strings.ToLower(resource) + + if resource != "" && !strings.HasSuffix(resource, "s") { + if strings.HasSuffix(resource, "y") { + return fmt.Sprintf("%sies", strings.TrimSuffix(resource, "y")) // e.g. NetworkPolicy -> networkpolicies + } else { + return fmt.Sprintf("%ss", resource) // add 's' at the end of a resource + } + } + return resource + +} diff --git a/cautils/opapolicy/datastructures.go b/cautils/opapolicy/datastructures.go index 1c897716..e3115cb8 100644 --- a/cautils/opapolicy/datastructures.go +++ b/cautils/opapolicy/datastructures.go @@ -48,6 +48,7 @@ type RuleReport struct { RuleStatus RuleStatus `json:"ruleStatus"` RuleResponses []RuleResponse `json:"ruleResponses"` ListInputResources []map[string]interface{} `json:"-"` + ListInputKinds []string `json:"-"` } type RuleStatus struct { Status string `json:"status"` diff --git a/cautils/opapolicy/datastructuresmethods.go b/cautils/opapolicy/datastructuresmethods.go index 6f48bab1..e2bce425 100644 --- a/cautils/opapolicy/datastructuresmethods.go +++ b/cautils/opapolicy/datastructuresmethods.go @@ -78,6 +78,13 @@ func (controlReport *ControlReport) GetNumberOfResources() int { return sum } +func (controlReport *ControlReport) ListControlsInputKinds() []string { + listControlsInputKinds := []string{} + for i := range controlReport.RuleReports { + listControlsInputKinds = append(listControlsInputKinds, controlReport.RuleReports[i].ListInputKinds...) + } + return listControlsInputKinds +} func (controlReport *ControlReport) Passed() bool { for i := range controlReport.RuleReports { if len(controlReport.RuleReports[i].RuleResponses) > 0 { diff --git a/cautils/opapolicy/resources/dependencies.go b/cautils/opapolicy/resources/dependencies.go index 87dd3bd4..f8b0de1d 100644 --- a/cautils/opapolicy/resources/dependencies.go +++ b/cautils/opapolicy/resources/dependencies.go @@ -196,6 +196,21 @@ query_all(resource) = http.send({ "raise_error": true, }) + + +# Query for all resources of type resource in all namespaces - without authentication +# Example: query_all("deployments") +query_all_no_auth(resource) = http.send({ + "url": sprintf("%v/%v/namespaces/default/%v", [ + host, + resource_group_mapping[resource], + resource, + ]), + "method": "get", + "raise_error": true, + "tls_insecure_skip_verify" : true, +}) + field_transform_to_qry_param(field,map) = finala { mid := {concat(".",[field,key]): val | val := map[key]} finala := label_map_to_query_string(mid) diff --git a/cmd/framework.go b/cmd/framework.go index 878c40ad..51272b29 100644 --- a/cmd/framework.go +++ b/cmd/framework.go @@ -29,7 +29,7 @@ type CLIHandler struct { var frameworkCmd = &cobra.Command{ Use: "framework [``/`-`] [flags]", Short: fmt.Sprintf("The framework you wish to use. Supported frameworks: %s", strings.Join(supportedFrameworks, ", ")), - Long: "Execute a scan on a running Kubernetes cluster or yaml/json files (use glob) or `-` for stdin", + Long: "Execute a scan on a running Kubernetes cluster or `yaml`/`json` files (use glob) or `-` for stdin", ValidArgs: supportedFrameworks, Args: func(cmd *cobra.Command, args []string) error { if len(args) < 1 { @@ -75,7 +75,7 @@ func init() { scanCmd.AddCommand(frameworkCmd) scanInfo = opapolicy.ScanInfo{} frameworkCmd.Flags().StringVarP(&scanInfo.ExcludedNamespaces, "exclude-namespaces", "e", "", "namespaces to exclude from check") - frameworkCmd.Flags().StringVarP(&scanInfo.Format, "format", "f", "pretty-printer", "output format. supported formats: `pretty-printer`/`json`/`junit`") + frameworkCmd.Flags().StringVarP(&scanInfo.Format, "format", "f", "pretty-printer", `output format. supported formats: "pretty-printer"/"json"/"junit"`) frameworkCmd.Flags().StringVarP(&scanInfo.Output, "output", "o", "", "output file. print output to file and not stdout") frameworkCmd.Flags().BoolVarP(&scanInfo.Silent, "silent", "s", false, "silent progress output") } diff --git a/opaprocessor/processorhandler.go b/opaprocessor/processorhandler.go index 52ac6f7c..53084369 100644 --- a/opaprocessor/processorhandler.go +++ b/opaprocessor/processorhandler.go @@ -87,6 +87,7 @@ func (opap *OPAProcessor) ProcessRulesHandler(opaSessionObj *cautils.OPASessionO ruleReport.RuleStatus.Status = "success" } ruleReport.ListInputResources = k8sObjects + ruleReport.ListInputKinds = listMatchKinds(rule.Match) ruleReports = append(ruleReports, ruleReport) } controlReport.RuleReports = ruleReports diff --git a/opaprocessor/processorhandlerutils.go b/opaprocessor/processorhandlerutils.go index 8189f7ad..8ed58d6c 100644 --- a/opaprocessor/processorhandlerutils.go +++ b/opaprocessor/processorhandlerutils.go @@ -59,3 +59,11 @@ func ruleWithArmoOpaDependency(annotations map[string]interface{}) bool { } return false } + +func listMatchKinds(match []opapolicy.RuleMatchObjects) []string { + matchKinds := []string{} + for i := range match { + matchKinds = append(matchKinds, match[i].Resources...) + } + return matchKinds +} diff --git a/printer/printresults.go b/printer/printresults.go index a4b4b74e..b2667ded 100644 --- a/printer/printresults.go +++ b/printer/printresults.go @@ -95,6 +95,7 @@ func (printer *Printer) SummarySetup(postureReport *opapolicy.PostureReport) { WorkloadSummary: mapResources, Description: cr.Description, Remediation: cr.Remediation, + ListInputKinds: cr.ListControlsInputKinds(), } } } @@ -129,7 +130,7 @@ func (printer *Printer) printSummary(controlName string, controlSummary *Control func (printer *Printer) printTitle(controlName string, controlSummary *ControlSummary) { cautils.InfoDisplay(printer.writer, "[control: %s] ", controlName) - if controlSummary.TotalResources == 0 { + if controlSummary.TotalResources == 0 && len(controlSummary.ListInputKinds) > 0 { cautils.InfoDisplay(printer.writer, "resources not found %v\n", emoji.ConfusedFace) } else if controlSummary.TotalFailed == 0 { cautils.SuccessDisplay(printer.writer, "passed %v\n", emoji.ThumbsUp) diff --git a/printer/summary.go b/printer/summary.go index 6c567830..482c4887 100644 --- a/printer/summary.go +++ b/printer/summary.go @@ -15,6 +15,7 @@ type ControlSummary struct { TotalFailed int Description string Remediation string + ListInputKinds []string WorkloadSummary map[string][]WorkloadSummary // :[] }