Skip to content

Commit

Permalink
fix: k8s summary separate infra and user finding results (#6120)
Browse files Browse the repository at this point in the history
Signed-off-by: chenk <hen.keinan@gmail.com>
  • Loading branch information
chen-keinan committed Feb 27, 2024
1 parent 1b7e474 commit dc76c6e
Show file tree
Hide file tree
Showing 6 changed files with 80 additions and 136 deletions.
140 changes: 42 additions & 98 deletions pkg/k8s/report/report.go
Expand Up @@ -22,6 +22,7 @@ const (

workloadComponent = "workload"
infraComponent = "infra"
infraNamespace = "kube-system"
)

type Option struct {
Expand Down Expand Up @@ -134,91 +135,77 @@ type reports struct {
// - infra checks report
func SeparateMisconfigReports(k8sReport Report, scanners types.Scanners, components []string) []reports {

var workloadMisconfig, infraMisconfig, rbacAssessment, workloadVulnerabilities, workloadResource []Resource
var workloadMisconfig, infraMisconfig, rbacAssessment, workloadVulnerabilities, infraVulnerabilities, workloadResource []Resource
for _, resource := range k8sReport.Resources {
if vulnerabilitiesOrSecretResource(resource) {
workloadVulnerabilities = append(workloadVulnerabilities, resource)
continue
}

switch {
case vulnerabilitiesOrSecretResource(resource):
if resource.Namespace == infraNamespace || nodeInfoResource(resource) {
infraVulnerabilities = append(infraVulnerabilities, nodeKind(resource))
} else {
workloadVulnerabilities = append(workloadVulnerabilities, resource)
}
case scanners.Enabled(types.RBACScanner) && rbacResource(resource):
rbacAssessment = append(rbacAssessment, resource)
case infraResource(resource):
workload, infra := splitInfraAndWorkloadResources(resource)

if slices.Contains(components, infraComponent) {
infraMisconfig = append(infraMisconfig, infra)
}

if slices.Contains(components, workloadComponent) {
workloadMisconfig = append(workloadMisconfig, workload)
}

case scanners.Enabled(types.MisconfigScanner) && !rbacResource(resource):
if slices.Contains(components, workloadComponent) {
workloadMisconfig = append(workloadMisconfig, resource)
}
infraMisconfig = append(infraMisconfig, nodeKind(resource))
case scanners.Enabled(types.MisconfigScanner) &&
!rbacResource(resource) &&
slices.Contains(components, workloadComponent):
workloadMisconfig = append(workloadMisconfig, resource)
}
}

var r []reports
workloadResource = append(workloadResource, workloadVulnerabilities...)
workloadResource = append(workloadResource, workloadMisconfig...)
if shouldAddWorkloadReport(scanners) {
if shouldAddToReport(scanners, components, workloadComponent) {
workloadReport := Report{
SchemaVersion: 0,
ClusterName: k8sReport.ClusterName,
Resources: workloadResource,
name: "Workload Assessment",
}

if (slices.Contains(components, workloadComponent) &&
len(workloadMisconfig) > 0) ||
len(workloadVulnerabilities) > 0 {
if slices.Contains(components, workloadComponent) {
r = append(r, reports{
Report: workloadReport,
Columns: WorkloadColumns(),
})
}
}

if scanners.Enabled(types.RBACScanner) && len(rbacAssessment) > 0 {
infraMisconfig = append(infraMisconfig, infraVulnerabilities...)
if shouldAddToReport(scanners, components, infraComponent) {
r = append(r, reports{
Report: Report{
SchemaVersion: 0,
ClusterName: k8sReport.ClusterName,
Resources: rbacAssessment,
name: "RBAC Assessment",
Resources: infraMisconfig,
name: "Infra Assessment",
},
Columns: RoleColumns(),
Columns: InfraColumns(),
})
}

if scanners.Enabled(types.MisconfigScanner) &&
slices.Contains(components, infraComponent) &&
len(infraMisconfig) > 0 {

if scanners.Enabled(types.RBACScanner) {
r = append(r, reports{
Report: Report{
SchemaVersion: 0,
ClusterName: k8sReport.ClusterName,
Resources: infraMisconfig,
name: "Infra Assessment",
Resources: rbacAssessment,
name: "RBAC Assessment",
},
Columns: InfraColumns(),
Columns: RoleColumns(),
})
}

return r
}

func rbacResource(misConfig Resource) bool {
return misConfig.Kind == "Role" || misConfig.Kind == "RoleBinding" || misConfig.Kind == "ClusterRole" || misConfig.Kind == "ClusterRoleBinding"
return slices.Contains([]string{"Role", "RoleBinding", "ClusterRole", "ClusterRoleBinding"}, misConfig.Kind)
}

func infraResource(misConfig Resource) bool {
return (misConfig.Kind == "Pod" && misConfig.Namespace == "kube-system") || misConfig.Kind == "NodeInfo"
return !rbacResource(misConfig) && (misConfig.Namespace == infraNamespace) || nodeInfoResource(misConfig)
}

func CreateResource(artifact *artifacts.Artifact, report types.Report, err error) Resource {
Expand All @@ -234,6 +221,10 @@ func CreateResource(artifact *artifacts.Artifact, report types.Report, err error
return r
}

func nodeInfoResource(nodeInfo Resource) bool {
return nodeInfo.Kind == "NodeInfo" || nodeInfo.Kind == "NodeComponents"
}

func createK8sResource(artifact *artifacts.Artifact, scanResults types.Results) Resource {
results := make([]types.Result, 0, len(scanResults))
// fix target name
Expand Down Expand Up @@ -269,68 +260,21 @@ func (r Report) PrintErrors() {
}
}

func splitInfraAndWorkloadResources(misconfig Resource) (Resource, Resource) {
workload := copyResource(misconfig)
infra := copyResource(misconfig)

workloadResults := make(types.Results, 0)
infraResults := make(types.Results, 0)

for _, result := range misconfig.Results {
var workloadMisconfigs, infraMisconfigs []types.DetectedMisconfiguration

for _, m := range result.Misconfigurations {
if strings.HasPrefix(m.ID, "KCV") {
infraMisconfigs = append(infraMisconfigs, m)
continue
}

workloadMisconfigs = append(workloadMisconfigs, m)
}

if len(workloadMisconfigs) > 0 {
workloadResults = append(workloadResults, copyResult(result, workloadMisconfigs))
}

if len(infraMisconfigs) > 0 {
infraResults = append(infraResults, copyResult(result, infraMisconfigs))
}
}

workload.Results = workloadResults
workload.Report.Results = workloadResults

infra.Results = infraResults
infra.Report.Results = infraResults

return workload, infra
func shouldAddToReport(scanners types.Scanners, components []string, componentType string) bool {
return scanners.AnyEnabled(
types.MisconfigScanner,
types.VulnerabilityScanner,
types.SecretScanner) &&
slices.Contains(components, componentType)
}

func copyResource(r Resource) Resource {
return Resource{
Namespace: r.Namespace,
Kind: r.Kind,
Name: r.Name,
Metadata: r.Metadata,
Error: r.Error,
Report: r.Report,
}
func vulnerabilitiesOrSecretResource(resource Resource) bool {
return len(resource.Results) > 0 && (len(resource.Results[0].Vulnerabilities) > 0 || len(resource.Results[0].Secrets) > 0)
}

func copyResult(r types.Result, misconfigs []types.DetectedMisconfiguration) types.Result {
return types.Result{
Target: r.Target,
Class: r.Class,
Type: r.Type,
MisconfSummary: r.MisconfSummary,
Misconfigurations: misconfigs,
func nodeKind(resource Resource) Resource {
if nodeInfoResource(resource) {
resource.Kind = "Node"
}
}

func shouldAddWorkloadReport(scanners types.Scanners) bool {
return scanners.AnyEnabled(types.MisconfigScanner, types.VulnerabilityScanner, types.SecretScanner)
}

func vulnerabilitiesOrSecretResource(resource Resource) bool {
return len(resource.Results) > 0 && (len(resource.Results[0].Vulnerabilities) > 0 || len(resource.Results[0].Secrets) > 0)
return resource
}
5 changes: 1 addition & 4 deletions pkg/k8s/report/report_test.go
Expand Up @@ -535,11 +535,10 @@ func Test_separateMisconfigReports(t *testing.T) {
Resources: []Resource{
{Kind: "Deployment"},
{Kind: "StatefulSet"},
{Kind: "Pod"},
},
},
{Resources: []Resource{{Kind: "Role"}}},
{Resources: []Resource{{Kind: "Pod"}}},
{Resources: []Resource{{Kind: "Role"}}},
},
},
{
Expand All @@ -556,7 +555,6 @@ func Test_separateMisconfigReports(t *testing.T) {
Resources: []Resource{
{Kind: "Deployment"},
{Kind: "StatefulSet"},
{Kind: "Pod"},
},
},
{Resources: []Resource{{Kind: "Pod"}}},
Expand All @@ -580,7 +578,6 @@ func Test_separateMisconfigReports(t *testing.T) {
Resources: []Resource{
{Kind: "Deployment"},
{Kind: "StatefulSet"},
{Kind: "Pod"},
},
},
},
Expand Down
5 changes: 2 additions & 3 deletions pkg/k8s/report/summary.go
Expand Up @@ -51,7 +51,7 @@ func ColumnHeading(scanners types.Scanners, components, availableColumns []strin
securityOptions[MisconfigurationsColumn] = nil
}
if slices.Contains(components, infraComponent) {
securityOptions[InfraAssessmentColumn] = nil
securityOptions[MisconfigurationsColumn] = nil
}
case types.SecretScanner:
securityOptions[SecretsColumn] = nil
Expand Down Expand Up @@ -107,8 +107,7 @@ func (s SummaryWriter) Write(report Report) error {
}

if slices.Contains(s.ColumnsHeading, MisconfigurationsColumn) ||
slices.Contains(s.ColumnsHeading, RbacAssessmentColumn) ||
slices.Contains(s.ColumnsHeading, InfraAssessmentColumn) {
slices.Contains(s.ColumnsHeading, RbacAssessmentColumn) {
rowParts = append(rowParts, s.generateSummary(mCount)...)
}

Expand Down
4 changes: 3 additions & 1 deletion pkg/k8s/report/summary_test.go
Expand Up @@ -62,7 +62,9 @@ func TestReport_ColumnHeading(t *testing.T) {
want: []string{
NamespaceColumn,
ResourceColumn,
InfraAssessmentColumn,
VulnerabilitiesColumn,
MisconfigurationsColumn,
SecretsColumn,
},
},
{
Expand Down
7 changes: 5 additions & 2 deletions pkg/k8s/report/table.go
Expand Up @@ -26,7 +26,6 @@ const (
MisconfigurationsColumn = "Misconfigurations"
SecretsColumn = "Secrets"
RbacAssessmentColumn = "RBAC Assessment"
InfraAssessmentColumn = "Kubernetes Infra Assessment"
)

func WorkloadColumns() []string {
Expand All @@ -42,7 +41,11 @@ func RoleColumns() []string {
}

func InfraColumns() []string {
return []string{InfraAssessmentColumn}
return []string{
VulnerabilitiesColumn,
MisconfigurationsColumn,
SecretsColumn,
}
}

func (tw TableWriter) Write(ctx context.Context, report Report) error {
Expand Down

0 comments on commit dc76c6e

Please sign in to comment.