diff --git a/go.mod b/go.mod index 2cb83ffcf8..f92b8736ee 100644 --- a/go.mod +++ b/go.mod @@ -355,7 +355,7 @@ require ( gopkg.in/ini.v1 v1.67.0 // indirect gopkg.in/neurosnap/sentences.v1 v1.0.6 // indirect gopkg.in/warnings.v0 v0.1.2 // indirect - gopkg.in/yaml.v2 v2.4.0 + gopkg.in/yaml.v2 v2.4.0 // indirect gotest.tools v2.2.0+incompatible gotest.tools/v3 v3.2.0 // indirect helm.sh/helm/v3 v3.10.0 // indirect diff --git a/pkg/compliance/report/json.go b/pkg/compliance/report/json.go index 64cdc5f706..8d58f25106 100644 --- a/pkg/compliance/report/json.go +++ b/pkg/compliance/report/json.go @@ -18,15 +18,17 @@ func (jw JSONWriter) Write(report *ComplianceReport) error { var output []byte var err error + var v interface{} switch jw.Report { case allReport: - output, err = json.MarshalIndent(report, "", " ") + v = report case summaryReport: - output, err = json.MarshalIndent(BuildSummary(report), "", " ") + v = BuildSummary(report) default: return xerrors.Errorf(`report %q not supported. Use "summary" or "all"`, jw.Report) } + output, err = json.MarshalIndent(v, "", " ") if err != nil { return xerrors.Errorf("failed to marshal json: %w", err) } diff --git a/pkg/compliance/report/json_test.go b/pkg/compliance/report/json_test.go index f4ec40cf66..c815f566d3 100644 --- a/pkg/compliance/report/json_test.go +++ b/pkg/compliance/report/json_test.go @@ -1,46 +1,82 @@ -package report +package report_test import ( "bytes" - "encoding/json" + "os" + "path/filepath" + "testing" + + "github.com/stretchr/testify/require" + + "github.com/aquasecurity/trivy/pkg/compliance/report" "github.com/aquasecurity/trivy/pkg/types" "github.com/stretchr/testify/assert" - "io" - "os" - "testing" ) -func TestJSONReport(t *testing.T) { +func TestJSONWriter_Write(t *testing.T) { + input := &report.ComplianceReport{ + ID: "1234", + Title: "NSA", + RelatedResources: []string{"https://example.com"}, + Results: []*report.ControlCheckResult{ + { + ID: "1.0", + Name: "Non-root containers", + Severity: "MEDIUM", + Results: types.Results{ + { + Misconfigurations: []types.DetectedMisconfiguration{ + {AVDID: "AVD-KSV012", Status: types.StatusFailure}, + }, + }, + }, + }, + { + ID: "1.1", + Name: "Immutable container file systems", + Severity: "LOW", + Results: types.Results{ + { + Misconfigurations: []types.DetectedMisconfiguration{ + {AVDID: "AVD-KSV013", Status: types.StatusFailure}, + }, + }, + }, + }, + }, + } + tests := []struct { - name string - specPath string - resultPath string - reportType string - wantJsonReportPath string + name string + reportType string + input *report.ComplianceReport + want string }{ - {name: "build summary json output report", specPath: "./testdata/config_spec.yaml", reportType: "summary", resultPath: "./testdata/results_config.json", wantJsonReportPath: "./testdata/json_summary.json"}, - {name: "build full json output report", specPath: "./testdata/config_spec.yaml", reportType: "all", resultPath: "./testdata/results_config.json", wantJsonReportPath: "./testdata/json_view.json"}, + { + name: "build summary json output report", + reportType: "summary", + input: input, + want: filepath.Join("testdata", "summary.json"), + }, + { + name: "build full json output report", + reportType: "all", + input: input, + want: filepath.Join("testdata", "all.json"), + }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - specfile, err := os.ReadFile(tt.specPath) - assert.NoError(t, err) - var res types.Results - resultByte, err := os.ReadFile(tt.resultPath) - err = json.Unmarshal(resultByte, &res) - assert.NoError(t, err) - complianceResults, err := BuildComplianceReport([]types.Results{res}, string(specfile)) - assert.NoError(t, err) - ioWriter := new(bytes.Buffer) - tr := JSONWriter{Report: tt.reportType, Output: ioWriter} - err = tr.Write(complianceResults) - assert.NoError(t, err) - bt, err := io.ReadAll(ioWriter) - assert.NoError(t, err) - r, err := os.ReadFile(tt.wantJsonReportPath) - assert.NoError(t, err) - assert.Equal(t, string(bt), string(r)) + buf := new(bytes.Buffer) + tr := report.JSONWriter{Report: tt.reportType, Output: buf} + err := tr.Write(tt.input) + require.NoError(t, err) + + want, err := os.ReadFile(tt.want) + require.NoError(t, err) + + assert.JSONEq(t, string(want), buf.String()) }) } } diff --git a/pkg/compliance/report/report.go b/pkg/compliance/report/report.go index 07d584ba54..24800765d9 100644 --- a/pkg/compliance/report/report.go +++ b/pkg/compliance/report/report.go @@ -4,7 +4,6 @@ import ( "io" "golang.org/x/xerrors" - "gopkg.in/yaml.v2" dbTypes "github.com/aquasecurity/trivy-db/pkg/types" "github.com/aquasecurity/trivy/pkg/compliance/spec" @@ -29,37 +28,37 @@ type Option struct { // ComplianceReport represents a kubernetes scan report type ComplianceReport struct { - ID string `json:"id"` - Title string `json:"title"` - Description string `json:"description"` - Version string `json:"severity"` - RelatedResources []string `json:"relatedResources"` - Results []*ControlCheckResult `json:"results"` + ID string + Title string + Description string + Version string + RelatedResources []string + Results []*ControlCheckResult } type ControlCheckResult struct { - ControlCheckID string `json:"id"` - ControlName string `json:"name"` - ControlDescription string `json:"description"` - DefaultStatus spec.ControlStatus `json:"defaultStatus,omitempty"` - ControlSeverity string `json:"severity"` - Results types.Results `json:"results"` + ID string + Name string + Description string + DefaultStatus spec.ControlStatus `json:",omitempty"` + Severity string + Results types.Results } -// ConsolidatedReport represents a kubernetes scan report with consolidated findings +// SummaryReport represents a kubernetes scan report with consolidated findings type SummaryReport struct { SchemaVersion int `json:",omitempty"` - ReportID string - ReportTitle string + ID string + Title string SummaryControls []ControlCheckSummary `json:",omitempty"` } type ControlCheckSummary struct { - ControlCheckID string `json:"id"` - ControlName string `json:"name"` - ControlSeverity string `json:"severity"` - TotalPass float32 `json:"totalPass"` - TotalFail float32 `json:"totalFail"` + ID string + Name string + Severity string + TotalPass float32 + TotalFail float32 } // Writer defines the result write operation @@ -99,16 +98,18 @@ func (r ComplianceReport) empty() bool { func buildControlCheckResults(checksMap map[string]types.Results, controls []spec.Control) []*ControlCheckResult { complianceResults := make([]*ControlCheckResult, 0) for _, control := range controls { - cr := ControlCheckResult{} - cr.ControlName = control.Name - cr.ControlCheckID = control.ID - cr.ControlDescription = control.Description - cr.ControlSeverity = string(control.Severity) - cr.DefaultStatus = control.DefaultStatus + var results types.Results for _, c := range control.Checks { - cr.Results = append(cr.Results, checksMap[c.ID]...) + results = append(results, checksMap[c.ID]...) } - complianceResults = append(complianceResults, &cr) + complianceResults = append(complianceResults, &ControlCheckResult{ + Name: control.Name, + ID: control.ID, + Description: control.Description, + Severity: string(control.Severity), + DefaultStatus: control.DefaultStatus, + Results: results, + }) } return complianceResults } @@ -126,20 +127,9 @@ func buildComplianceReportResults(checksMap map[string]types.Results, spec spec. } } -func BuildComplianceReport(scanResults []types.Results, complianceSpec string) (*ComplianceReport, error) { - // load compliance spec - cs := spec.ComplianceSpec{} - err := yaml.Unmarshal([]byte(complianceSpec), &cs) - if err != nil { - return nil, err - } - // validate scanners types (vuln and config) define in spec supported - err = spec.ValidateScanners(cs.Spec.Controls) - if err != nil { - return nil, err - } +func BuildComplianceReport(scanResults []types.Results, cs spec.ComplianceSpec) (*ComplianceReport, error) { // aggregate checks by ID - aggregateChecksByID := spec.AggregateAllChecksBySpecID(scanResults, cs.Spec.Controls) + aggregateChecksByID := spec.AggregateAllChecksBySpecID(scanResults, cs) // build compliance report results return buildComplianceReportResults(aggregateChecksByID, cs.Spec), nil diff --git a/pkg/compliance/report/report_test.go b/pkg/compliance/report/report_test.go index afce07432e..b1b4cc9b6a 100644 --- a/pkg/compliance/report/report_test.go +++ b/pkg/compliance/report/report_test.go @@ -1,84 +1,242 @@ -package report +package report_test import ( - "bytes" - "encoding/json" - "io" - "os" - "reflect" + "fmt" "testing" - "github.com/aquasecurity/trivy/pkg/types" "github.com/stretchr/testify/assert" + + dbTypes "github.com/aquasecurity/trivy-db/pkg/types" + "github.com/aquasecurity/trivy-db/pkg/vulnsrc/vulnerability" + "github.com/aquasecurity/trivy/pkg/compliance/report" + "github.com/aquasecurity/trivy/pkg/compliance/spec" + ftypes "github.com/aquasecurity/trivy/pkg/fanal/types" + "github.com/aquasecurity/trivy/pkg/types" ) -func TestReport(t *testing.T) { +func TestBuildComplianceReport(t *testing.T) { + type args struct { + scanResults []types.Results + cs spec.ComplianceSpec + } tests := []struct { - name string - specPath string - resultPath string - Option Option - wantSummaryReportPath string - expectError bool + name string + args args + want *report.ComplianceReport + wantErr assert.ErrorAssertionFunc }{ - {name: "build table report summary", Option: Option{Report: "summary", Format: "table"}, specPath: "./testdata/config_spec.yaml", resultPath: "./testdata/results_config.json", wantSummaryReportPath: "./testdata/table_summary.txt"}, - {name: "build table report full", Option: Option{Report: "all", Format: "table"}, specPath: "./testdata/config_spec.yaml", resultPath: "./testdata/results_config.json", wantSummaryReportPath: "./testdata/table.txt"}, - {name: "build json report summary", Option: Option{Report: "summary", Format: "json"}, specPath: "./testdata/config_spec.yaml", resultPath: "./testdata/results_config.json", wantSummaryReportPath: "./testdata/json_summary.json"}, - {name: "build json report full", Option: Option{Report: "all", Format: "json"}, specPath: "./testdata/config_spec.yaml", resultPath: "./testdata/results_config.json", wantSummaryReportPath: "./testdata/json_view.json"}, - {name: "build report bad format", Option: Option{Report: "all", Format: "aaa"}, specPath: "./testdata/config_spec.yaml", resultPath: "./testdata/results_config.json", wantSummaryReportPath: "./testdata/json_view.json", expectError: true}, + { + name: "happy", + args: args{ + scanResults: []types.Results{ + { + { + Target: "Deployment/metrics-server", + Class: types.ClassConfig, + Type: ftypes.Kubernetes, + MisconfSummary: &types.MisconfSummary{ + Successes: 1, + Failures: 0, + Exceptions: 0, + }, + Misconfigurations: []types.DetectedMisconfiguration{ + { + Type: "Kubernetes Security Check", + ID: "KSV001", + AVDID: "AVD-KSV-0001", + Title: "Process can elevate its own privileges", + Description: "A program inside the container can elevate its own privileges and run as root, which might give the program control over the container and node.", + Message: "Container 'metrics-server' of Deployment 'metrics-server' should set 'securityContext.allowPrivilegeEscalation' to false", + Namespace: "builtin.kubernetes.KSV001", + Query: "data.builtin.kubernetes.KSV001.deny", + Resolution: "Set 'set containers[].securityContext.allowPrivilegeEscalation' to 'false'.", + Severity: dbTypes.SeverityMedium.String(), + PrimaryURL: "https://avd.aquasec.com/misconfig/ksv001", + References: []string{ + "https://kubernetes.io/docs/concepts/security/pod-security-standards/#restricted", + "https://avd.aquasec.com/misconfig/ksv001", + }, + Status: types.StatusPassed, + }, + { + Type: "Kubernetes Security Check", + ID: "KSV002", + AVDID: "AVD-KSV-9999", + Status: types.StatusFailure, + }, + }, + }, + }, + { + { + Target: "rancher/metrics-server:v0.3.6 (debian 9.9)", + Class: types.ClassOSPkg, + Type: "debian", + Vulnerabilities: []types.DetectedVulnerability{ + { + VulnerabilityID: "DLA-2424-1", + VendorIDs: []string{"DLA-2424-1"}, + PkgName: "tzdata", + InstalledVersion: "2019a-0+deb9u1", + FixedVersion: "2020d-0+deb9u1", + Layer: ftypes.Layer{ + DiffID: "sha256:932da51564135c98a49a34a193d6cd363d8fa4184d957fde16c9d8527b3f3b02", + }, + DataSource: &dbTypes.DataSource{ + ID: vulnerability.Debian, + Name: "Debian Security Tracker", + URL: "https://salsa.debian.org/security-tracker-team/security-tracker", + }, + Vulnerability: dbTypes.Vulnerability{ + Title: "tzdata - new upstream version", + Severity: dbTypes.SeverityUnknown.String(), + }, + }, + }, + }, + }, + }, + cs: spec.ComplianceSpec{ + Spec: spec.Spec{ + ID: "1234", + Title: "NSA", + Description: "National Security Agency - Kubernetes Hardening Guidance", + Version: "1.0", + RelatedResources: []string{ + "https://example.com", + }, + Controls: []spec.Control{ + { + ID: "1.0", + Name: "Non-root containers", + Description: "Check that container is not running as root", + Severity: "MEDIUM", + Checks: []spec.SpecCheck{ + {ID: "AVD-KSV-0001"}, + }, + }, + { + ID: "1.1", + Name: "Immutable container file systems", + Description: "Check that container root file system is immutable", + Severity: "LOW", + Checks: []spec.SpecCheck{ + {ID: "AVD-KSV-0002"}, + }, + }, + { + ID: "1.2", + Name: "tzdata - new upstream version", + Description: "Bad tzdata package", + Severity: "CRITICAL", + Checks: []spec.SpecCheck{ + {ID: "DLA-2424-1"}, + }, + }, + }, + }, + }, + }, + want: &report.ComplianceReport{ + ID: "1234", + Title: "NSA", + Description: "National Security Agency - Kubernetes Hardening Guidance", + Version: "1.0", + RelatedResources: []string{ + "https://example.com", + }, + Results: []*report.ControlCheckResult{ + { + ID: "1.0", + Name: "Non-root containers", + Description: "Check that container is not running as root", + Severity: "MEDIUM", + Results: types.Results{ + { + Target: "Deployment/metrics-server", + Class: types.ClassConfig, + Type: ftypes.Kubernetes, + MisconfSummary: &types.MisconfSummary{ + Successes: 1, + Failures: 0, + Exceptions: 0, + }, + Misconfigurations: []types.DetectedMisconfiguration{ + { + Type: "Kubernetes Security Check", + ID: "KSV001", + AVDID: "AVD-KSV-0001", + Title: "Process can elevate its own privileges", + Description: "A program inside the container can elevate its own privileges and run as root, which might give the program control over the container and node.", + Message: "Container 'metrics-server' of Deployment 'metrics-server' should set 'securityContext.allowPrivilegeEscalation' to false", + Namespace: "builtin.kubernetes.KSV001", + Query: "data.builtin.kubernetes.KSV001.deny", + Resolution: "Set 'set containers[].securityContext.allowPrivilegeEscalation' to 'false'.", + Severity: dbTypes.SeverityMedium.String(), + PrimaryURL: "https://avd.aquasec.com/misconfig/ksv001", + References: []string{ + "https://kubernetes.io/docs/concepts/security/pod-security-standards/#restricted", + "https://avd.aquasec.com/misconfig/ksv001", + }, + Status: types.StatusPassed, + }, + }, + }, + }, + }, + { + ID: "1.1", + Name: "Immutable container file systems", + Description: "Check that container root file system is immutable", + Severity: "LOW", + Results: nil, + }, + { + ID: "1.2", + Name: "tzdata - new upstream version", + Description: "Bad tzdata package", + Severity: "CRITICAL", + Results: types.Results{ + { + Target: "rancher/metrics-server:v0.3.6 (debian 9.9)", + Class: types.ClassOSPkg, + Type: "debian", + Vulnerabilities: []types.DetectedVulnerability{ + { + VulnerabilityID: "DLA-2424-1", + VendorIDs: []string{"DLA-2424-1"}, + PkgName: "tzdata", + InstalledVersion: "2019a-0+deb9u1", + FixedVersion: "2020d-0+deb9u1", + Layer: ftypes.Layer{ + DiffID: "sha256:932da51564135c98a49a34a193d6cd363d8fa4184d957fde16c9d8527b3f3b02", + }, + DataSource: &dbTypes.DataSource{ + ID: vulnerability.Debian, + Name: "Debian Security Tracker", + URL: "https://salsa.debian.org/security-tracker-team/security-tracker", + }, + Vulnerability: dbTypes.Vulnerability{ + Title: "tzdata - new upstream version", + Severity: dbTypes.SeverityUnknown.String(), + }, + }, + }, + }, + }, + }, + }, + }, + wantErr: assert.NoError, + }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - specfile, err := os.ReadFile(tt.specPath) - assert.NoError(t, err) - var res types.Results - resultByte, err := os.ReadFile(tt.resultPath) - err = json.Unmarshal(resultByte, &res) - assert.NoError(t, err) - complianceResults, err := BuildComplianceReport([]types.Results{res}, string(specfile)) - ioWriter := new(bytes.Buffer) - tt.Option.Output = ioWriter - err = Write(complianceResults, tt.Option) - if tt.expectError { - assert.Error(t, err) - } else { - assert.NoError(t, err) - bt, err := io.ReadAll(ioWriter) - assert.NoError(t, err) - r, err := os.ReadFile(tt.wantSummaryReportPath) - assert.NoError(t, err) - assert.Equal(t, string(bt), string(r)) + got, err := report.BuildComplianceReport(tt.args.scanResults, tt.args.cs) + if !tt.wantErr(t, err, fmt.Sprintf("BuildComplianceReport(%v, %v)", tt.args.scanResults, tt.args.cs)) { + return } - }) - } -} - -func TestBuildComplianceReportResults(t *testing.T) { - tests := []struct { - name string - specPath string - resultPath string - complianceReportPath string - }{ - {name: "build report test config and vuln", specPath: "./testdata/config_vuln_spec.yaml", resultPath: "./testdata/results_vul_config.json", complianceReportPath: "./testdata/vuln_config_compliance.json"}} - - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - specFile, err := os.ReadFile(tt.specPath) - assert.NoError(t, err) - var res types.Results - c, err := os.ReadFile(tt.resultPath) - err = json.Unmarshal(c, &res) - assert.NoError(t, err) - pp, err := BuildComplianceReport([]types.Results{res}, string(specFile)) - assert.NoError(t, err) - complianceReport, err := os.ReadFile(tt.complianceReportPath) - assert.NoError(t, err) - var cp ComplianceReport - err = json.Unmarshal(complianceReport, &cp) - assert.NoError(t, err) - assert.True(t, reflect.DeepEqual(&cp, pp)) - + assert.Equalf(t, tt.want, got, "BuildComplianceReport(%v, %v)", tt.args.scanResults, tt.args.cs) }) } } diff --git a/pkg/compliance/report/summary.go b/pkg/compliance/report/summary.go index e83261036e..d53f78f9f6 100644 --- a/pkg/compliance/report/summary.go +++ b/pkg/compliance/report/summary.go @@ -11,12 +11,17 @@ import ( dbTypes "github.com/aquasecurity/trivy-db/pkg/types" "github.com/aquasecurity/trivy/pkg/compliance/spec" pkgReport "github.com/aquasecurity/trivy/pkg/report/table" + "github.com/aquasecurity/trivy/pkg/types" ) func BuildSummary(cr *ComplianceReport) *SummaryReport { - ccma := make([]ControlCheckSummary, 0) + var ccma []ControlCheckSummary for _, control := range cr.Results { - ccm := ControlCheckSummary{ControlCheckID: control.ControlCheckID, ControlName: control.ControlName, ControlSeverity: control.ControlSeverity} + ccm := ControlCheckSummary{ + ID: control.ID, + Name: control.Name, + Severity: control.Severity, + } if len(control.Results) == 0 { // this validation is mainly for vuln type if control.DefaultStatus == spec.PassStatus { ccm.TotalPass = 1 @@ -25,27 +30,23 @@ func BuildSummary(cr *ComplianceReport) *SummaryReport { continue } for _, check := range control.Results { - for _, cr := range check.Misconfigurations { - if cr.CheckPass() { - ccm.TotalPass++ - continue - } - ccm.TotalFail++ - } - for _, cr := range check.Vulnerabilities { - if cr.CheckPass() { + for _, m := range check.Misconfigurations { + if m.Status == types.StatusPassed { ccm.TotalPass++ continue } ccm.TotalFail++ } + // Detected vulnerabilities are always failure. + ccm.TotalFail += float32(len(check.Vulnerabilities)) } ccma = append(ccma, ccm) - } - return &SummaryReport{ReportID: cr.ID, - ReportTitle: cr.Title, - SummaryControls: ccma} + return &SummaryReport{ + ID: cr.ID, + Title: cr.Title, + SummaryControls: ccma, + } } type SummaryWriter struct { @@ -69,7 +70,6 @@ func NewSummaryWriter(output io.Writer, requiredSevs []dbTypes.Severity, columnH // Write writes the results in a summarized table format func (s SummaryWriter) Write(report *ComplianceReport) error { - if _, err := fmt.Fprintln(s.Output); err != nil { return xerrors.Errorf("failed to write summary report: %w", err) } @@ -102,7 +102,7 @@ func (s SummaryWriter) Write(report *ComplianceReport) error { func (s SummaryWriter) generateSummary(summaryControls ControlCheckSummary) []string { percentage := calculatePercentage(summaryControls.TotalFail, summaryControls.TotalPass) - return []string{summaryControls.ControlCheckID, summaryControls.ControlSeverity, summaryControls.ControlName, percentage} + return []string{summaryControls.ID, summaryControls.Severity, summaryControls.Name, percentage} } func calculatePercentage(totalFail float32, totalPass float32) string { diff --git a/pkg/compliance/report/summary_test.go b/pkg/compliance/report/summary_test.go index 132ac6e8d8..3d93548866 100644 --- a/pkg/compliance/report/summary_test.go +++ b/pkg/compliance/report/summary_test.go @@ -1,62 +1,158 @@ -package report +package report_test import ( - "encoding/json" - "os" - "strings" "testing" + "github.com/aquasecurity/trivy/pkg/compliance/report" "github.com/aquasecurity/trivy/pkg/types" "github.com/stretchr/testify/assert" ) func TestBuildSummary(t *testing.T) { tests := []struct { - name string - specPath string - resultPath string - wantSummaryReportPath string + name string + reportType string + input *report.ComplianceReport + want *report.SummaryReport }{ - {name: "build report summary config only", specPath: "./testdata/config_spec.yaml", resultPath: "./testdata/results_config.json", wantSummaryReportPath: "./testdata/report_summary.json"}, - {name: "build report summary config and vuln", specPath: "./testdata/config_vuln_spec.yaml", resultPath: "./testdata/results_vul_config.json", wantSummaryReportPath: "./testdata/vuln_config_summary.json"}} - - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - specfile, err := os.ReadFile(tt.specPath) - assert.NoError(t, err) - var res types.Results - c, err := os.ReadFile(tt.resultPath) - err = json.Unmarshal(c, &res) - assert.NoError(t, err) - complianceResults, err := BuildComplianceReport([]types.Results{res}, string(specfile)) - tk := BuildSummary(complianceResults) - o, err := json.Marshal(tk) - assert.NoError(t, err) - r, err := os.ReadFile(tt.wantSummaryReportPath) - assert.NoError(t, err) - assert.Equal(t, strings.TrimSpace(string(o)), string(r)) - - }) - } -} - -func TestCalculatePercentage(t *testing.T) { - tests := []struct { - name string - pass float32 - fail float32 - want string - }{ - {name: "calcuale percentage pass bigger then fail", pass: 10.0, fail: 5.0, want: "66.67%"}, - {name: "calcuale percentage pass smaller then fail", pass: 5.0, fail: 10.0, want: "33.33%"}, - {name: "calcuale percentage pass zero and fail zero", pass: 0.0, fail: 0.0, want: "0.00%"}, + { + name: "build report summary config only", + reportType: "summary", + input: &report.ComplianceReport{ + ID: "1234", + Title: "NSA", + RelatedResources: []string{"https://example.com"}, + Results: []*report.ControlCheckResult{ + { + ID: "1.0", + Name: "Non-root containers", + Severity: "MEDIUM", + Results: types.Results{ + { + Misconfigurations: []types.DetectedMisconfiguration{ + {AVDID: "AVD-KSV012", Status: types.StatusFailure}, + }, + }, + }, + }, + { + ID: "1.1", + Name: "Immutable container file systems", + Severity: "LOW", + Results: types.Results{ + { + Misconfigurations: []types.DetectedMisconfiguration{ + {AVDID: "AVD-KSV013", Status: types.StatusFailure}, + }, + }, + }, + }, + }, + }, + want: &report.SummaryReport{ + SchemaVersion: 0, + ID: "1234", + Title: "NSA", + SummaryControls: []report.ControlCheckSummary{ + { + ID: "1.0", + Name: "Non-root containers", + Severity: "MEDIUM", + TotalPass: 0, + TotalFail: 1, + }, + { + ID: "1.1", + Name: "Immutable container file systems", + Severity: "LOW", + TotalPass: 0, + TotalFail: 1, + }, + }, + }, + }, + { + name: "build full json output report", + reportType: "all", + input: &report.ComplianceReport{ + ID: "1234", + Title: "NSA", + RelatedResources: []string{"https://example.com"}, + Results: []*report.ControlCheckResult{ + { + ID: "1.0", + Name: "Non-root containers", + Severity: "MEDIUM", + Results: types.Results{ + { + Misconfigurations: []types.DetectedMisconfiguration{ + {AVDID: "AVD-KSV012", Status: types.StatusFailure}, + }, + }, + }, + }, + { + ID: "1.1", + Name: "Immutable container file systems", + Severity: "LOW", + Results: types.Results{ + { + Misconfigurations: []types.DetectedMisconfiguration{ + {AVDID: "AVD-KSV013", Status: types.StatusFailure}, + }, + }, + }, + }, + { + ID: "1.2", + Name: "tzdata - new upstream version", + Severity: "LOW", + Results: types.Results{ + { + Vulnerabilities: []types.DetectedVulnerability{ + {VulnerabilityID: "CVE-9999-0001"}, + {VulnerabilityID: "CVE-9999-0002"}, + }, + }, + }, + }, + }, + }, + want: &report.SummaryReport{ + SchemaVersion: 0, + ID: "1234", + Title: "NSA", + SummaryControls: []report.ControlCheckSummary{ + { + ID: "1.0", + Name: "Non-root containers", + Severity: "MEDIUM", + TotalPass: 0, + TotalFail: 1, + }, + { + ID: "1.1", + Name: "Immutable container file systems", + Severity: "LOW", + TotalPass: 0, + TotalFail: 1, + }, + { + ID: "1.2", + Name: "tzdata - new upstream version", + Severity: "LOW", + TotalPass: 0, + TotalFail: 2, + }, + }, + }, + }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - got := calculatePercentage(tt.fail, tt.pass) - assert.Equal(t, got, tt.want) - + got := report.BuildSummary(tt.input) + assert.Equal(t, tt.want, got) }) } } diff --git a/pkg/compliance/report/table.go b/pkg/compliance/report/table.go index 3a956ea308..17a9ed184c 100644 --- a/pkg/compliance/report/table.go +++ b/pkg/compliance/report/table.go @@ -25,7 +25,7 @@ const ( ComplianceColumn = "Compliance" ) -func (tw TableWriter) Columns() []string { +func (tw TableWriter) columns() []string { return []string{ControlIDColumn, SeverityColumn, ControlNameColumn, ComplianceColumn} } @@ -41,7 +41,7 @@ func (tw TableWriter) Write(report *ComplianceReport) error { } } case summaryReport: - writer := NewSummaryWriter(tw.Output, tw.Severities, tw.Columns()) + writer := NewSummaryWriter(tw.Output, tw.Severities, tw.columns()) return writer.Write(report) default: return xerrors.Errorf(`report %q not supported. Use "summary" or "all"`, tw.Report) diff --git a/pkg/compliance/report/table_test.go b/pkg/compliance/report/table_test.go index 57a745f7d2..335cce9f07 100644 --- a/pkg/compliance/report/table_test.go +++ b/pkg/compliance/report/table_test.go @@ -1,52 +1,75 @@ -package report +package report_test import ( "bytes" - "encoding/json" - "github.com/aquasecurity/trivy/pkg/types" - "github.com/stretchr/testify/assert" - "io" "os" + "path/filepath" "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + + "github.com/aquasecurity/trivy/pkg/compliance/report" + "github.com/aquasecurity/trivy/pkg/types" ) -func TestTableReport(t *testing.T) { +func TestTableWriter_Write(t *testing.T) { + tests := []struct { - name string - specPath string - resultPath string - reportType string - wantSummaryReportPath string + name string + reportType string + input *report.ComplianceReport + want string }{ - {name: "build table report summary config only", specPath: "./testdata/config_spec.yaml", reportType: "summary", resultPath: "./testdata/results_config.json", wantSummaryReportPath: "./testdata/table_summary.txt"}, - {name: "build table report summary config and vuln", specPath: "./testdata/config_vuln_spec.yaml", reportType: "summary", resultPath: "./testdata/results_vul_config.json", wantSummaryReportPath: "./testdata/vuln_conf_table_summary.txt"}, - {name: "build table report config only", specPath: "./testdata/config_spec.yaml", reportType: "all", resultPath: "./testdata/results_config.json", wantSummaryReportPath: "./testdata/table.txt"}, - {name: "build table report config and vuln", specPath: "./testdata/config_vuln_spec.yaml", reportType: "all", resultPath: "./testdata/results_vul_config.json", wantSummaryReportPath: "./testdata/vuln_conf_table.txt"}, + { + name: "build summary table", + reportType: "summary", + input: &report.ComplianceReport{ + ID: "1234", + Title: "NSA", + RelatedResources: []string{"https://example.com"}, + Results: []*report.ControlCheckResult{ + { + ID: "1.0", + Name: "Non-root containers", + Severity: "MEDIUM", + Results: types.Results{ + { + Misconfigurations: []types.DetectedMisconfiguration{ + {AVDID: "AVD-KSV012", Status: types.StatusFailure}, + }, + }, + }, + }, + { + ID: "1.1", + Name: "Immutable container file systems", + Severity: "LOW", + Results: types.Results{ + { + Misconfigurations: []types.DetectedMisconfiguration{ + {AVDID: "AVD-KSV013", Status: types.StatusFailure}, + }, + }, + }, + }, + }, + }, + want: filepath.Join("testdata", "table_summary.txt"), + }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - specfile, err := os.ReadFile(tt.specPath) - assert.NoError(t, err) - var res types.Results - resultByte, err := os.ReadFile(tt.resultPath) - err = json.Unmarshal(resultByte, &res) - assert.NoError(t, err) - complianceResults, err := BuildComplianceReport([]types.Results{res}, string(specfile)) - ioWriter := new(bytes.Buffer) - tr := TableWriter{Report: tt.reportType, Output: ioWriter} - err = tr.Write(complianceResults) - assert.NoError(t, err) - bt, err := io.ReadAll(ioWriter) - assert.NoError(t, err) - r, err := os.ReadFile(tt.wantSummaryReportPath) - assert.NoError(t, err) - assert.Equal(t, string(bt), string(r)) + buf := new(bytes.Buffer) + tr := report.TableWriter{Report: tt.reportType, Output: buf} + err := tr.Write(tt.input) + require.NoError(t, err) + + want, err := os.ReadFile(tt.want) + require.NoError(t, err) + + assert.Equal(t, string(want), buf.String()) }) } } - -func TestColumn(t *testing.T) { - tr := TableWriter{} - assert.Equal(t, tr.Columns(), []string{ControlIDColumn, SeverityColumn, ControlNameColumn, ComplianceColumn}) -} diff --git a/pkg/compliance/report/testdata/all.json b/pkg/compliance/report/testdata/all.json new file mode 100644 index 0000000000..459de9998d --- /dev/null +++ b/pkg/compliance/report/testdata/all.json @@ -0,0 +1,57 @@ +{ + "ID": "1234", + "Title": "NSA", + "Description": "", + "Version": "", + "RelatedResources": [ + "https://example.com" + ], + "Results": [ + { + "ID": "1.0", + "Name": "Non-root containers", + "Description": "", + "Severity": "MEDIUM", + "Results": [ + { + "Target": "", + "Misconfigurations": [ + { + "AVDID": "AVD-KSV012", + "Status": "FAIL", + "Layer": {}, + "CauseMetadata": { + "Code": { + "Lines": null + } + } + } + ] + } + ] + }, + { + "ID": "1.1", + "Name": "Immutable container file systems", + "Description": "", + "Severity": "LOW", + "Results": [ + { + "Target": "", + "Misconfigurations": [ + { + "AVDID": "AVD-KSV013", + "Status": "FAIL", + "Layer": {}, + "CauseMetadata": { + "Code": { + "Lines": null + } + } + } + ] + } + ] + } + ] +} \ No newline at end of file diff --git a/pkg/compliance/report/testdata/config_spec.yaml b/pkg/compliance/report/testdata/config_spec.yaml deleted file mode 100644 index b22cd3c225..0000000000 --- a/pkg/compliance/report/testdata/config_spec.yaml +++ /dev/null @@ -1,23 +0,0 @@ ---- -spec: - id: "1234" - title: nsa - description: National Security Agency - Kubernetes Hardening Guidance - relatedResources : - - http://related-resource/ - version: "1.0" - controls: - - name: Non-root containers - description: 'Check that container is not running as root' - id: '1.0' - checks: - - id: AVD-KSV-0001 - severity: 'MEDIUM' - - name: Immutable container file systems - description: 'Check that container root file system is immutable' - id: '1.1' - checks: - - id: AVD-KSV-0003 - severity: 'LOW' - - \ No newline at end of file diff --git a/pkg/compliance/report/testdata/config_vuln_spec.yaml b/pkg/compliance/report/testdata/config_vuln_spec.yaml deleted file mode 100644 index 65677de07a..0000000000 --- a/pkg/compliance/report/testdata/config_vuln_spec.yaml +++ /dev/null @@ -1,29 +0,0 @@ ---- -spec: - id: "1234" - title: nsa - description: National Security Agency - Kubernetes Hardening Guidance - relatedResources : - - http://related-resource/ - version: "1.0" - controls: - - name: Non-root containers - description: 'Check that container is not running as root' - id: '1.0' - checks: - - id: AVD-KSV-0001 - severity: 'MEDIUM' - - name: Immutable container file systems - description: 'Check that container root file system is immutable' - id: '1.1' - checks: - - id: AVD-KSV-0003 - severity: 'LOW' - - name: tzdata - new upstream version - description: 'Bad tzdata package' - id: '1.2' - checks: - - id: DLA-2424-1 - severity: 'CRITICAL' - - \ No newline at end of file diff --git a/pkg/compliance/report/testdata/json_summary.json b/pkg/compliance/report/testdata/json_summary.json deleted file mode 100644 index c5b03c45db..0000000000 --- a/pkg/compliance/report/testdata/json_summary.json +++ /dev/null @@ -1,20 +0,0 @@ -{ - "ReportID": "1234", - "ReportTitle": "nsa", - "SummaryControls": [ - { - "id": "1.0", - "name": "Non-root containers", - "severity": "MEDIUM", - "totalPass": 0, - "totalFail": 1 - }, - { - "id": "1.1", - "name": "Immutable container file systems", - "severity": "LOW", - "totalPass": 0, - "totalFail": 1 - } - ] -} diff --git a/pkg/compliance/report/testdata/json_view.json b/pkg/compliance/report/testdata/json_view.json deleted file mode 100644 index dc5359f0a8..0000000000 --- a/pkg/compliance/report/testdata/json_view.json +++ /dev/null @@ -1,271 +0,0 @@ -{ - "id": "1234", - "title": "nsa", - "description": "National Security Agency - Kubernetes Hardening Guidance", - "severity": "1.0", - "relatedResources": [ - "http://related-resource/" - ], - "results": [ - { - "id": "1.0", - "name": "Non-root containers", - "description": "Check that container is not running as root", - "severity": "MEDIUM", - "results": [ - { - "Target": "Deployment/metrics-server", - "Class": "config", - "Type": "kubernetes", - "MisconfSummary": { - "Successes": 1, - "Failures": 0, - "Exceptions": 0 - }, - "Misconfigurations": [ - { - "Type": "Kubernetes Security Check", - "ID": "KSV001", - "AVDID": "AVD-KSV-0001", - "Title": "Process can elevate its own privileges", - "Description": "A program inside the container can elevate its own privileges and run as root, which might give the program control over the container and node.", - "Message": "Container 'metrics-server' of Deployment 'metrics-server' should set 'securityContext.allowPrivilegeEscalation' to false", - "Namespace": "builtin.kubernetes.KSV001", - "Query": "data.builtin.kubernetes.KSV001.deny", - "Resolution": "Set 'set containers[].securityContext.allowPrivilegeEscalation' to 'false'.", - "Severity": "MEDIUM", - "PrimaryURL": "https://avd.aquasec.com/misconfig/ksv001", - "References": [ - "https://kubernetes.io/docs/concepts/security/pod-security-standards/#restricted", - "https://avd.aquasec.com/misconfig/ksv001" - ], - "Status": "FAIL", - "Layer": {}, - "CauseMetadata": { - "Provider": "Kubernetes", - "Service": "general", - "StartLine": 132, - "EndLine": 140, - "Code": { - "Lines": [ - { - "Number": 132, - "Content": " - image: rancher/metrics-server:v0.3.6", - "IsCause": true, - "Annotation": "", - "Truncated": false, - "FirstCause": true, - "LastCause": false - }, - { - "Number": 133, - "Content": " imagePullPolicy: IfNotPresent", - "IsCause": true, - "Annotation": "", - "Truncated": false, - "FirstCause": false, - "LastCause": false - }, - { - "Number": 134, - "Content": " name: metrics-server", - "IsCause": true, - "Annotation": "", - "Truncated": false, - "FirstCause": false, - "LastCause": false - }, - { - "Number": 135, - "Content": " resources: {}", - "IsCause": true, - "Annotation": "", - "Truncated": false, - "FirstCause": false, - "LastCause": false - }, - { - "Number": 136, - "Content": " terminationMessagePath: /dev/termination-log", - "IsCause": true, - "Annotation": "", - "Truncated": false, - "FirstCause": false, - "LastCause": false - }, - { - "Number": 137, - "Content": " terminationMessagePolicy: File", - "IsCause": true, - "Annotation": "", - "Truncated": false, - "FirstCause": false, - "LastCause": false - }, - { - "Number": 138, - "Content": " volumeMounts:", - "IsCause": true, - "Annotation": "", - "Truncated": false, - "FirstCause": false, - "LastCause": false - }, - { - "Number": 139, - "Content": " - mountPath: /tmp", - "IsCause": true, - "Annotation": "", - "Truncated": false, - "FirstCause": false, - "LastCause": false - }, - { - "Number": 140, - "Content": " name: tmp-dir", - "IsCause": true, - "Annotation": "", - "Truncated": false, - "FirstCause": false, - "LastCause": true - } - ] - } - } - } - ] - } - ] - }, - { - "id": "1.1", - "name": "Immutable container file systems", - "description": "Check that container root file system is immutable", - "severity": "LOW", - "results": [ - { - "Target": "Deployment/metrics-server", - "Class": "config", - "Type": "kubernetes", - "MisconfSummary": { - "Successes": 1, - "Failures": 0, - "Exceptions": 0 - }, - "Misconfigurations": [ - { - "Type": "Kubernetes Security Check", - "ID": "KSV003", - "AVDID": "AVD-KSV-0003", - "Title": "Default capabilities not dropped", - "Description": "The container should drop all default capabilities and add only those that are needed for its execution.", - "Message": "Container 'metrics-server' of Deployment 'metrics-server' should add 'ALL' to 'securityContext.capabilities.drop'", - "Namespace": "builtin.kubernetes.KSV003", - "Query": "data.builtin.kubernetes.KSV003.deny", - "Resolution": "Add 'ALL' to containers[].securityContext.capabilities.drop.", - "Severity": "LOW", - "PrimaryURL": "https://avd.aquasec.com/misconfig/ksv003", - "References": [ - "https://kubesec.io/basics/containers-securitycontext-capabilities-drop-index-all/", - "https://avd.aquasec.com/misconfig/ksv003" - ], - "Status": "FAIL", - "Layer": {}, - "CauseMetadata": { - "Provider": "Kubernetes", - "Service": "general", - "StartLine": 132, - "EndLine": 140, - "Code": { - "Lines": [ - { - "Number": 132, - "Content": " - image: rancher/metrics-server:v0.3.6", - "IsCause": true, - "Annotation": "", - "Truncated": false, - "FirstCause": true, - "LastCause": false - }, - { - "Number": 133, - "Content": " imagePullPolicy: IfNotPresent", - "IsCause": true, - "Annotation": "", - "Truncated": false, - "FirstCause": false, - "LastCause": false - }, - { - "Number": 134, - "Content": " name: metrics-server", - "IsCause": true, - "Annotation": "", - "Truncated": false, - "FirstCause": false, - "LastCause": false - }, - { - "Number": 135, - "Content": " resources: {}", - "IsCause": true, - "Annotation": "", - "Truncated": false, - "FirstCause": false, - "LastCause": false - }, - { - "Number": 136, - "Content": " terminationMessagePath: /dev/termination-log", - "IsCause": true, - "Annotation": "", - "Truncated": false, - "FirstCause": false, - "LastCause": false - }, - { - "Number": 137, - "Content": " terminationMessagePolicy: File", - "IsCause": true, - "Annotation": "", - "Truncated": false, - "FirstCause": false, - "LastCause": false - }, - { - "Number": 138, - "Content": " volumeMounts:", - "IsCause": true, - "Annotation": "", - "Truncated": false, - "FirstCause": false, - "LastCause": false - }, - { - "Number": 139, - "Content": " - mountPath: /tmp", - "IsCause": true, - "Annotation": "", - "Truncated": false, - "FirstCause": false, - "LastCause": false - }, - { - "Number": 140, - "Content": " name: tmp-dir", - "IsCause": true, - "Annotation": "", - "Truncated": false, - "FirstCause": false, - "LastCause": true - } - ] - } - } - } - ] - } - ] - } - ] -} diff --git a/pkg/compliance/report/testdata/report_summary.json b/pkg/compliance/report/testdata/report_summary.json deleted file mode 100644 index 37f2a0bab2..0000000000 --- a/pkg/compliance/report/testdata/report_summary.json +++ /dev/null @@ -1 +0,0 @@ -{"ReportID":"1234","ReportTitle":"nsa","SummaryControls":[{"id":"1.0","name":"Non-root containers","severity":"MEDIUM","totalPass":0,"totalFail":1},{"id":"1.1","name":"Immutable container file systems","severity":"LOW","totalPass":0,"totalFail":1}]} \ No newline at end of file diff --git a/pkg/compliance/report/testdata/results_config.json b/pkg/compliance/report/testdata/results_config.json deleted file mode 100644 index cf1b4a490b..0000000000 --- a/pkg/compliance/report/testdata/results_config.json +++ /dev/null @@ -1 +0,0 @@ -[{"Target":"Deployment/metrics-server","Class":"config","Type":"kubernetes","MisconfSummary":{"Successes":66,"Failures":13,"Exceptions":0},"Misconfigurations":[{"Type":"Kubernetes Security Check","ID":"KSV001","AVDID":"AVD-KSV-0001","Title":"Process can elevate its own privileges","Description":"A program inside the container can elevate its own privileges and run as root, which might give the program control over the container and node.","Message":"Container 'metrics-server' of Deployment 'metrics-server' should set 'securityContext.allowPrivilegeEscalation' to false","Namespace":"builtin.kubernetes.KSV001","Query":"data.builtin.kubernetes.KSV001.deny","Resolution":"Set 'set containers[].securityContext.allowPrivilegeEscalation' to 'false'.","Severity":"MEDIUM","PrimaryURL":"https://avd.aquasec.com/misconfig/ksv001","References":["https://kubernetes.io/docs/concepts/security/pod-security-standards/#restricted","https://avd.aquasec.com/misconfig/ksv001"],"Status":"FAIL","Layer":{},"CauseMetadata":{"Provider":"Kubernetes","Service":"general","StartLine":132,"EndLine":140,"Code":{"Lines":[{"Number":132,"Content":" - image: rancher/metrics-server:v0.3.6","IsCause":true,"Annotation":"","Truncated":false,"FirstCause":true,"LastCause":false},{"Number":133,"Content":" imagePullPolicy: IfNotPresent","IsCause":true,"Annotation":"","Truncated":false,"FirstCause":false,"LastCause":false},{"Number":134,"Content":" name: metrics-server","IsCause":true,"Annotation":"","Truncated":false,"FirstCause":false,"LastCause":false},{"Number":135,"Content":" resources: {}","IsCause":true,"Annotation":"","Truncated":false,"FirstCause":false,"LastCause":false},{"Number":136,"Content":" terminationMessagePath: /dev/termination-log","IsCause":true,"Annotation":"","Truncated":false,"FirstCause":false,"LastCause":false},{"Number":137,"Content":" terminationMessagePolicy: File","IsCause":true,"Annotation":"","Truncated":false,"FirstCause":false,"LastCause":false},{"Number":138,"Content":" volumeMounts:","IsCause":true,"Annotation":"","Truncated":false,"FirstCause":false,"LastCause":false},{"Number":139,"Content":" - mountPath: /tmp","IsCause":true,"Annotation":"","Truncated":false,"FirstCause":false,"LastCause":false},{"Number":140,"Content":" name: tmp-dir","IsCause":true,"Annotation":"","Truncated":false,"FirstCause":false,"LastCause":true}]}}},{"Type":"Kubernetes Security Check","ID":"KSV003","AVDID":"AVD-KSV-0003","Title":"Default capabilities not dropped","Description":"The container should drop all default capabilities and add only those that are needed for its execution.","Message":"Container 'metrics-server' of Deployment 'metrics-server' should add 'ALL' to 'securityContext.capabilities.drop'","Namespace":"builtin.kubernetes.KSV003","Query":"data.builtin.kubernetes.KSV003.deny","Resolution":"Add 'ALL' to containers[].securityContext.capabilities.drop.","Severity":"LOW","PrimaryURL":"https://avd.aquasec.com/misconfig/ksv003","References":["https://kubesec.io/basics/containers-securitycontext-capabilities-drop-index-all/","https://avd.aquasec.com/misconfig/ksv003"],"Status":"FAIL","Layer":{},"CauseMetadata":{"Provider":"Kubernetes","Service":"general","StartLine":132,"EndLine":140,"Code":{"Lines":[{"Number":132,"Content":" - image: rancher/metrics-server:v0.3.6","IsCause":true,"Annotation":"","Truncated":false,"FirstCause":true,"LastCause":false},{"Number":133,"Content":" imagePullPolicy: IfNotPresent","IsCause":true,"Annotation":"","Truncated":false,"FirstCause":false,"LastCause":false},{"Number":134,"Content":" name: metrics-server","IsCause":true,"Annotation":"","Truncated":false,"FirstCause":false,"LastCause":false},{"Number":135,"Content":" resources: {}","IsCause":true,"Annotation":"","Truncated":false,"FirstCause":false,"LastCause":false},{"Number":136,"Content":" terminationMessagePath: /dev/termination-log","IsCause":true,"Annotation":"","Truncated":false,"FirstCause":false,"LastCause":false},{"Number":137,"Content":" terminationMessagePolicy: File","IsCause":true,"Annotation":"","Truncated":false,"FirstCause":false,"LastCause":false},{"Number":138,"Content":" volumeMounts:","IsCause":true,"Annotation":"","Truncated":false,"FirstCause":false,"LastCause":false},{"Number":139,"Content":" - mountPath: /tmp","IsCause":true,"Annotation":"","Truncated":false,"FirstCause":false,"LastCause":false},{"Number":140,"Content":" name: tmp-dir","IsCause":true,"Annotation":"","Truncated":false,"FirstCause":false,"LastCause":true}]}}},{"Type":"Kubernetes Security Check","ID":"KSV011","AVDID":"AVD-KSV-0011","Title":"CPU not limited","Description":"Enforcing CPU limits prevents DoS via resource exhaustion.","Message":"Container 'metrics-server' of Deployment 'metrics-server' should set 'resources.limits.cpu'","Namespace":"builtin.kubernetes.KSV011","Query":"data.builtin.kubernetes.KSV011.deny","Resolution":"Set a limit value under 'containers[].resources.limits.cpu'.","Severity":"LOW","PrimaryURL":"https://avd.aquasec.com/misconfig/ksv011","References":["https://cloud.google.com/blog/products/containers-kubernetes/kubernetes-best-practices-resource-requests-and-limits","https://avd.aquasec.com/misconfig/ksv011"],"Status":"FAIL","Layer":{},"CauseMetadata":{"Provider":"Kubernetes","Service":"general","StartLine":132,"EndLine":140,"Code":{"Lines":[{"Number":132,"Content":" - image: rancher/metrics-server:v0.3.6","IsCause":true,"Annotation":"","Truncated":false,"FirstCause":true,"LastCause":false},{"Number":133,"Content":" imagePullPolicy: IfNotPresent","IsCause":true,"Annotation":"","Truncated":false,"FirstCause":false,"LastCause":false},{"Number":134,"Content":" name: metrics-server","IsCause":true,"Annotation":"","Truncated":false,"FirstCause":false,"LastCause":false},{"Number":135,"Content":" resources: {}","IsCause":true,"Annotation":"","Truncated":false,"FirstCause":false,"LastCause":false},{"Number":136,"Content":" terminationMessagePath: /dev/termination-log","IsCause":true,"Annotation":"","Truncated":false,"FirstCause":false,"LastCause":false},{"Number":137,"Content":" terminationMessagePolicy: File","IsCause":true,"Annotation":"","Truncated":false,"FirstCause":false,"LastCause":false},{"Number":138,"Content":" volumeMounts:","IsCause":true,"Annotation":"","Truncated":false,"FirstCause":false,"LastCause":false},{"Number":139,"Content":" - mountPath: /tmp","IsCause":true,"Annotation":"","Truncated":false,"FirstCause":false,"LastCause":false},{"Number":140,"Content":" name: tmp-dir","IsCause":true,"Annotation":"","Truncated":false,"FirstCause":false,"LastCause":true}]}}},{"Type":"Kubernetes Security Check","ID":"KSV012","AVDID":"AVD-KSV-0012","Title":"Runs as root user","Description":"'runAsNonRoot' forces the running image to run as a non-root user to ensure least privileges.","Message":"Container 'metrics-server' of Deployment 'metrics-server' should set 'securityContext.runAsNonRoot' to true","Namespace":"builtin.kubernetes.KSV012","Query":"data.builtin.kubernetes.KSV012.deny","Resolution":"Set 'containers[].securityContext.runAsNonRoot' to true.","Severity":"MEDIUM","PrimaryURL":"https://avd.aquasec.com/misconfig/ksv012","References":["https://kubernetes.io/docs/concepts/security/pod-security-standards/#restricted","https://avd.aquasec.com/misconfig/ksv012"],"Status":"FAIL","Layer":{},"CauseMetadata":{"Provider":"Kubernetes","Service":"general","StartLine":132,"EndLine":140,"Code":{"Lines":[{"Number":132,"Content":" - image: rancher/metrics-server:v0.3.6","IsCause":true,"Annotation":"","Truncated":false,"FirstCause":true,"LastCause":false},{"Number":133,"Content":" imagePullPolicy: IfNotPresent","IsCause":true,"Annotation":"","Truncated":false,"FirstCause":false,"LastCause":false},{"Number":134,"Content":" name: metrics-server","IsCause":true,"Annotation":"","Truncated":false,"FirstCause":false,"LastCause":false},{"Number":135,"Content":" resources: {}","IsCause":true,"Annotation":"","Truncated":false,"FirstCause":false,"LastCause":false},{"Number":136,"Content":" terminationMessagePath: /dev/termination-log","IsCause":true,"Annotation":"","Truncated":false,"FirstCause":false,"LastCause":false},{"Number":137,"Content":" terminationMessagePolicy: File","IsCause":true,"Annotation":"","Truncated":false,"FirstCause":false,"LastCause":false},{"Number":138,"Content":" volumeMounts:","IsCause":true,"Annotation":"","Truncated":false,"FirstCause":false,"LastCause":false},{"Number":139,"Content":" - mountPath: /tmp","IsCause":true,"Annotation":"","Truncated":false,"FirstCause":false,"LastCause":false},{"Number":140,"Content":" name: tmp-dir","IsCause":true,"Annotation":"","Truncated":false,"FirstCause":false,"LastCause":true}]}}},{"Type":"Kubernetes Security Check","ID":"KSV014","AVDID":"AVD-KSV-0014","Title":"Root file system is not read-only","Description":"An immutable root file system prevents applications from writing to their local disk. This can limit intrusions, as attackers will not be able to tamper with the file system or write foreign executables to disk.","Message":"Container 'metrics-server' of Deployment 'metrics-server' should set 'securityContext.readOnlyRootFilesystem' to true","Namespace":"builtin.kubernetes.KSV014","Query":"data.builtin.kubernetes.KSV014.deny","Resolution":"Change 'containers[].securityContext.readOnlyRootFilesystem' to 'true'.","Severity":"LOW","PrimaryURL":"https://avd.aquasec.com/misconfig/ksv014","References":["https://kubesec.io/basics/containers-securitycontext-readonlyrootfilesystem-true/","https://avd.aquasec.com/misconfig/ksv014"],"Status":"FAIL","Layer":{},"CauseMetadata":{"Provider":"Kubernetes","Service":"general","StartLine":132,"EndLine":140,"Code":{"Lines":[{"Number":132,"Content":" - image: rancher/metrics-server:v0.3.6","IsCause":true,"Annotation":"","Truncated":false,"FirstCause":true,"LastCause":false},{"Number":133,"Content":" imagePullPolicy: IfNotPresent","IsCause":true,"Annotation":"","Truncated":false,"FirstCause":false,"LastCause":false},{"Number":134,"Content":" name: metrics-server","IsCause":true,"Annotation":"","Truncated":false,"FirstCause":false,"LastCause":false},{"Number":135,"Content":" resources: {}","IsCause":true,"Annotation":"","Truncated":false,"FirstCause":false,"LastCause":false},{"Number":136,"Content":" terminationMessagePath: /dev/termination-log","IsCause":true,"Annotation":"","Truncated":false,"FirstCause":false,"LastCause":false},{"Number":137,"Content":" terminationMessagePolicy: File","IsCause":true,"Annotation":"","Truncated":false,"FirstCause":false,"LastCause":false},{"Number":138,"Content":" volumeMounts:","IsCause":true,"Annotation":"","Truncated":false,"FirstCause":false,"LastCause":false},{"Number":139,"Content":" - mountPath: /tmp","IsCause":true,"Annotation":"","Truncated":false,"FirstCause":false,"LastCause":false},{"Number":140,"Content":" name: tmp-dir","IsCause":true,"Annotation":"","Truncated":false,"FirstCause":false,"LastCause":true}]}}},{"Type":"Kubernetes Security Check","ID":"KSV015","AVDID":"AVD-KSV-0015","Title":"CPU requests not specified","Description":"When containers have resource requests specified, the scheduler can make better decisions about which nodes to place pods on, and how to deal with resource contention.","Message":"Container 'metrics-server' of Deployment 'metrics-server' should set 'resources.requests.cpu'","Namespace":"builtin.kubernetes.KSV015","Query":"data.builtin.kubernetes.KSV015.deny","Resolution":"Set 'containers[].resources.requests.cpu'.","Severity":"LOW","PrimaryURL":"https://avd.aquasec.com/misconfig/ksv015","References":["https://cloud.google.com/blog/products/containers-kubernetes/kubernetes-best-practices-resource-requests-and-limits","https://avd.aquasec.com/misconfig/ksv015"],"Status":"FAIL","Layer":{},"CauseMetadata":{"Provider":"Kubernetes","Service":"general","StartLine":132,"EndLine":140,"Code":{"Lines":[{"Number":132,"Content":" - image: rancher/metrics-server:v0.3.6","IsCause":true,"Annotation":"","Truncated":false,"FirstCause":true,"LastCause":false},{"Number":133,"Content":" imagePullPolicy: IfNotPresent","IsCause":true,"Annotation":"","Truncated":false,"FirstCause":false,"LastCause":false},{"Number":134,"Content":" name: metrics-server","IsCause":true,"Annotation":"","Truncated":false,"FirstCause":false,"LastCause":false},{"Number":135,"Content":" resources: {}","IsCause":true,"Annotation":"","Truncated":false,"FirstCause":false,"LastCause":false},{"Number":136,"Content":" terminationMessagePath: /dev/termination-log","IsCause":true,"Annotation":"","Truncated":false,"FirstCause":false,"LastCause":false},{"Number":137,"Content":" terminationMessagePolicy: File","IsCause":true,"Annotation":"","Truncated":false,"FirstCause":false,"LastCause":false},{"Number":138,"Content":" volumeMounts:","IsCause":true,"Annotation":"","Truncated":false,"FirstCause":false,"LastCause":false},{"Number":139,"Content":" - mountPath: /tmp","IsCause":true,"Annotation":"","Truncated":false,"FirstCause":false,"LastCause":false},{"Number":140,"Content":" name: tmp-dir","IsCause":true,"Annotation":"","Truncated":false,"FirstCause":false,"LastCause":true}]}}},{"Type":"Kubernetes Security Check","ID":"KSV016","AVDID":"AVD-KSV-0016","Title":"Memory requests not specified","Description":"When containers have memory requests specified, the scheduler can make better decisions about which nodes to place pods on, and how to deal with resource contention.","Message":"Container 'metrics-server' of Deployment 'metrics-server' should set 'resources.requests.memory'","Namespace":"builtin.kubernetes.KSV016","Query":"data.builtin.kubernetes.KSV016.deny","Resolution":"Set 'containers[].resources.requests.memory'.","Severity":"LOW","PrimaryURL":"https://avd.aquasec.com/misconfig/ksv016","References":["https://kubesec.io/basics/containers-resources-limits-memory/","https://avd.aquasec.com/misconfig/ksv016"],"Status":"FAIL","Layer":{},"CauseMetadata":{"Provider":"Kubernetes","Service":"general","StartLine":132,"EndLine":140,"Code":{"Lines":[{"Number":132,"Content":" - image: rancher/metrics-server:v0.3.6","IsCause":true,"Annotation":"","Truncated":false,"FirstCause":true,"LastCause":false},{"Number":133,"Content":" imagePullPolicy: IfNotPresent","IsCause":true,"Annotation":"","Truncated":false,"FirstCause":false,"LastCause":false},{"Number":134,"Content":" name: metrics-server","IsCause":true,"Annotation":"","Truncated":false,"FirstCause":false,"LastCause":false},{"Number":135,"Content":" resources: {}","IsCause":true,"Annotation":"","Truncated":false,"FirstCause":false,"LastCause":false},{"Number":136,"Content":" terminationMessagePath: /dev/termination-log","IsCause":true,"Annotation":"","Truncated":false,"FirstCause":false,"LastCause":false},{"Number":137,"Content":" terminationMessagePolicy: File","IsCause":true,"Annotation":"","Truncated":false,"FirstCause":false,"LastCause":false},{"Number":138,"Content":" volumeMounts:","IsCause":true,"Annotation":"","Truncated":false,"FirstCause":false,"LastCause":false},{"Number":139,"Content":" - mountPath: /tmp","IsCause":true,"Annotation":"","Truncated":false,"FirstCause":false,"LastCause":false},{"Number":140,"Content":" name: tmp-dir","IsCause":true,"Annotation":"","Truncated":false,"FirstCause":false,"LastCause":true}]}}},{"Type":"Kubernetes Security Check","ID":"KSV018","AVDID":"AVD-KSV-0018","Title":"Memory not limited","Description":"Enforcing memory limits prevents DoS via resource exhaustion.","Message":"Container 'metrics-server' of Deployment 'metrics-server' should set 'resources.limits.memory'","Namespace":"builtin.kubernetes.KSV018","Query":"data.builtin.kubernetes.KSV018.deny","Resolution":"Set a limit value under 'containers[].resources.limits.memory'.","Severity":"LOW","PrimaryURL":"https://avd.aquasec.com/misconfig/ksv018","References":["https://kubesec.io/basics/containers-resources-limits-memory/","https://avd.aquasec.com/misconfig/ksv018"],"Status":"FAIL","Layer":{},"CauseMetadata":{"Provider":"Kubernetes","Service":"general","StartLine":132,"EndLine":140,"Code":{"Lines":[{"Number":132,"Content":" - image: rancher/metrics-server:v0.3.6","IsCause":true,"Annotation":"","Truncated":false,"FirstCause":true,"LastCause":false},{"Number":133,"Content":" imagePullPolicy: IfNotPresent","IsCause":true,"Annotation":"","Truncated":false,"FirstCause":false,"LastCause":false},{"Number":134,"Content":" name: metrics-server","IsCause":true,"Annotation":"","Truncated":false,"FirstCause":false,"LastCause":false},{"Number":135,"Content":" resources: {}","IsCause":true,"Annotation":"","Truncated":false,"FirstCause":false,"LastCause":false},{"Number":136,"Content":" terminationMessagePath: /dev/termination-log","IsCause":true,"Annotation":"","Truncated":false,"FirstCause":false,"LastCause":false},{"Number":137,"Content":" terminationMessagePolicy: File","IsCause":true,"Annotation":"","Truncated":false,"FirstCause":false,"LastCause":false},{"Number":138,"Content":" volumeMounts:","IsCause":true,"Annotation":"","Truncated":false,"FirstCause":false,"LastCause":false},{"Number":139,"Content":" - mountPath: /tmp","IsCause":true,"Annotation":"","Truncated":false,"FirstCause":false,"LastCause":false},{"Number":140,"Content":" name: tmp-dir","IsCause":true,"Annotation":"","Truncated":false,"FirstCause":false,"LastCause":true}]}}},{"Type":"Kubernetes Security Check","ID":"KSV020","AVDID":"AVD-KSV-0020","Title":"Runs with low user ID","Description":"Force the container to run with user ID \u003e 10000 to avoid conflicts with the host’s user table.","Message":"Container 'metrics-server' of Deployment 'metrics-server' should set 'securityContext.runAsUser' \u003e 10000","Namespace":"builtin.kubernetes.KSV020","Query":"data.builtin.kubernetes.KSV020.deny","Resolution":"Set 'containers[].securityContext.runAsUser' to an integer \u003e 10000.","Severity":"LOW","PrimaryURL":"https://avd.aquasec.com/misconfig/ksv020","References":["https://kubesec.io/basics/containers-securitycontext-runasuser/","https://avd.aquasec.com/misconfig/ksv020"],"Status":"FAIL","Layer":{},"CauseMetadata":{"Provider":"Kubernetes","Service":"general","StartLine":132,"EndLine":140,"Code":{"Lines":[{"Number":132,"Content":" - image: rancher/metrics-server:v0.3.6","IsCause":true,"Annotation":"","Truncated":false,"FirstCause":true,"LastCause":false},{"Number":133,"Content":" imagePullPolicy: IfNotPresent","IsCause":true,"Annotation":"","Truncated":false,"FirstCause":false,"LastCause":false},{"Number":134,"Content":" name: metrics-server","IsCause":true,"Annotation":"","Truncated":false,"FirstCause":false,"LastCause":false},{"Number":135,"Content":" resources: {}","IsCause":true,"Annotation":"","Truncated":false,"FirstCause":false,"LastCause":false},{"Number":136,"Content":" terminationMessagePath: /dev/termination-log","IsCause":true,"Annotation":"","Truncated":false,"FirstCause":false,"LastCause":false},{"Number":137,"Content":" terminationMessagePolicy: File","IsCause":true,"Annotation":"","Truncated":false,"FirstCause":false,"LastCause":false},{"Number":138,"Content":" volumeMounts:","IsCause":true,"Annotation":"","Truncated":false,"FirstCause":false,"LastCause":false},{"Number":139,"Content":" - mountPath: /tmp","IsCause":true,"Annotation":"","Truncated":false,"FirstCause":false,"LastCause":false},{"Number":140,"Content":" name: tmp-dir","IsCause":true,"Annotation":"","Truncated":false,"FirstCause":false,"LastCause":true}]}}},{"Type":"Kubernetes Security Check","ID":"KSV021","AVDID":"AVD-KSV-0021","Title":"Runs with low group ID","Description":"Force the container to run with group ID \u003e 10000 to avoid conflicts with the host’s user table.","Message":"Container 'metrics-server' of Deployment 'metrics-server' should set 'securityContext.runAsGroup' \u003e 10000","Namespace":"builtin.kubernetes.KSV021","Query":"data.builtin.kubernetes.KSV021.deny","Resolution":"Set 'containers[].securityContext.runAsGroup' to an integer \u003e 10000.","Severity":"LOW","PrimaryURL":"https://avd.aquasec.com/misconfig/ksv021","References":["https://kubesec.io/basics/containers-securitycontext-runasuser/","https://avd.aquasec.com/misconfig/ksv021"],"Status":"FAIL","Layer":{},"CauseMetadata":{"Provider":"Kubernetes","Service":"general","StartLine":132,"EndLine":140,"Code":{"Lines":[{"Number":132,"Content":" - image: rancher/metrics-server:v0.3.6","IsCause":true,"Annotation":"","Truncated":false,"FirstCause":true,"LastCause":false},{"Number":133,"Content":" imagePullPolicy: IfNotPresent","IsCause":true,"Annotation":"","Truncated":false,"FirstCause":false,"LastCause":false},{"Number":134,"Content":" name: metrics-server","IsCause":true,"Annotation":"","Truncated":false,"FirstCause":false,"LastCause":false},{"Number":135,"Content":" resources: {}","IsCause":true,"Annotation":"","Truncated":false,"FirstCause":false,"LastCause":false},{"Number":136,"Content":" terminationMessagePath: /dev/termination-log","IsCause":true,"Annotation":"","Truncated":false,"FirstCause":false,"LastCause":false},{"Number":137,"Content":" terminationMessagePolicy: File","IsCause":true,"Annotation":"","Truncated":false,"FirstCause":false,"LastCause":false},{"Number":138,"Content":" volumeMounts:","IsCause":true,"Annotation":"","Truncated":false,"FirstCause":false,"LastCause":false},{"Number":139,"Content":" - mountPath: /tmp","IsCause":true,"Annotation":"","Truncated":false,"FirstCause":false,"LastCause":false},{"Number":140,"Content":" name: tmp-dir","IsCause":true,"Annotation":"","Truncated":false,"FirstCause":false,"LastCause":true}]}}},{"Type":"Kubernetes Security Check","ID":"KSV030","AVDID":"AVD-KSV-0030","Title":"Default Seccomp profile not set","Description":"The RuntimeDefault/Localhost seccomp profile must be required, or allow specific additional profiles.","Message":"Either Pod or Container should set 'securityContext.seccompProfile.type' to 'RuntimeDefault'","Namespace":"builtin.kubernetes.KSV030","Query":"data.builtin.kubernetes.KSV030.deny","Resolution":"Set 'spec.securityContext.seccompProfile.type', 'spec.containers[*].securityContext.seccompProfile' and 'spec.initContainers[*].securityContext.seccompProfile' to 'RuntimeDefault' or undefined.","Severity":"LOW","PrimaryURL":"https://avd.aquasec.com/misconfig/ksv030","References":["https://kubernetes.io/docs/concepts/security/pod-security-standards/#restricted","https://avd.aquasec.com/misconfig/ksv030"],"Status":"FAIL","Layer":{},"CauseMetadata":{"Provider":"Kubernetes","Service":"general","StartLine":132,"EndLine":140,"Code":{"Lines":[{"Number":132,"Content":" - image: rancher/metrics-server:v0.3.6","IsCause":true,"Annotation":"","Truncated":false,"FirstCause":true,"LastCause":false},{"Number":133,"Content":" imagePullPolicy: IfNotPresent","IsCause":true,"Annotation":"","Truncated":false,"FirstCause":false,"LastCause":false},{"Number":134,"Content":" name: metrics-server","IsCause":true,"Annotation":"","Truncated":false,"FirstCause":false,"LastCause":false},{"Number":135,"Content":" resources: {}","IsCause":true,"Annotation":"","Truncated":false,"FirstCause":false,"LastCause":false},{"Number":136,"Content":" terminationMessagePath: /dev/termination-log","IsCause":true,"Annotation":"","Truncated":false,"FirstCause":false,"LastCause":false},{"Number":137,"Content":" terminationMessagePolicy: File","IsCause":true,"Annotation":"","Truncated":false,"FirstCause":false,"LastCause":false},{"Number":138,"Content":" volumeMounts:","IsCause":true,"Annotation":"","Truncated":false,"FirstCause":false,"LastCause":false},{"Number":139,"Content":" - mountPath: /tmp","IsCause":true,"Annotation":"","Truncated":false,"FirstCause":false,"LastCause":false},{"Number":140,"Content":" name: tmp-dir","IsCause":true,"Annotation":"","Truncated":false,"FirstCause":false,"LastCause":true}]}}},{"Type":"Kubernetes Security Check","ID":"KSV037","AVDID":"AVD-KSV-0037","Title":"User Pods should not be placed in kube-system namespace","Description":"ensure that User pods are not placed in kube-system namespace","Message":"Deployment 'metrics-server' should not be set with 'kube-system' namespace","Namespace":"builtin.kubernetes.KSV037","Query":"data.builtin.kubernetes.KSV037.deny","Resolution":"Deploy the use pods into a designated namespace which is not kube-system.","Severity":"MEDIUM","PrimaryURL":"https://avd.aquasec.com/misconfig/ksv037","References":["https://kubernetes.io/docs/reference/setup-tools/kubeadm/implementation-details/","https://avd.aquasec.com/misconfig/ksv037"],"Status":"FAIL","Layer":{},"CauseMetadata":{"Provider":"Kubernetes","Service":"general","StartLine":113,"EndLine":160,"Code":{"Lines":[{"Number":113,"Content":" progressDeadlineSeconds: 600","IsCause":true,"Annotation":"","Truncated":false,"FirstCause":true,"LastCause":false},{"Number":114,"Content":" replicas: 1","IsCause":true,"Annotation":"","Truncated":false,"FirstCause":false,"LastCause":false},{"Number":115,"Content":" revisionHistoryLimit: 10","IsCause":true,"Annotation":"","Truncated":false,"FirstCause":false,"LastCause":false},{"Number":116,"Content":" selector:","IsCause":true,"Annotation":"","Truncated":false,"FirstCause":false,"LastCause":false},{"Number":117,"Content":" matchLabels:","IsCause":true,"Annotation":"","Truncated":false,"FirstCause":false,"LastCause":false},{"Number":118,"Content":" k8s-app: metrics-server","IsCause":true,"Annotation":"","Truncated":false,"FirstCause":false,"LastCause":false},{"Number":119,"Content":" strategy:","IsCause":true,"Annotation":"","Truncated":false,"FirstCause":false,"LastCause":false},{"Number":120,"Content":" rollingUpdate:","IsCause":true,"Annotation":"","Truncated":false,"FirstCause":false,"LastCause":false},{"Number":121,"Content":" maxSurge: 25%","IsCause":true,"Annotation":"","Truncated":false,"FirstCause":false,"LastCause":true},{"Number":122,"Content":"","IsCause":false,"Annotation":"","Truncated":true,"FirstCause":false,"LastCause":false}]}}},{"Type":"Kubernetes Security Check","ID":"KSV106","AVDID":"AVD-KSV-0106","Title":"Container capabilities must only include NET_BIND_SERVICE","Description":"Containers must drop ALL capabilities, and are only permitted to add back the NET_BIND_SERVICE capability.","Message":"container should drop all","Namespace":"builtin.kubernetes.KSV106","Query":"data.builtin.kubernetes.KSV106.deny","Resolution":"Set 'spec.containers[*].securityContext.capabilities.drop' to 'ALL' and only add 'NET_BIND_SERVICE' to 'spec.containers[*].securityContext.capabilities.add'.","Severity":"LOW","PrimaryURL":"https://avd.aquasec.com/misconfig/ksv106","References":["https://kubernetes.io/docs/concepts/security/pod-security-standards/#restricted","https://avd.aquasec.com/misconfig/ksv106"],"Status":"FAIL","Layer":{},"CauseMetadata":{"Provider":"Kubernetes","Service":"general","StartLine":132,"EndLine":140,"Code":{"Lines":[{"Number":132,"Content":" - image: rancher/metrics-server:v0.3.6","IsCause":true,"Annotation":"","Truncated":false,"FirstCause":true,"LastCause":false},{"Number":133,"Content":" imagePullPolicy: IfNotPresent","IsCause":true,"Annotation":"","Truncated":false,"FirstCause":false,"LastCause":false},{"Number":134,"Content":" name: metrics-server","IsCause":true,"Annotation":"","Truncated":false,"FirstCause":false,"LastCause":false},{"Number":135,"Content":" resources: {}","IsCause":true,"Annotation":"","Truncated":false,"FirstCause":false,"LastCause":false},{"Number":136,"Content":" terminationMessagePath: /dev/termination-log","IsCause":true,"Annotation":"","Truncated":false,"FirstCause":false,"LastCause":false},{"Number":137,"Content":" terminationMessagePolicy: File","IsCause":true,"Annotation":"","Truncated":false,"FirstCause":false,"LastCause":false},{"Number":138,"Content":" volumeMounts:","IsCause":true,"Annotation":"","Truncated":false,"FirstCause":false,"LastCause":false},{"Number":139,"Content":" - mountPath: /tmp","IsCause":true,"Annotation":"","Truncated":false,"FirstCause":false,"LastCause":false},{"Number":140,"Content":" name: tmp-dir","IsCause":true,"Annotation":"","Truncated":false,"FirstCause":false,"LastCause":true}]}}}]}] \ No newline at end of file diff --git a/pkg/compliance/report/testdata/results_vul_config.json b/pkg/compliance/report/testdata/results_vul_config.json deleted file mode 100644 index c3a7a8550f..0000000000 --- a/pkg/compliance/report/testdata/results_vul_config.json +++ /dev/null @@ -1,150 +0,0 @@ -[ - { - "Target": "Deployment/metrics-server", - "Class": "config", - "Type": "kubernetes", - "MisconfSummary": { - "Successes": 66, - "Failures": 13, - "Exceptions": 0 - }, - "Misconfigurations": [ - { - "Type": "Kubernetes Security Check", - "ID": "KSV001", - "AVDID": "AVD-KSV-0001", - "Title": "Process can elevate its own privileges", - "Description": "A program inside the container can elevate its own privileges and run as root, which might give the program control over the container and node.", - "Message": "Container 'metrics-server' of Deployment 'metrics-server' should set 'securityContext.allowPrivilegeEscalation' to false", - "Namespace": "builtin.kubernetes.KSV001", - "Query": "data.builtin.kubernetes.KSV001.deny", - "Resolution": "Set 'set containers[].securityContext.allowPrivilegeEscalation' to 'false'.", - "Severity": "MEDIUM", - "PrimaryURL": "https://avd.aquasec.com/misconfig/ksv001", - "References": [ - "https://kubernetes.io/docs/concepts/security/pod-security-standards/#restricted", - "https://avd.aquasec.com/misconfig/ksv001" - ], - "Status": "PASS", - "Layer": {}, - "CauseMetadata": { - "Provider": "Kubernetes", - "Service": "general", - "StartLine": 132, - "EndLine": 140, - "Code": { - "Lines": [ - { - "Number": 132, - "Content": " - image: rancher/metrics-server:v0.3.6", - "IsCause": true, - "Annotation": "", - "Truncated": false, - "FirstCause": true, - "LastCause": false - }, - { - "Number": 133, - "Content": " imagePullPolicy: IfNotPresent", - "IsCause": true, - "Annotation": "", - "Truncated": false, - "FirstCause": false, - "LastCause": false - }, - { - "Number": 134, - "Content": " name: metrics-server", - "IsCause": true, - "Annotation": "", - "Truncated": false, - "FirstCause": false, - "LastCause": false - }, - { - "Number": 135, - "Content": " resources: {}", - "IsCause": true, - "Annotation": "", - "Truncated": false, - "FirstCause": false, - "LastCause": false - }, - { - "Number": 136, - "Content": " terminationMessagePath: /dev/termination-log", - "IsCause": true, - "Annotation": "", - "Truncated": false, - "FirstCause": false, - "LastCause": false - }, - { - "Number": 137, - "Content": " terminationMessagePolicy: File", - "IsCause": true, - "Annotation": "", - "Truncated": false, - "FirstCause": false, - "LastCause": false - }, - { - "Number": 138, - "Content": " volumeMounts:", - "IsCause": true, - "Annotation": "", - "Truncated": false, - "FirstCause": false, - "LastCause": false - }, - { - "Number": 139, - "Content": " - mountPath: /tmp", - "IsCause": true, - "Annotation": "", - "Truncated": false, - "FirstCause": false, - "LastCause": false - }, - { - "Number": 140, - "Content": " name: tmp-dir", - "IsCause": true, - "Annotation": "", - "Truncated": false, - "FirstCause": false, - "LastCause": true - } - ] - } - } - } - ] - }, - { - "Target": "rancher/metrics-server:v0.3.6 (debian 9.9)", - "Class": "os-pkgs", - "Type": "debian", - "Vulnerabilities": [ - { - "VulnerabilityID": "DLA-2424-1", - "VendorIDs": [ - "DLA-2424-1" - ], - "PkgName": "tzdata", - "InstalledVersion": "2019a-0+deb9u1", - "FixedVersion": "2020d-0+deb9u1", - "Layer": { - "DiffID": "sha256:932da51564135c98a49a34a193d6cd363d8fa4184d957fde16c9d8527b3f3b02" - }, - "DataSource": { - "ID": "debian", - "Name": "Debian Security Tracker", - "URL": "https://salsa.debian.org/security-tracker-team/security-tracker" - }, - "Title": "tzdata - new upstream version", - "Severity": "UNKNOWN" - } - ] - } -] \ No newline at end of file diff --git a/pkg/compliance/report/testdata/summary.json b/pkg/compliance/report/testdata/summary.json new file mode 100644 index 0000000000..0cf8982b61 --- /dev/null +++ b/pkg/compliance/report/testdata/summary.json @@ -0,0 +1,20 @@ +{ + "ID": "1234", + "Title": "NSA", + "SummaryControls": [ + { + "ID": "1.0", + "Name": "Non-root containers", + "Severity": "MEDIUM", + "TotalPass": 0, + "TotalFail": 1 + }, + { + "ID": "1.1", + "Name": "Immutable container file systems", + "Severity": "LOW", + "TotalPass": 0, + "TotalFail": 1 + } + ] +} diff --git a/pkg/compliance/report/testdata/table.txt b/pkg/compliance/report/testdata/table_all.txt similarity index 100% rename from pkg/compliance/report/testdata/table.txt rename to pkg/compliance/report/testdata/table_all.txt diff --git a/pkg/compliance/report/testdata/table_summary.txt b/pkg/compliance/report/testdata/table_summary.txt index 57f3df1ce1..9a08c9bced 100644 --- a/pkg/compliance/report/testdata/table_summary.txt +++ b/pkg/compliance/report/testdata/table_summary.txt @@ -1,5 +1,5 @@ -Summary Report for compliance: nsa +Summary Report for compliance: NSA ┌─────┬──────────┬──────────────────────────────────┬────────────┐ │ ID │ Severity │ Control Name │ Compliance │ ├─────┼──────────┼──────────────────────────────────┼────────────┤ diff --git a/pkg/compliance/report/testdata/vuln_conf_table.txt b/pkg/compliance/report/testdata/vuln_conf_table.txt deleted file mode 100644 index c442d5b380..0000000000 --- a/pkg/compliance/report/testdata/vuln_conf_table.txt +++ /dev/null @@ -1,36 +0,0 @@ - -Deployment/metrics-server (kubernetes) -====================================== -Tests: 1 (SUCCESSES: 1, FAILURES: 0, EXCEPTIONS: 0) -Failures: 0 () - -MEDIUM: Container 'metrics-server' of Deployment 'metrics-server' should set 'securityContext.allowPrivilegeEscalation' to false -════════════════════════════════════════ -A program inside the container can elevate its own privileges and run as root, which might give the program control over the container and node. - -See https://avd.aquasec.com/misconfig/ksv001 -──────────────────────────────────────── - Deployment/metrics-server:132-140 -──────────────────────────────────────── - 132 ┌ - image: rancher/metrics-server:v0.3.6 - 133 │ imagePullPolicy: IfNotPresent - 134 │ name: metrics-server - 135 │ resources: {} - 136 │ terminationMessagePath: /dev/termination-log - 137 │ terminationMessagePolicy: File - 138 │ volumeMounts: - 139 │ - mountPath: /tmp - 140 └ name: tmp-dir -──────────────────────────────────────── - - - -rancher/metrics-server:v0.3.6 (debian 9.9) -========================================== -Total: 0 () - -┌─────────┬───────────────┬──────────┬───────────────────┬────────────────┬───────────────────────────────┐ -│ Library │ Vulnerability │ Severity │ Installed Version │ Fixed Version │ Title │ -├─────────┼───────────────┼──────────┼───────────────────┼────────────────┼───────────────────────────────┤ -│ tzdata │ DLA-2424-1 │ UNKNOWN │ 2019a-0+deb9u1 │ 2020d-0+deb9u1 │ tzdata - new upstream version │ -└─────────┴───────────────┴──────────┴───────────────────┴────────────────┴───────────────────────────────┘ diff --git a/pkg/compliance/report/testdata/vuln_conf_table_summary.txt b/pkg/compliance/report/testdata/vuln_conf_table_summary.txt deleted file mode 100644 index 824f528122..0000000000 --- a/pkg/compliance/report/testdata/vuln_conf_table_summary.txt +++ /dev/null @@ -1,11 +0,0 @@ - -Summary Report for compliance: nsa -┌─────┬──────────┬──────────────────────────────────┬────────────┐ -│ ID │ Severity │ Control Name │ Compliance │ -├─────┼──────────┼──────────────────────────────────┼────────────┤ -│ 1.0 │ MEDIUM │ Non-root containers │ 100.00% │ -│ 1.1 │ LOW │ Immutable container file systems │ 0.00% │ -│ 1.2 │ CRITICAL │ tzdata - new upstream version │ 0.00% │ -└─────┴──────────┴──────────────────────────────────┴────────────┘ - - diff --git a/pkg/compliance/report/testdata/vuln_config_compliance.json b/pkg/compliance/report/testdata/vuln_config_compliance.json deleted file mode 100644 index 3a4a206249..0000000000 --- a/pkg/compliance/report/testdata/vuln_config_compliance.json +++ /dev/null @@ -1,182 +0,0 @@ -{ - "id": "1234", - "title": "nsa", - "description": "National Security Agency - Kubernetes Hardening Guidance", - "severity": "1.0", - "relatedResources": [ - "http://related-resource/" - ], - "results": [ - { - "id": "1.0", - "name": "Non-root containers", - "description": "Check that container is not running as root", - "severity": "MEDIUM", - "results": [ - { - "Target": "Deployment/metrics-server", - "Class": "config", - "Type": "kubernetes", - "MisconfSummary": { - "Successes": 1, - "Failures": 0, - "Exceptions": 0 - }, - "Misconfigurations": [ - { - "Type": "Kubernetes Security Check", - "ID": "KSV001", - "AVDID": "AVD-KSV-0001", - "Title": "Process can elevate its own privileges", - "Description": "A program inside the container can elevate its own privileges and run as root, which might give the program control over the container and node.", - "Message": "Container 'metrics-server' of Deployment 'metrics-server' should set 'securityContext.allowPrivilegeEscalation' to false", - "Namespace": "builtin.kubernetes.KSV001", - "Query": "data.builtin.kubernetes.KSV001.deny", - "Resolution": "Set 'set containers[].securityContext.allowPrivilegeEscalation' to 'false'.", - "Severity": "MEDIUM", - "PrimaryURL": "https://avd.aquasec.com/misconfig/ksv001", - "References": [ - "https://kubernetes.io/docs/concepts/security/pod-security-standards/#restricted", - "https://avd.aquasec.com/misconfig/ksv001" - ], - "Status": "PASS", - "Layer": {}, - "CauseMetadata": { - "Provider": "Kubernetes", - "Service": "general", - "StartLine": 132, - "EndLine": 140, - "Code": { - "Lines": [ - { - "Number": 132, - "Content": " - image: rancher/metrics-server:v0.3.6", - "IsCause": true, - "Annotation": "", - "Truncated": false, - "FirstCause": true, - "LastCause": false - }, - { - "Number": 133, - "Content": " imagePullPolicy: IfNotPresent", - "IsCause": true, - "Annotation": "", - "Truncated": false, - "FirstCause": false, - "LastCause": false - }, - { - "Number": 134, - "Content": " name: metrics-server", - "IsCause": true, - "Annotation": "", - "Truncated": false, - "FirstCause": false, - "LastCause": false - }, - { - "Number": 135, - "Content": " resources: {}", - "IsCause": true, - "Annotation": "", - "Truncated": false, - "FirstCause": false, - "LastCause": false - }, - { - "Number": 136, - "Content": " terminationMessagePath: /dev/termination-log", - "IsCause": true, - "Annotation": "", - "Truncated": false, - "FirstCause": false, - "LastCause": false - }, - { - "Number": 137, - "Content": " terminationMessagePolicy: File", - "IsCause": true, - "Annotation": "", - "Truncated": false, - "FirstCause": false, - "LastCause": false - }, - { - "Number": 138, - "Content": " volumeMounts:", - "IsCause": true, - "Annotation": "", - "Truncated": false, - "FirstCause": false, - "LastCause": false - }, - { - "Number": 139, - "Content": " - mountPath: /tmp", - "IsCause": true, - "Annotation": "", - "Truncated": false, - "FirstCause": false, - "LastCause": false - }, - { - "Number": 140, - "Content": " name: tmp-dir", - "IsCause": true, - "Annotation": "", - "Truncated": false, - "FirstCause": false, - "LastCause": true - } - ] - } - } - } - ] - } - ] - }, - { - "id": "1.1", - "name": "Immutable container file systems", - "description": "Check that container root file system is immutable", - "severity": "LOW", - "results": null - }, - { - "id": "1.2", - "name": "tzdata - new upstream version", - "description": "Bad tzdata package", - "severity": "CRITICAL", - "results": [ - { - "Target": "rancher/metrics-server:v0.3.6 (debian 9.9)", - "Class": "os-pkgs", - "Type": "debian", - "Vulnerabilities": [ - { - "VulnerabilityID": "DLA-2424-1", - "VendorIDs": [ - "DLA-2424-1" - ], - "PkgName": "tzdata", - "InstalledVersion": "2019a-0+deb9u1", - "FixedVersion": "2020d-0+deb9u1", - "Layer": { - "DiffID": "sha256:932da51564135c98a49a34a193d6cd363d8fa4184d957fde16c9d8527b3f3b02" - }, - "DataSource": { - "ID": "debian", - "Name": "Debian Security Tracker", - "URL": "https://salsa.debian.org/security-tracker-team/security-tracker" - }, - "Title": "tzdata - new upstream version", - "Severity": "UNKNOWN" - } - ] - } - ] - } - ] -} \ No newline at end of file diff --git a/pkg/compliance/report/testdata/vuln_config_summary.json b/pkg/compliance/report/testdata/vuln_config_summary.json deleted file mode 100644 index cdeaf2f61b..0000000000 --- a/pkg/compliance/report/testdata/vuln_config_summary.json +++ /dev/null @@ -1 +0,0 @@ -{"ReportID":"1234","ReportTitle":"nsa","SummaryControls":[{"id":"1.0","name":"Non-root containers","severity":"MEDIUM","totalPass":1,"totalFail":0},{"id":"1.1","name":"Immutable container file systems","severity":"LOW","totalPass":0,"totalFail":0},{"id":"1.2","name":"tzdata - new upstream version","severity":"CRITICAL","totalPass":0,"totalFail":1}]} \ No newline at end of file diff --git a/pkg/compliance/spec/compliance.go b/pkg/compliance/spec/compliance.go index a6d6526aff..3f4fa8237c 100644 --- a/pkg/compliance/spec/compliance.go +++ b/pkg/compliance/spec/compliance.go @@ -1,17 +1,16 @@ package spec -type Severity string +import ( + "strings" -const ( - SeverityCritical Severity = "CRITICAL" - SeverityHigh Severity = "HIGH" - SeverityMedium Severity = "MEDIUM" - SeverityLow Severity = "LOW" + "golang.org/x/exp/maps" + "golang.org/x/xerrors" - SeverityNone Severity = "NONE" - SeverityUnknown Severity = "UNKNOWN" + "github.com/aquasecurity/trivy/pkg/types" ) +type Severity string + // ComplianceSpec represent the compliance specification type ComplianceSpec struct { Spec Spec `yaml:"spec"` @@ -58,3 +57,42 @@ const ( PassStatus ControlStatus = "PASS" WarnStatus ControlStatus = "WARN" ) + +// SecurityChecks reads spec control and determines the scanners by check ID prefix +func (cs *ComplianceSpec) SecurityChecks() ([]types.SecurityCheck, error) { + scannerTypes := map[types.SecurityCheck]struct{}{} + for _, control := range cs.Spec.Controls { + for _, check := range control.Checks { + scannerType := securityCheckByCheckID(check.ID) + if scannerType == types.SecurityCheckUnknown { + return nil, xerrors.Errorf("unsupported check ID: %s", check.ID) + } + scannerTypes[scannerType] = struct{}{} + } + } + return maps.Keys(scannerTypes), nil +} + +// CheckIDs return list of compliance check IDs +func (cs *ComplianceSpec) CheckIDs() map[types.SecurityCheck][]string { + checkIDsMap := map[types.SecurityCheck][]string{} + for _, control := range cs.Spec.Controls { + for _, check := range control.Checks { + scannerType := securityCheckByCheckID(check.ID) + checkIDsMap[scannerType] = append(checkIDsMap[scannerType], check.ID) + } + } + return checkIDsMap +} + +func securityCheckByCheckID(checkID string) types.SecurityCheck { + checkID = strings.ToLower(checkID) + switch { + case strings.HasPrefix(checkID, "cve-") || strings.HasPrefix(checkID, "dla-"): + return types.SecurityCheckVulnerability + case strings.HasPrefix(checkID, "avd-"): + return types.SecurityCheckConfig + default: + return types.SecurityCheckUnknown + } +} diff --git a/pkg/compliance/spec/compliance_test.go b/pkg/compliance/spec/compliance_test.go new file mode 100644 index 0000000000..6dec9bd0b5 --- /dev/null +++ b/pkg/compliance/spec/compliance_test.go @@ -0,0 +1,236 @@ +package spec_test + +import ( + "fmt" + "sort" + "testing" + + "github.com/stretchr/testify/assert" + + "github.com/aquasecurity/trivy/pkg/compliance/spec" + "github.com/aquasecurity/trivy/pkg/types" +) + +func TestComplianceSpec_SecurityChecks(t *testing.T) { + tests := []struct { + name string + spec spec.Spec + want []types.SecurityCheck + wantErr assert.ErrorAssertionFunc + }{ + { + name: "get config scanner type by check id prefix", + spec: spec.Spec{ + ID: "1234", + Title: "NSA", + Description: "National Security Agency - Kubernetes Hardening Guidance", + RelatedResources: []string{ + "https://example.com", + }, + Version: "1.0", + Controls: []spec.Control{ + { + Name: "Non-root containers", + Description: "Check that container is not running as root", + ID: "1.0", + Checks: []spec.SpecCheck{ + {ID: "AVD-KSV012"}, + }, + }, + { + Name: "Check that encryption resource has been set", + Description: "Control checks whether encryption resource has been set", + ID: "1.1", + Checks: []spec.SpecCheck{ + {ID: "AVD-1.2.31"}, + {ID: "AVD-1.2.32"}, + }, + }, + }, + }, + want: []types.SecurityCheck{types.SecurityCheckConfig}, + wantErr: assert.NoError, + }, + { + name: "get config and vuln scanners types by check id prefix", + spec: spec.Spec{ + ID: "1234", + Title: "NSA", + Description: "National Security Agency - Kubernetes Hardening Guidance", + RelatedResources: []string{ + "https://example.com", + }, + Version: "1.0", + Controls: []spec.Control{ + { + Name: "Non-root containers", + Description: "Check that container is not running as root", + ID: "1.0", + Checks: []spec.SpecCheck{ + {ID: "AVD-KSV012"}, + }, + }, + { + Name: "Check that encryption resource has been set", + Description: "Control checks whether encryption resource has been set", + ID: "1.1", + Checks: []spec.SpecCheck{ + {ID: "AVD-1.2.31"}, + {ID: "AVD-1.2.32"}, + }, + }, + { + Name: "Ensure no critical vulnerabilities", + Description: "Control checks whether critical vulnerabilities are not found", + ID: "7.0", + Checks: []spec.SpecCheck{ + {ID: "CVE-9999-9999"}, + }, + }, + }, + }, + want: []types.SecurityCheck{types.SecurityCheckConfig, types.SecurityCheckVulnerability}, + wantErr: assert.NoError, + }, + { + name: "unknown prefix", + spec: spec.Spec{ + ID: "1234", + Title: "NSA", + Description: "National Security Agency - Kubernetes Hardening Guidance", + RelatedResources: []string{ + "https://example.com", + }, + Version: "1.0", + Controls: []spec.Control{ + { + Name: "Unknown", + ID: "1.0", + Checks: []spec.SpecCheck{ + {ID: "UNKNOWN-001"}, + }, + }, + }, + }, + wantErr: assert.Error, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + cs := &spec.ComplianceSpec{ + Spec: tt.spec, + } + got, err := cs.SecurityChecks() + if !tt.wantErr(t, err, fmt.Sprintf("SecurityChecks()")) { + return + } + sort.Strings(got) // for consistency + assert.Equalf(t, tt.want, got, "SecurityChecks()") + }) + } +} + +func TestComplianceSpec_CheckIDs(t *testing.T) { + tests := []struct { + name string + spec spec.Spec + want map[types.SecurityCheck][]string + }{ + { + name: "get config scanner type by check id prefix", + spec: spec.Spec{ + ID: "1234", + Title: "NSA", + Description: "National Security Agency - Kubernetes Hardening Guidance", + RelatedResources: []string{ + "https://example.com", + }, + Version: "1.0", + Controls: []spec.Control{ + { + Name: "Non-root containers", + Description: "Check that container is not running as root", + ID: "1.0", + Checks: []spec.SpecCheck{ + {ID: "AVD-KSV012"}, + }, + }, + { + Name: "Check that encryption resource has been set", + Description: "Control checks whether encryption resource has been set", + ID: "1.1", + Checks: []spec.SpecCheck{ + {ID: "AVD-1.2.31"}, + {ID: "AVD-1.2.32"}, + }, + }, + }, + }, + want: map[types.SecurityCheck][]string{ + types.SecurityCheckConfig: { + "AVD-KSV012", + "AVD-1.2.31", + "AVD-1.2.32", + }, + }, + }, + { + name: "get config and vuln scanners types by check id prefix", + spec: spec.Spec{ + ID: "1234", + Title: "NSA", + Description: "National Security Agency - Kubernetes Hardening Guidance", + RelatedResources: []string{ + "https://example.com", + }, + Version: "1.0", + Controls: []spec.Control{ + { + Name: "Non-root containers", + Description: "Check that container is not running as root", + ID: "1.0", + Checks: []spec.SpecCheck{ + {ID: "AVD-KSV012"}, + }, + }, + { + Name: "Check that encryption resource has been set", + Description: "Control checks whether encryption resource has been set", + ID: "1.1", + Checks: []spec.SpecCheck{ + {ID: "AVD-1.2.31"}, + {ID: "AVD-1.2.32"}, + }, + }, + { + Name: "Ensure no critical vulnerabilities", + Description: "Control checks whether critical vulnerabilities are not found", + ID: "7.0", + Checks: []spec.SpecCheck{ + {ID: "CVE-9999-9999"}, + }, + }, + }, + }, + want: map[types.SecurityCheck][]string{ + types.SecurityCheckConfig: { + "AVD-KSV012", + "AVD-1.2.31", + "AVD-1.2.32", + }, + types.SecurityCheckVulnerability: { + "CVE-9999-9999", + }, + }, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + cs := &spec.ComplianceSpec{ + Spec: tt.spec, + } + got := cs.CheckIDs() + assert.Equalf(t, tt.want, got, "CheckIDs()") + }) + } +} diff --git a/pkg/compliance/spec/controlutil.go b/pkg/compliance/spec/controlutil.go deleted file mode 100644 index d74c3da69c..0000000000 --- a/pkg/compliance/spec/controlutil.go +++ /dev/null @@ -1,71 +0,0 @@ -package spec - -import ( - "fmt" - "strings" - - "golang.org/x/exp/slices" - "gopkg.in/yaml.v2" - - "github.com/aquasecurity/trivy/pkg/types" -) - -// GetScannerTypes read spec control and detremine the scanners by check ID prefix -func GetScannerTypes(complianceSpec string) ([]types.SecurityCheck, error) { - cs := ComplianceSpec{} - err := yaml.Unmarshal([]byte(complianceSpec), &cs) - if err != nil { - return nil, err - } - scannerTypes := make([]types.SecurityCheck, 0) - for _, control := range cs.Spec.Controls { - for _, check := range control.Checks { - scannerType := scannersByCheckIDPrefix(check.ID) - if !slices.Contains(scannerTypes, scannerType) { - scannerTypes = append(scannerTypes, scannerType) - } - } - } - return scannerTypes, nil -} - -// ValidateScanners validate that scanner types are supported -func ValidateScanners(controls []Control) error { - for _, control := range controls { - for _, check := range control.Checks { - scannerType := scannersByCheckIDPrefix(check.ID) - if !slices.Contains(types.SecurityChecks, scannerType) { - return fmt.Errorf("scanner type %v is not supported", scannerType) - } - } - } - return nil -} - -// ScannerCheckIDs return list of compliance check IDs -func ScannerCheckIDs(controls []Control) map[string][]string { - scannerChecksMap := make(map[string][]string) - for _, control := range controls { - for _, check := range control.Checks { - scannerType := scannersByCheckIDPrefix(check.ID) - if _, ok := scannerChecksMap[scannerType]; !ok { - scannerChecksMap[scannerType] = make([]string, 0) - } - if !slices.Contains(scannerChecksMap[scannerType], check.ID) { - scannerChecksMap[scannerType] = append(scannerChecksMap[scannerType], check.ID) - } - } - } - return scannerChecksMap -} - -func scannersByCheckIDPrefix(checkID string) string { - switch { - case strings.HasPrefix(strings.ToLower(checkID), "cve-") || strings.HasPrefix(strings.ToLower(checkID), "dla-"): - return "vuln" - case strings.HasPrefix(strings.ToLower(checkID), "avd-"): - return "config" - default: - return "" - } -} diff --git a/pkg/compliance/spec/controlutil_test.go b/pkg/compliance/spec/controlutil_test.go deleted file mode 100644 index ebaf200f0a..0000000000 --- a/pkg/compliance/spec/controlutil_test.go +++ /dev/null @@ -1,86 +0,0 @@ -package spec_test - -import ( - "os" - "testing" - - "github.com/aquasecurity/trivy/pkg/compliance/spec" - "github.com/aquasecurity/trivy/pkg/types" - "github.com/stretchr/testify/assert" - "gopkg.in/yaml.v2" -) - -func TestGetScannerTypes(t *testing.T) { - tests := []struct { - name string - specPath string - want []types.SecurityCheck - }{ - {name: "get config scanner type by check id prefix", specPath: "./testdata/spec.yaml", want: []types.SecurityCheck{types.SecurityCheckConfig}}, - {name: "get config and vuln scanners types by check id prefix", specPath: "./testdata/multi_scanner_spec.yaml", want: []types.SecurityCheck{types.SecurityCheckConfig, types.SecurityCheckVulnerability}}, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - b, err := os.ReadFile(tt.specPath) - assert.NoError(t, err) - got, err := spec.GetScannerTypes(string(b)) - assert.NoError(t, err) - assert.Equal(t, got, tt.want) - }) - } -} - -func TestCheckIDs(t *testing.T) { - tests := []struct { - name string - specPath string - wantConfig int - }{ - {name: "get map of scannerType:checkIds array", specPath: "./testdata/spec.yaml", wantConfig: 29}, - {name: "get map of scannerType:checkIds array when dup ids", specPath: "./testdata/spec_dup_id.yaml", wantConfig: 1}, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - cr, err := ReadSpecFile(tt.specPath) - assert.NoError(t, err) - got := spec.ScannerCheckIDs(cr.Spec.Controls) - assert.Equal(t, len(got["config"]), tt.wantConfig) - }) - } -} - -func TestValidateScanners(t *testing.T) { - tests := []struct { - name string - specPath string - expectError bool - }{ - //{name: "spec with valid scanner", specPath: "./testdata/spec.yaml", expectError: false}, - {name: "spec with non valid scanner", specPath: "./testdata/bad_scanner_spec.yaml", expectError: true}, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - compliance, err := ReadSpecFile(tt.specPath) - assert.NoError(t, err) - err = spec.ValidateScanners(compliance.Spec.Controls) - if tt.expectError { - assert.Error(t, err) - } else { - assert.NoError(t, err) - } - }) - } -} - -func ReadSpecFile(specFilePath string) (*spec.ComplianceSpec, error) { - b, err := os.ReadFile(specFilePath) - if err != nil { - return nil, err - } - cr := spec.ComplianceSpec{} - err = yaml.Unmarshal(b, &cr) - if err != nil { - return nil, err - } - return &cr, nil -} diff --git a/pkg/compliance/spec/mapper.go b/pkg/compliance/spec/mapper.go index b2a15a12b6..3a37a661de 100644 --- a/pkg/compliance/spec/mapper.go +++ b/pkg/compliance/spec/mapper.go @@ -1,60 +1,39 @@ package spec import ( + "golang.org/x/exp/slices" + "github.com/aquasecurity/trivy/pkg/types" ) -// TrivyCheck represent checks models : vulnerability , misconfiguration and secret -type TrivyCheck interface { - GetID() string - CheckType() string - CheckPass() bool -} - -// Mapper represent scan checks to spec check ids mapper -type Mapper[T TrivyCheck] interface { - FilterScanResultsBySpecCheckIds(trivyChecks []T, scannerCheckIDs map[string][]string) []T - MapSpecCheckIDToFilteredResults(trivyChecks []TrivyCheck, target string, class types.ResultClass, typeN string, scannerCheckIDs map[string][]string) map[string]types.Results -} - -type mapper[T TrivyCheck] struct { -} - -// NewMapper instansiate new Mapper for specific scanner type -func NewMapper[T TrivyCheck]() Mapper[T] { - return &mapper[T]{} -} - -// FilterScanResultsBySpecCheckIds create a array of filtered security checks by spec checks ids -func (m mapper[T]) FilterScanResultsBySpecCheckIds(trivyChecks []T, scannerCheckIDs map[string][]string) []T { - filteredSecurityCheck := make([]T, 0) - for _, tc := range trivyChecks { - for _, id := range scannerCheckIDs[tc.CheckType()] { - if tc.GetID() == id { - filteredSecurityCheck = append(filteredSecurityCheck, tc) - } - } - } - return filteredSecurityCheck -} - -// MapSpecCheckIDToFilteredResults map spec check id to filterred scan results -func (m mapper[T]) MapSpecCheckIDToFilteredResults(trivyChecks []TrivyCheck, target string, class types.ResultClass, typeN string, scannerCheckIDs map[string][]string) map[string]types.Results { +// MapSpecCheckIDToFilteredResults map spec check id to filtered scan results +func MapSpecCheckIDToFilteredResults(result types.Result, checkIDs map[types.SecurityCheck][]string) map[string]types.Results { mapCheckByID := make(map[string]types.Results) - for _, tc := range trivyChecks { - if _, ok := mapCheckByID[tc.GetID()]; !ok { - mapCheckByID[tc.GetID()] = make(types.Results, 0) + for _, vuln := range result.Vulnerabilities { + // Skip irrelevant check IDs + if !slices.Contains(checkIDs[types.SecurityCheckVulnerability], vuln.GetID()) { + continue } - for _, id := range scannerCheckIDs[tc.CheckType()] { - if tc.GetID() == id { - switch val := tc.(type) { - case types.DetectedMisconfiguration: - mapCheckByID[tc.GetID()] = append(mapCheckByID[tc.GetID()], types.Result{Target: target, Class: class, Type: typeN, MisconfSummary: misconfigSummary(val), Misconfigurations: []types.DetectedMisconfiguration{val}}) - case types.DetectedVulnerability: - mapCheckByID[tc.GetID()] = append(mapCheckByID[tc.GetID()], types.Result{Target: target, Class: class, Type: typeN, Vulnerabilities: []types.DetectedVulnerability{val}}) - } - } + mapCheckByID[vuln.GetID()] = append(mapCheckByID[vuln.GetID()], types.Result{ + Target: result.Target, + Class: result.Class, + Type: result.Type, + Vulnerabilities: []types.DetectedVulnerability{vuln}, + }) + } + for _, m := range result.Misconfigurations { + // Skip irrelevant check IDs + if !slices.Contains(checkIDs[types.SecurityCheckConfig], m.GetID()) { + continue } + + mapCheckByID[m.GetID()] = append(mapCheckByID[m.GetID()], types.Result{ + Target: result.Target, + Class: result.Class, + Type: result.Type, + MisconfSummary: misconfigSummary(m), + Misconfigurations: []types.DetectedMisconfiguration{m}, + }) } return mapCheckByID } @@ -65,66 +44,24 @@ func misconfigSummary(misconfig types.DetectedMisconfiguration) *types.MisconfSu case types.StatusPassed: rms.Successes = 1 case types.StatusFailure: - rms.Successes = 1 + rms.Failures = 1 case types.StatusException: rms.Exceptions = 1 } return &rms } -// FilterResults filter miconfiguration and vulnerabilities results by spec scanner check Ids -func FilterResults(results types.Results, scannerCheckIDs map[string][]string) types.Results { - filteredResults := make(types.Results, 0) - for _, result := range results { - if len(result.Misconfigurations) > 0 { - filteredMisconfig := NewMapper[types.DetectedMisconfiguration]().FilterScanResultsBySpecCheckIds(result.Misconfigurations, scannerCheckIDs) - result.Misconfigurations = filteredMisconfig - } - if len(result.Vulnerabilities) > 0 { - filteredVuln := NewMapper[types.DetectedVulnerability]().FilterScanResultsBySpecCheckIds(result.Vulnerabilities, scannerCheckIDs) - result.Vulnerabilities = filteredVuln - } - filteredResults = append(filteredResults, result) - } - return filteredResults -} - -// AggregateAllChecksBySpecID aggregate all scan results and map it to spec ids -func AggregateAllChecksBySpecID(multiResults []types.Results, controls []Control) map[string]types.Results { - scannerCheckIDs := ScannerCheckIDs(controls) +// AggregateAllChecksBySpecID aggregates all scan results and map it to spec ids +func AggregateAllChecksBySpecID(multiResults []types.Results, cs ComplianceSpec) map[string]types.Results { + checkIDs := cs.CheckIDs() complianceArr := make(map[string]types.Results, 0) for _, resResult := range multiResults { - filteredResults := FilterResults(resResult, scannerCheckIDs) - for _, result := range filteredResults { - if len(result.Misconfigurations) > 0 { - cMapper := NewMapper[types.DetectedMisconfiguration]() - misconfigMap := cMapper.MapSpecCheckIDToFilteredResults(getTrivyChecks(result.Misconfigurations), result.Target, result.Class, result.Type, scannerCheckIDs) - for id, checks := range misconfigMap { - if _, ok := misconfigMap[id]; !ok { - complianceArr[id] = make(types.Results, 0) - } - complianceArr[id] = append(complianceArr[id], checks...) - } - } - if len(result.Vulnerabilities) > 0 { - vMapper := NewMapper[types.DetectedMisconfiguration]() - vulnsMap := vMapper.MapSpecCheckIDToFilteredResults(getTrivyChecks(result.Vulnerabilities), result.Target, result.Class, result.Type, scannerCheckIDs) - for id, checks := range vulnsMap { - if _, ok := vulnsMap[id]; !ok { - complianceArr[id] = make(types.Results, 0) - } - complianceArr[id] = append(complianceArr[id], checks...) - } + for _, result := range resResult { + m := MapSpecCheckIDToFilteredResults(result, checkIDs) + for id, checks := range m { + complianceArr[id] = append(complianceArr[id], checks...) } } } return complianceArr } - -func getTrivyChecks[T TrivyCheck](checks []T) []TrivyCheck { - tc := make([]TrivyCheck, 0) - for _, check := range checks { - tc = append(tc, check) - } - return tc -} diff --git a/pkg/compliance/spec/mapper_test.go b/pkg/compliance/spec/mapper_test.go index 78f67994e0..186f1407f1 100644 --- a/pkg/compliance/spec/mapper_test.go +++ b/pkg/compliance/spec/mapper_test.go @@ -3,83 +3,98 @@ package spec_test import ( "testing" - "github.com/aquasecurity/trivy/pkg/compliance/spec" - "github.com/aquasecurity/trivy/pkg/types" "github.com/stretchr/testify/assert" + + "github.com/aquasecurity/trivy/pkg/compliance/spec" + ftypes "github.com/aquasecurity/trivy/pkg/fanal/types" + "github.com/aquasecurity/trivy/pkg/types" ) -func TestFilterScanResultsBySpecCheckIds(t *testing.T) { - tests := []struct { - name string - specPath string - trivyCheck spec.TrivyCheck - wantMapping map[string][]spec.TrivyCheck - }{ - {name: "filter results by check ids for config", specPath: "./testdata/mapping_spec.yaml", trivyCheck: types.DetectedMisconfiguration{AVDID: "KSV012"}, - wantMapping: map[string][]spec.TrivyCheck{"KSV012": {types.DetectedMisconfiguration{AVDID: "KSV012"}}}}, - {name: "filter results by check ids for vulns", specPath: "./testdata/mapping_spec.yaml", trivyCheck: types.DetectedVulnerability{VulnerabilityID: "KSV014"}, - wantMapping: map[string][]spec.TrivyCheck{"KSV014": {types.DetectedVulnerability{VulnerabilityID: "KSV014"}}}}, - } - - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - cr, err := ReadSpecFile(tt.specPath) - assert.NoError(t, err) - scannerIDMap := spec.ScannerCheckIDs(cr.Spec.Controls) - m := spec.NewMapper[spec.TrivyCheck]() - filteredResults := m.FilterScanResultsBySpecCheckIds([]spec.TrivyCheck{tt.trivyCheck}, scannerIDMap) - for _, v := range filteredResults { - assert.Equal(t, len(tt.wantMapping[v.GetID()]), 1) - } - }) - } -} - -func TestFilterResults(t *testing.T) { - tests := []struct { - name string - specPath string - results types.Results - wantFiltered types.Results - }{ - {name: "filter results by check ids define in spec", specPath: "./testdata/mapping_spec.yaml", - results: types.Results{{Misconfigurations: []types.DetectedMisconfiguration{{AVDID: "AVD-KSV012"}, {AVDID: "AVD-KSV017"}}, Vulnerabilities: []types.DetectedVulnerability{{VulnerabilityID: "CVE-KSV014"}}}}, - wantFiltered: types.Results{{Misconfigurations: []types.DetectedMisconfiguration{{AVDID: "AVD-KSV012"}}, Vulnerabilities: []types.DetectedVulnerability{{VulnerabilityID: "CVE-KSV014"}}}}}, - } - - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - cr, err := ReadSpecFile(tt.specPath) - assert.NoError(t, err) - scannerIDMap := spec.ScannerCheckIDs(cr.Spec.Controls) - r := spec.FilterResults(tt.results, scannerIDMap) - assert.Equal(t, r, tt.wantFiltered) - }) - } -} - -func TestMapSpecCheckIDtoFilteredResults(t *testing.T) { - tests := []struct { - name string - specPath string - trivyCheck spec.TrivyCheck - wantMapping map[string]types.Results - }{ - {name: "map Check by ID config", specPath: "./testdata/mapping_spec.yaml", trivyCheck: types.DetectedMisconfiguration{AVDID: "AVD-KSV012"}, - wantMapping: map[string]types.Results{"AVD-KSV012": {types.Result{Target: "target", MisconfSummary: &types.MisconfSummary{Successes: 0, Failures: 0, Exceptions: 0}, Class: "class", Type: "typeN", Misconfigurations: []types.DetectedMisconfiguration{{AVDID: "AVD-KSV012"}}}}}, +func TestMapSpecCheckIDToFilteredResults(t *testing.T) { + checkIDs := map[types.SecurityCheck][]string{ + types.SecurityCheckConfig: { + "AVD-KSV012", + "AVD-1.2.31", + "AVD-1.2.32", + }, + types.SecurityCheckVulnerability: { + "CVE-9999-9999", + }, + } + tests := []struct { + name string + checkIDs map[types.SecurityCheck][]string + result types.Result + want map[string]types.Results + }{ + { + name: "misconfiguration", + checkIDs: checkIDs, + result: types.Result{ + Target: "target", + Class: types.ClassConfig, + Type: ftypes.Kubernetes, + Misconfigurations: []types.DetectedMisconfiguration{ + {AVDID: "AVD-KSV012", Status: types.StatusFailure}, + {AVDID: "AVD-KSV013", Status: types.StatusFailure}, + {AVDID: "AVD-1.2.31", Status: types.StatusFailure}, + }, + }, + want: map[string]types.Results{ + "AVD-KSV012": { + { + Target: "target", + Class: types.ClassConfig, + Type: ftypes.Kubernetes, + MisconfSummary: &types.MisconfSummary{Successes: 0, Failures: 1, Exceptions: 0}, + Misconfigurations: []types.DetectedMisconfiguration{ + {AVDID: "AVD-KSV012", Status: types.StatusFailure}, + }, + }, + }, + "AVD-1.2.31": { + { + Target: "target", + Class: types.ClassConfig, + Type: ftypes.Kubernetes, + MisconfSummary: &types.MisconfSummary{Successes: 0, Failures: 1, Exceptions: 0}, + Misconfigurations: []types.DetectedMisconfiguration{ + {AVDID: "AVD-1.2.31", Status: types.StatusFailure}, + }, + }, + }, + }, + }, + { + name: "vulnerability", + checkIDs: checkIDs, + result: types.Result{ + Target: "target", + Class: types.ClassLangPkg, + Type: ftypes.GoModule, + Vulnerabilities: []types.DetectedVulnerability{ + {VulnerabilityID: "CVE-9999-0001"}, + {VulnerabilityID: "CVE-9999-9999"}, + }, + }, + want: map[string]types.Results{ + "CVE-9999-9999": { + { + Target: "target", + Class: types.ClassLangPkg, + Type: ftypes.GoModule, + Vulnerabilities: []types.DetectedVulnerability{ + {VulnerabilityID: "CVE-9999-9999"}, + }, + }, + }, + }, }, } - for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - cr, err := ReadSpecFile(tt.specPath) - assert.NoError(t, err) - scannerIDMap := spec.ScannerCheckIDs(cr.Spec.Controls) - m := spec.NewMapper[spec.TrivyCheck]() - mapResults := m.MapSpecCheckIDToFilteredResults([]spec.TrivyCheck{tt.trivyCheck}, "target", "class", "typeN", scannerIDMap) - for key, val := range tt.wantMapping { - assert.Equal(t, mapResults[key], val) - } + got := spec.MapSpecCheckIDToFilteredResults(tt.result, tt.checkIDs) + assert.Equalf(t, tt.want, got, "CheckIDs()") }) } } diff --git a/pkg/compliance/spec/testdata/bad_scanner_spec.yaml b/pkg/compliance/spec/testdata/bad_scanner_spec.yaml deleted file mode 100644 index 8b1ffae278..0000000000 --- a/pkg/compliance/spec/testdata/bad_scanner_spec.yaml +++ /dev/null @@ -1,22 +0,0 @@ ---- -spec: - id: "1234" - title: nsa - description: National Security Agency - Kubernetes Hardening Guidance - version: "1.0" - related_resources : - - http://related-resource/ - controls: - - name: Pod and/or namespace Selectors usage - description: 'Control check validate the pod and/or namespace Selectors usage' - id: '2.0' - defaultStatus: 'FAIL' - checks: - - id: AVD-KSV038 - severity: 'MEDIUM' - - name: Use CNI plugin that supports NetworkPolicy API - description: 'Control check whether check cni plugin installed' - id: '3.0' - checks: - - id: 5.3.1 - severity: 'CRITICAL' \ No newline at end of file diff --git a/pkg/compliance/spec/testdata/compliance_report.json b/pkg/compliance/spec/testdata/compliance_report.json deleted file mode 100644 index 3bbd55512b..0000000000 --- a/pkg/compliance/spec/testdata/compliance_report.json +++ /dev/null @@ -1 +0,0 @@ -{"id":"1234","title":"nsa","description":"National Security Agency - Kubernetes Hardening Guidance","severity":"1.0","relatedResources":["http://related-resource/"],"checksResults":[{"id":"1.0","name":"Non-root containers","description":"Check that container is not running as root","severity":"MEDIUM","checksResults":[{"Target":"Deployment/metrics-server","Class":"config","Type":"kubernetes","MisconfSummary":{"Successes":1,"Failures":0,"Exceptions":0},"Misconfigurations":[{"Type":"Kubernetes Security Check","ID":"KSV001","AVDID":"AVD-KSV-0001","Title":"Process can elevate its own privileges","Description":"A program inside the container can elevate its own privileges and run as root, which might give the program control over the container and node.","Message":"Container 'metrics-server' of Deployment 'metrics-server' should set 'securityContext.allowPrivilegeEscalation' to false","Namespace":"builtin.kubernetes.KSV001","Query":"data.builtin.kubernetes.KSV001.deny","Resolution":"Set 'set containers[].securityContext.allowPrivilegeEscalation' to 'false'.","Severity":"MEDIUM","PrimaryURL":"https://avd.aquasec.com/misconfig/ksv001","References":["https://kubernetes.io/docs/concepts/security/pod-security-standards/#restricted","https://avd.aquasec.com/misconfig/ksv001"],"Status":"FAIL","Layer":{},"CauseMetadata":{"Provider":"Kubernetes","Service":"general","StartLine":132,"EndLine":140,"Code":{"Lines":[{"Number":132,"Content":" - image: rancher/metrics-server:v0.3.6","IsCause":true,"Annotation":"","Truncated":false,"FirstCause":true,"LastCause":false},{"Number":133,"Content":" imagePullPolicy: IfNotPresent","IsCause":true,"Annotation":"","Truncated":false,"FirstCause":false,"LastCause":false},{"Number":134,"Content":" name: metrics-server","IsCause":true,"Annotation":"","Truncated":false,"FirstCause":false,"LastCause":false},{"Number":135,"Content":" resources: {}","IsCause":true,"Annotation":"","Truncated":false,"FirstCause":false,"LastCause":false},{"Number":136,"Content":" terminationMessagePath: /dev/termination-log","IsCause":true,"Annotation":"","Truncated":false,"FirstCause":false,"LastCause":false},{"Number":137,"Content":" terminationMessagePolicy: File","IsCause":true,"Annotation":"","Truncated":false,"FirstCause":false,"LastCause":false},{"Number":138,"Content":" volumeMounts:","IsCause":true,"Annotation":"","Truncated":false,"FirstCause":false,"LastCause":false},{"Number":139,"Content":" - mountPath: /tmp","IsCause":true,"Annotation":"","Truncated":false,"FirstCause":false,"LastCause":false},{"Number":140,"Content":" name: tmp-dir","IsCause":true,"Annotation":"","Truncated":false,"FirstCause":false,"LastCause":true}]}}}]}]},{"id":"1.1","name":"Immutable container file systems","description":"Check that container root file system is immutable","severity":"LOW","checksResults":[{"Target":"Deployment/metrics-server","Class":"config","Type":"kubernetes","MisconfSummary":{"Successes":1,"Failures":0,"Exceptions":0},"Misconfigurations":[{"Type":"Kubernetes Security Check","ID":"KSV003","AVDID":"AVD-KSV-0003","Title":"Default capabilities not dropped","Description":"The container should drop all default capabilities and add only those that are needed for its execution.","Message":"Container 'metrics-server' of Deployment 'metrics-server' should add 'ALL' to 'securityContext.capabilities.drop'","Namespace":"builtin.kubernetes.KSV003","Query":"data.builtin.kubernetes.KSV003.deny","Resolution":"Add 'ALL' to containers[].securityContext.capabilities.drop.","Severity":"LOW","PrimaryURL":"https://avd.aquasec.com/misconfig/ksv003","References":["https://kubesec.io/basics/containers-securitycontext-capabilities-drop-index-all/","https://avd.aquasec.com/misconfig/ksv003"],"Status":"FAIL","Layer":{},"CauseMetadata":{"Provider":"Kubernetes","Service":"general","StartLine":132,"EndLine":140,"Code":{"Lines":[{"Number":132,"Content":" - image: rancher/metrics-server:v0.3.6","IsCause":true,"Annotation":"","Truncated":false,"FirstCause":true,"LastCause":false},{"Number":133,"Content":" imagePullPolicy: IfNotPresent","IsCause":true,"Annotation":"","Truncated":false,"FirstCause":false,"LastCause":false},{"Number":134,"Content":" name: metrics-server","IsCause":true,"Annotation":"","Truncated":false,"FirstCause":false,"LastCause":false},{"Number":135,"Content":" resources: {}","IsCause":true,"Annotation":"","Truncated":false,"FirstCause":false,"LastCause":false},{"Number":136,"Content":" terminationMessagePath: /dev/termination-log","IsCause":true,"Annotation":"","Truncated":false,"FirstCause":false,"LastCause":false},{"Number":137,"Content":" terminationMessagePolicy: File","IsCause":true,"Annotation":"","Truncated":false,"FirstCause":false,"LastCause":false},{"Number":138,"Content":" volumeMounts:","IsCause":true,"Annotation":"","Truncated":false,"FirstCause":false,"LastCause":false},{"Number":139,"Content":" - mountPath: /tmp","IsCause":true,"Annotation":"","Truncated":false,"FirstCause":false,"LastCause":false},{"Number":140,"Content":" name: tmp-dir","IsCause":true,"Annotation":"","Truncated":false,"FirstCause":false,"LastCause":true}]}}}]}]}]} \ No newline at end of file diff --git a/pkg/compliance/spec/testdata/config_spec.yaml b/pkg/compliance/spec/testdata/config_spec.yaml deleted file mode 100644 index b22cd3c225..0000000000 --- a/pkg/compliance/spec/testdata/config_spec.yaml +++ /dev/null @@ -1,23 +0,0 @@ ---- -spec: - id: "1234" - title: nsa - description: National Security Agency - Kubernetes Hardening Guidance - relatedResources : - - http://related-resource/ - version: "1.0" - controls: - - name: Non-root containers - description: 'Check that container is not running as root' - id: '1.0' - checks: - - id: AVD-KSV-0001 - severity: 'MEDIUM' - - name: Immutable container file systems - description: 'Check that container root file system is immutable' - id: '1.1' - checks: - - id: AVD-KSV-0003 - severity: 'LOW' - - \ No newline at end of file diff --git a/pkg/compliance/spec/testdata/mapping_spec.yaml b/pkg/compliance/spec/testdata/mapping_spec.yaml deleted file mode 100644 index 170d292be9..0000000000 --- a/pkg/compliance/spec/testdata/mapping_spec.yaml +++ /dev/null @@ -1,23 +0,0 @@ ---- -spec: - id: "1234" - title: nsa - description: National Security Agency - Kubernetes Hardening Guidance - relatedResources : - - http://related-resource/ - version: "1.0" - controls: - - name: Non-root containers - description: 'Check that container is not running as root' - id: '1.0' - checks: - - id: AVD-KSV012 - severity: 'MEDIUM' - - name: Immutable container file systems - description: 'Check that container root file system is immutable' - id: '1.1' - checks: - - id: CVE-KSV014 - severity: 'LOW' - - \ No newline at end of file diff --git a/pkg/compliance/spec/testdata/multi_scanner_spec.yaml b/pkg/compliance/spec/testdata/multi_scanner_spec.yaml deleted file mode 100644 index 2905b5c2c2..0000000000 --- a/pkg/compliance/spec/testdata/multi_scanner_spec.yaml +++ /dev/null @@ -1,178 +0,0 @@ ---- -spec: - name: "1234" - title: nsa - description: National Security Agency - Kubernetes Hardening Guidance - related_resources : - - http://related-resource/ - version: "1.0" - controls: - - name: Non-root containers - description: 'Check that container is not running as root' - id: '1.0' - checks: - - id: AVD-KSV012 - severity: 'MEDIUM' - - name: Immutable container file systems - description: 'Check that container root file system is immutable' - id: '1.1' - checks: - - id: AVD-KSV014 - severity: 'LOW' - - name: Preventing privileged containers - description: 'Controls whether Pods can run privileged containers' - id: '1.2' - checks: - - id: AVD-KSV017 - severity: 'HIGH' - - name: Share containers process namespaces - description: 'Controls whether containers can share process namespaces' - id: '1.3' - checks: - - id: AVD-KSV008 - severity: 'HIGH' - - name: Share host process namespaces - description: 'Controls whether share host process namespaces' - id: '1.4' - checks: - - id: AVD-KSV009 - severity: 'HIGH' - - name: Use the host network - description: 'Controls whether containers can use the host network' - id: '1.5' - checks: - - id: AVD-KSV010 - severity: 'HIGH' - - name: Run with root privileges or with root group membership - description: 'Controls whether container applications can run with root privileges or with root group membership' - id: '1.6' - checks: - - id: AVD-KSV029 - severity: 'LOW' - - name: Restricts escalation to root privileges - description: 'Control check restrictions escalation to root privileges' - id: '1.7' - checks: - - id: AVD-KSV001 - severity: 'MEDIUM' - - name: Sets the SELinux context of the container - description: 'Control checks if pod sets the SELinux context of the container' - id: '1.8' - checks: - - id: AVD-KSV002 - severity: 'MEDIUM' - - name: Restrict a container's access to resources with AppArmor - description: 'Control checks the restriction of containers access to resources with AppArmor' - id: '1.9' - checks: - - id: AVD-KSV030 - severity: 'MEDIUM' - - name: Sets the seccomp profile used to sandbox containers. - description: 'Control checks the sets the seccomp profile used to sandbox containers' - id: '1.10' - checks: - - id: AVD-KSV030 - severity: 'LOW' - - name: Protecting Pod service account tokens - description: 'Control check whether disable secret token been mount ,automountServiceAccountToken: false' - id: '1.11' - checks: - - id: AVD-KSV036 - severity: 'MEDIUM' - - name: Namespace kube-system should not be used by users - description: 'Control check whether Namespace kube-system is not be used by users' - id: '1.12' - defaultStatus: 'FAIL' - checks: - - id: AVD-KSV037 - severity: 'MEDIUM' - - name: Pod and/or namespace Selectors usage - description: 'Control check validate the pod and/or namespace Selectors usage' - id: '2.0' - defaultStatus: 'FAIL' - checks: - - id: AVD-KSV038 - severity: 'MEDIUM' - - name: Use CNI plugin that supports NetworkPolicy API - description: 'Control check whether check cni plugin installed' - id: '3.0' - checks: - - id: AVD-5.3.1 - severity: 'CRITICAL' - - name: Use ResourceQuota policies to limit resources - description: 'Control check the use of ResourceQuota policy to limit aggregate resource usage within namespace' - id: '4.0' - defaultStatus: 'FAIL' - checks: - - id: "AVD-KSV040" - severity: 'MEDIUM' - - name: Use LimitRange policies to limit resources - description: 'Control check the use of LimitRange policy limit resource usage for namespaces or nodes' - id: '4.1' - defaultStatus: 'FAIL' - checks: - - id: "AVD-KSV039" - severity: 'MEDIUM' - - name: Control plan disable insecure port - description: 'Control check whether control plan disable insecure port' - id: '5.0' - checks: - - id: AVD-1.2.19 - severity: 'CRITICAL' - - name: Encrypt etcd communication - description: 'Control check whether etcd communication is encrypted' - id: '5.1' - checks: - - id: CVE-2.1 - severity: 'CRITICAL' - - name: Ensure kube config file permission - description: 'Control check whether kube config file permissions' - id: '6.0' - checks: - - id: AVD-4.1.3 - - id: AVD-4.1.4 - severity: 'CRITICAL' - - name: Check that encryption resource has been set - description: 'Control checks whether encryption resource has been set' - id: '6.1' - checks: - - id: AVD-1.2.31 - - id: AVD-1.2.32 - severity: 'CRITICAL' - - name: Check encryption provider - description: 'Control checks whether encryption provider has been set' - id: '6.2' - checks: - - id: AVD-1.2.3 - severity: 'CRITICAL' - - name: Make sure anonymous-auth is unset - description: 'Control checks whether anonymous-auth is unset' - id: '7.0' - checks: - - id: AVD-1.2.1 - severity: 'CRITICAL' - - name: Make sure -authorization-mode=RBAC - description: 'Control check whether RBAC permission is in use' - id: '7.1' - checks: - - id: AVD-1.2.7 - - id: AVD-1.2.8 - severity: 'CRITICAL' - - name: Audit policy is configure - description: 'Control check whether audit policy is configure' - id: '8.0' - checks: - - id: AVD-3.2.1 - severity: 'HIGH' - - name: Audit log path is configure - description: 'Control check whether audit log path is configure' - id: '8.1' - checks: - - id: AVD-1.2.22 - severity: 'MEDIUM' - - name: Audit log aging - description: 'Control check whether audit log aging is configure' - id: '8.2' - checks: - - id: AVD-1.2.23 - severity: 'MEDIUM' \ No newline at end of file diff --git a/pkg/compliance/spec/testdata/results_config.json b/pkg/compliance/spec/testdata/results_config.json deleted file mode 100644 index cf1b4a490b..0000000000 --- a/pkg/compliance/spec/testdata/results_config.json +++ /dev/null @@ -1 +0,0 @@ -[{"Target":"Deployment/metrics-server","Class":"config","Type":"kubernetes","MisconfSummary":{"Successes":66,"Failures":13,"Exceptions":0},"Misconfigurations":[{"Type":"Kubernetes Security Check","ID":"KSV001","AVDID":"AVD-KSV-0001","Title":"Process can elevate its own privileges","Description":"A program inside the container can elevate its own privileges and run as root, which might give the program control over the container and node.","Message":"Container 'metrics-server' of Deployment 'metrics-server' should set 'securityContext.allowPrivilegeEscalation' to false","Namespace":"builtin.kubernetes.KSV001","Query":"data.builtin.kubernetes.KSV001.deny","Resolution":"Set 'set containers[].securityContext.allowPrivilegeEscalation' to 'false'.","Severity":"MEDIUM","PrimaryURL":"https://avd.aquasec.com/misconfig/ksv001","References":["https://kubernetes.io/docs/concepts/security/pod-security-standards/#restricted","https://avd.aquasec.com/misconfig/ksv001"],"Status":"FAIL","Layer":{},"CauseMetadata":{"Provider":"Kubernetes","Service":"general","StartLine":132,"EndLine":140,"Code":{"Lines":[{"Number":132,"Content":" - image: rancher/metrics-server:v0.3.6","IsCause":true,"Annotation":"","Truncated":false,"FirstCause":true,"LastCause":false},{"Number":133,"Content":" imagePullPolicy: IfNotPresent","IsCause":true,"Annotation":"","Truncated":false,"FirstCause":false,"LastCause":false},{"Number":134,"Content":" name: metrics-server","IsCause":true,"Annotation":"","Truncated":false,"FirstCause":false,"LastCause":false},{"Number":135,"Content":" resources: {}","IsCause":true,"Annotation":"","Truncated":false,"FirstCause":false,"LastCause":false},{"Number":136,"Content":" terminationMessagePath: /dev/termination-log","IsCause":true,"Annotation":"","Truncated":false,"FirstCause":false,"LastCause":false},{"Number":137,"Content":" terminationMessagePolicy: File","IsCause":true,"Annotation":"","Truncated":false,"FirstCause":false,"LastCause":false},{"Number":138,"Content":" volumeMounts:","IsCause":true,"Annotation":"","Truncated":false,"FirstCause":false,"LastCause":false},{"Number":139,"Content":" - mountPath: /tmp","IsCause":true,"Annotation":"","Truncated":false,"FirstCause":false,"LastCause":false},{"Number":140,"Content":" name: tmp-dir","IsCause":true,"Annotation":"","Truncated":false,"FirstCause":false,"LastCause":true}]}}},{"Type":"Kubernetes Security Check","ID":"KSV003","AVDID":"AVD-KSV-0003","Title":"Default capabilities not dropped","Description":"The container should drop all default capabilities and add only those that are needed for its execution.","Message":"Container 'metrics-server' of Deployment 'metrics-server' should add 'ALL' to 'securityContext.capabilities.drop'","Namespace":"builtin.kubernetes.KSV003","Query":"data.builtin.kubernetes.KSV003.deny","Resolution":"Add 'ALL' to containers[].securityContext.capabilities.drop.","Severity":"LOW","PrimaryURL":"https://avd.aquasec.com/misconfig/ksv003","References":["https://kubesec.io/basics/containers-securitycontext-capabilities-drop-index-all/","https://avd.aquasec.com/misconfig/ksv003"],"Status":"FAIL","Layer":{},"CauseMetadata":{"Provider":"Kubernetes","Service":"general","StartLine":132,"EndLine":140,"Code":{"Lines":[{"Number":132,"Content":" - image: rancher/metrics-server:v0.3.6","IsCause":true,"Annotation":"","Truncated":false,"FirstCause":true,"LastCause":false},{"Number":133,"Content":" imagePullPolicy: IfNotPresent","IsCause":true,"Annotation":"","Truncated":false,"FirstCause":false,"LastCause":false},{"Number":134,"Content":" name: metrics-server","IsCause":true,"Annotation":"","Truncated":false,"FirstCause":false,"LastCause":false},{"Number":135,"Content":" resources: {}","IsCause":true,"Annotation":"","Truncated":false,"FirstCause":false,"LastCause":false},{"Number":136,"Content":" terminationMessagePath: /dev/termination-log","IsCause":true,"Annotation":"","Truncated":false,"FirstCause":false,"LastCause":false},{"Number":137,"Content":" terminationMessagePolicy: File","IsCause":true,"Annotation":"","Truncated":false,"FirstCause":false,"LastCause":false},{"Number":138,"Content":" volumeMounts:","IsCause":true,"Annotation":"","Truncated":false,"FirstCause":false,"LastCause":false},{"Number":139,"Content":" - mountPath: /tmp","IsCause":true,"Annotation":"","Truncated":false,"FirstCause":false,"LastCause":false},{"Number":140,"Content":" name: tmp-dir","IsCause":true,"Annotation":"","Truncated":false,"FirstCause":false,"LastCause":true}]}}},{"Type":"Kubernetes Security Check","ID":"KSV011","AVDID":"AVD-KSV-0011","Title":"CPU not limited","Description":"Enforcing CPU limits prevents DoS via resource exhaustion.","Message":"Container 'metrics-server' of Deployment 'metrics-server' should set 'resources.limits.cpu'","Namespace":"builtin.kubernetes.KSV011","Query":"data.builtin.kubernetes.KSV011.deny","Resolution":"Set a limit value under 'containers[].resources.limits.cpu'.","Severity":"LOW","PrimaryURL":"https://avd.aquasec.com/misconfig/ksv011","References":["https://cloud.google.com/blog/products/containers-kubernetes/kubernetes-best-practices-resource-requests-and-limits","https://avd.aquasec.com/misconfig/ksv011"],"Status":"FAIL","Layer":{},"CauseMetadata":{"Provider":"Kubernetes","Service":"general","StartLine":132,"EndLine":140,"Code":{"Lines":[{"Number":132,"Content":" - image: rancher/metrics-server:v0.3.6","IsCause":true,"Annotation":"","Truncated":false,"FirstCause":true,"LastCause":false},{"Number":133,"Content":" imagePullPolicy: IfNotPresent","IsCause":true,"Annotation":"","Truncated":false,"FirstCause":false,"LastCause":false},{"Number":134,"Content":" name: metrics-server","IsCause":true,"Annotation":"","Truncated":false,"FirstCause":false,"LastCause":false},{"Number":135,"Content":" resources: {}","IsCause":true,"Annotation":"","Truncated":false,"FirstCause":false,"LastCause":false},{"Number":136,"Content":" terminationMessagePath: /dev/termination-log","IsCause":true,"Annotation":"","Truncated":false,"FirstCause":false,"LastCause":false},{"Number":137,"Content":" terminationMessagePolicy: File","IsCause":true,"Annotation":"","Truncated":false,"FirstCause":false,"LastCause":false},{"Number":138,"Content":" volumeMounts:","IsCause":true,"Annotation":"","Truncated":false,"FirstCause":false,"LastCause":false},{"Number":139,"Content":" - mountPath: /tmp","IsCause":true,"Annotation":"","Truncated":false,"FirstCause":false,"LastCause":false},{"Number":140,"Content":" name: tmp-dir","IsCause":true,"Annotation":"","Truncated":false,"FirstCause":false,"LastCause":true}]}}},{"Type":"Kubernetes Security Check","ID":"KSV012","AVDID":"AVD-KSV-0012","Title":"Runs as root user","Description":"'runAsNonRoot' forces the running image to run as a non-root user to ensure least privileges.","Message":"Container 'metrics-server' of Deployment 'metrics-server' should set 'securityContext.runAsNonRoot' to true","Namespace":"builtin.kubernetes.KSV012","Query":"data.builtin.kubernetes.KSV012.deny","Resolution":"Set 'containers[].securityContext.runAsNonRoot' to true.","Severity":"MEDIUM","PrimaryURL":"https://avd.aquasec.com/misconfig/ksv012","References":["https://kubernetes.io/docs/concepts/security/pod-security-standards/#restricted","https://avd.aquasec.com/misconfig/ksv012"],"Status":"FAIL","Layer":{},"CauseMetadata":{"Provider":"Kubernetes","Service":"general","StartLine":132,"EndLine":140,"Code":{"Lines":[{"Number":132,"Content":" - image: rancher/metrics-server:v0.3.6","IsCause":true,"Annotation":"","Truncated":false,"FirstCause":true,"LastCause":false},{"Number":133,"Content":" imagePullPolicy: IfNotPresent","IsCause":true,"Annotation":"","Truncated":false,"FirstCause":false,"LastCause":false},{"Number":134,"Content":" name: metrics-server","IsCause":true,"Annotation":"","Truncated":false,"FirstCause":false,"LastCause":false},{"Number":135,"Content":" resources: {}","IsCause":true,"Annotation":"","Truncated":false,"FirstCause":false,"LastCause":false},{"Number":136,"Content":" terminationMessagePath: /dev/termination-log","IsCause":true,"Annotation":"","Truncated":false,"FirstCause":false,"LastCause":false},{"Number":137,"Content":" terminationMessagePolicy: File","IsCause":true,"Annotation":"","Truncated":false,"FirstCause":false,"LastCause":false},{"Number":138,"Content":" volumeMounts:","IsCause":true,"Annotation":"","Truncated":false,"FirstCause":false,"LastCause":false},{"Number":139,"Content":" - mountPath: /tmp","IsCause":true,"Annotation":"","Truncated":false,"FirstCause":false,"LastCause":false},{"Number":140,"Content":" name: tmp-dir","IsCause":true,"Annotation":"","Truncated":false,"FirstCause":false,"LastCause":true}]}}},{"Type":"Kubernetes Security Check","ID":"KSV014","AVDID":"AVD-KSV-0014","Title":"Root file system is not read-only","Description":"An immutable root file system prevents applications from writing to their local disk. This can limit intrusions, as attackers will not be able to tamper with the file system or write foreign executables to disk.","Message":"Container 'metrics-server' of Deployment 'metrics-server' should set 'securityContext.readOnlyRootFilesystem' to true","Namespace":"builtin.kubernetes.KSV014","Query":"data.builtin.kubernetes.KSV014.deny","Resolution":"Change 'containers[].securityContext.readOnlyRootFilesystem' to 'true'.","Severity":"LOW","PrimaryURL":"https://avd.aquasec.com/misconfig/ksv014","References":["https://kubesec.io/basics/containers-securitycontext-readonlyrootfilesystem-true/","https://avd.aquasec.com/misconfig/ksv014"],"Status":"FAIL","Layer":{},"CauseMetadata":{"Provider":"Kubernetes","Service":"general","StartLine":132,"EndLine":140,"Code":{"Lines":[{"Number":132,"Content":" - image: rancher/metrics-server:v0.3.6","IsCause":true,"Annotation":"","Truncated":false,"FirstCause":true,"LastCause":false},{"Number":133,"Content":" imagePullPolicy: IfNotPresent","IsCause":true,"Annotation":"","Truncated":false,"FirstCause":false,"LastCause":false},{"Number":134,"Content":" name: metrics-server","IsCause":true,"Annotation":"","Truncated":false,"FirstCause":false,"LastCause":false},{"Number":135,"Content":" resources: {}","IsCause":true,"Annotation":"","Truncated":false,"FirstCause":false,"LastCause":false},{"Number":136,"Content":" terminationMessagePath: /dev/termination-log","IsCause":true,"Annotation":"","Truncated":false,"FirstCause":false,"LastCause":false},{"Number":137,"Content":" terminationMessagePolicy: File","IsCause":true,"Annotation":"","Truncated":false,"FirstCause":false,"LastCause":false},{"Number":138,"Content":" volumeMounts:","IsCause":true,"Annotation":"","Truncated":false,"FirstCause":false,"LastCause":false},{"Number":139,"Content":" - mountPath: /tmp","IsCause":true,"Annotation":"","Truncated":false,"FirstCause":false,"LastCause":false},{"Number":140,"Content":" name: tmp-dir","IsCause":true,"Annotation":"","Truncated":false,"FirstCause":false,"LastCause":true}]}}},{"Type":"Kubernetes Security Check","ID":"KSV015","AVDID":"AVD-KSV-0015","Title":"CPU requests not specified","Description":"When containers have resource requests specified, the scheduler can make better decisions about which nodes to place pods on, and how to deal with resource contention.","Message":"Container 'metrics-server' of Deployment 'metrics-server' should set 'resources.requests.cpu'","Namespace":"builtin.kubernetes.KSV015","Query":"data.builtin.kubernetes.KSV015.deny","Resolution":"Set 'containers[].resources.requests.cpu'.","Severity":"LOW","PrimaryURL":"https://avd.aquasec.com/misconfig/ksv015","References":["https://cloud.google.com/blog/products/containers-kubernetes/kubernetes-best-practices-resource-requests-and-limits","https://avd.aquasec.com/misconfig/ksv015"],"Status":"FAIL","Layer":{},"CauseMetadata":{"Provider":"Kubernetes","Service":"general","StartLine":132,"EndLine":140,"Code":{"Lines":[{"Number":132,"Content":" - image: rancher/metrics-server:v0.3.6","IsCause":true,"Annotation":"","Truncated":false,"FirstCause":true,"LastCause":false},{"Number":133,"Content":" imagePullPolicy: IfNotPresent","IsCause":true,"Annotation":"","Truncated":false,"FirstCause":false,"LastCause":false},{"Number":134,"Content":" name: metrics-server","IsCause":true,"Annotation":"","Truncated":false,"FirstCause":false,"LastCause":false},{"Number":135,"Content":" resources: {}","IsCause":true,"Annotation":"","Truncated":false,"FirstCause":false,"LastCause":false},{"Number":136,"Content":" terminationMessagePath: /dev/termination-log","IsCause":true,"Annotation":"","Truncated":false,"FirstCause":false,"LastCause":false},{"Number":137,"Content":" terminationMessagePolicy: File","IsCause":true,"Annotation":"","Truncated":false,"FirstCause":false,"LastCause":false},{"Number":138,"Content":" volumeMounts:","IsCause":true,"Annotation":"","Truncated":false,"FirstCause":false,"LastCause":false},{"Number":139,"Content":" - mountPath: /tmp","IsCause":true,"Annotation":"","Truncated":false,"FirstCause":false,"LastCause":false},{"Number":140,"Content":" name: tmp-dir","IsCause":true,"Annotation":"","Truncated":false,"FirstCause":false,"LastCause":true}]}}},{"Type":"Kubernetes Security Check","ID":"KSV016","AVDID":"AVD-KSV-0016","Title":"Memory requests not specified","Description":"When containers have memory requests specified, the scheduler can make better decisions about which nodes to place pods on, and how to deal with resource contention.","Message":"Container 'metrics-server' of Deployment 'metrics-server' should set 'resources.requests.memory'","Namespace":"builtin.kubernetes.KSV016","Query":"data.builtin.kubernetes.KSV016.deny","Resolution":"Set 'containers[].resources.requests.memory'.","Severity":"LOW","PrimaryURL":"https://avd.aquasec.com/misconfig/ksv016","References":["https://kubesec.io/basics/containers-resources-limits-memory/","https://avd.aquasec.com/misconfig/ksv016"],"Status":"FAIL","Layer":{},"CauseMetadata":{"Provider":"Kubernetes","Service":"general","StartLine":132,"EndLine":140,"Code":{"Lines":[{"Number":132,"Content":" - image: rancher/metrics-server:v0.3.6","IsCause":true,"Annotation":"","Truncated":false,"FirstCause":true,"LastCause":false},{"Number":133,"Content":" imagePullPolicy: IfNotPresent","IsCause":true,"Annotation":"","Truncated":false,"FirstCause":false,"LastCause":false},{"Number":134,"Content":" name: metrics-server","IsCause":true,"Annotation":"","Truncated":false,"FirstCause":false,"LastCause":false},{"Number":135,"Content":" resources: {}","IsCause":true,"Annotation":"","Truncated":false,"FirstCause":false,"LastCause":false},{"Number":136,"Content":" terminationMessagePath: /dev/termination-log","IsCause":true,"Annotation":"","Truncated":false,"FirstCause":false,"LastCause":false},{"Number":137,"Content":" terminationMessagePolicy: File","IsCause":true,"Annotation":"","Truncated":false,"FirstCause":false,"LastCause":false},{"Number":138,"Content":" volumeMounts:","IsCause":true,"Annotation":"","Truncated":false,"FirstCause":false,"LastCause":false},{"Number":139,"Content":" - mountPath: /tmp","IsCause":true,"Annotation":"","Truncated":false,"FirstCause":false,"LastCause":false},{"Number":140,"Content":" name: tmp-dir","IsCause":true,"Annotation":"","Truncated":false,"FirstCause":false,"LastCause":true}]}}},{"Type":"Kubernetes Security Check","ID":"KSV018","AVDID":"AVD-KSV-0018","Title":"Memory not limited","Description":"Enforcing memory limits prevents DoS via resource exhaustion.","Message":"Container 'metrics-server' of Deployment 'metrics-server' should set 'resources.limits.memory'","Namespace":"builtin.kubernetes.KSV018","Query":"data.builtin.kubernetes.KSV018.deny","Resolution":"Set a limit value under 'containers[].resources.limits.memory'.","Severity":"LOW","PrimaryURL":"https://avd.aquasec.com/misconfig/ksv018","References":["https://kubesec.io/basics/containers-resources-limits-memory/","https://avd.aquasec.com/misconfig/ksv018"],"Status":"FAIL","Layer":{},"CauseMetadata":{"Provider":"Kubernetes","Service":"general","StartLine":132,"EndLine":140,"Code":{"Lines":[{"Number":132,"Content":" - image: rancher/metrics-server:v0.3.6","IsCause":true,"Annotation":"","Truncated":false,"FirstCause":true,"LastCause":false},{"Number":133,"Content":" imagePullPolicy: IfNotPresent","IsCause":true,"Annotation":"","Truncated":false,"FirstCause":false,"LastCause":false},{"Number":134,"Content":" name: metrics-server","IsCause":true,"Annotation":"","Truncated":false,"FirstCause":false,"LastCause":false},{"Number":135,"Content":" resources: {}","IsCause":true,"Annotation":"","Truncated":false,"FirstCause":false,"LastCause":false},{"Number":136,"Content":" terminationMessagePath: /dev/termination-log","IsCause":true,"Annotation":"","Truncated":false,"FirstCause":false,"LastCause":false},{"Number":137,"Content":" terminationMessagePolicy: File","IsCause":true,"Annotation":"","Truncated":false,"FirstCause":false,"LastCause":false},{"Number":138,"Content":" volumeMounts:","IsCause":true,"Annotation":"","Truncated":false,"FirstCause":false,"LastCause":false},{"Number":139,"Content":" - mountPath: /tmp","IsCause":true,"Annotation":"","Truncated":false,"FirstCause":false,"LastCause":false},{"Number":140,"Content":" name: tmp-dir","IsCause":true,"Annotation":"","Truncated":false,"FirstCause":false,"LastCause":true}]}}},{"Type":"Kubernetes Security Check","ID":"KSV020","AVDID":"AVD-KSV-0020","Title":"Runs with low user ID","Description":"Force the container to run with user ID \u003e 10000 to avoid conflicts with the host’s user table.","Message":"Container 'metrics-server' of Deployment 'metrics-server' should set 'securityContext.runAsUser' \u003e 10000","Namespace":"builtin.kubernetes.KSV020","Query":"data.builtin.kubernetes.KSV020.deny","Resolution":"Set 'containers[].securityContext.runAsUser' to an integer \u003e 10000.","Severity":"LOW","PrimaryURL":"https://avd.aquasec.com/misconfig/ksv020","References":["https://kubesec.io/basics/containers-securitycontext-runasuser/","https://avd.aquasec.com/misconfig/ksv020"],"Status":"FAIL","Layer":{},"CauseMetadata":{"Provider":"Kubernetes","Service":"general","StartLine":132,"EndLine":140,"Code":{"Lines":[{"Number":132,"Content":" - image: rancher/metrics-server:v0.3.6","IsCause":true,"Annotation":"","Truncated":false,"FirstCause":true,"LastCause":false},{"Number":133,"Content":" imagePullPolicy: IfNotPresent","IsCause":true,"Annotation":"","Truncated":false,"FirstCause":false,"LastCause":false},{"Number":134,"Content":" name: metrics-server","IsCause":true,"Annotation":"","Truncated":false,"FirstCause":false,"LastCause":false},{"Number":135,"Content":" resources: {}","IsCause":true,"Annotation":"","Truncated":false,"FirstCause":false,"LastCause":false},{"Number":136,"Content":" terminationMessagePath: /dev/termination-log","IsCause":true,"Annotation":"","Truncated":false,"FirstCause":false,"LastCause":false},{"Number":137,"Content":" terminationMessagePolicy: File","IsCause":true,"Annotation":"","Truncated":false,"FirstCause":false,"LastCause":false},{"Number":138,"Content":" volumeMounts:","IsCause":true,"Annotation":"","Truncated":false,"FirstCause":false,"LastCause":false},{"Number":139,"Content":" - mountPath: /tmp","IsCause":true,"Annotation":"","Truncated":false,"FirstCause":false,"LastCause":false},{"Number":140,"Content":" name: tmp-dir","IsCause":true,"Annotation":"","Truncated":false,"FirstCause":false,"LastCause":true}]}}},{"Type":"Kubernetes Security Check","ID":"KSV021","AVDID":"AVD-KSV-0021","Title":"Runs with low group ID","Description":"Force the container to run with group ID \u003e 10000 to avoid conflicts with the host’s user table.","Message":"Container 'metrics-server' of Deployment 'metrics-server' should set 'securityContext.runAsGroup' \u003e 10000","Namespace":"builtin.kubernetes.KSV021","Query":"data.builtin.kubernetes.KSV021.deny","Resolution":"Set 'containers[].securityContext.runAsGroup' to an integer \u003e 10000.","Severity":"LOW","PrimaryURL":"https://avd.aquasec.com/misconfig/ksv021","References":["https://kubesec.io/basics/containers-securitycontext-runasuser/","https://avd.aquasec.com/misconfig/ksv021"],"Status":"FAIL","Layer":{},"CauseMetadata":{"Provider":"Kubernetes","Service":"general","StartLine":132,"EndLine":140,"Code":{"Lines":[{"Number":132,"Content":" - image: rancher/metrics-server:v0.3.6","IsCause":true,"Annotation":"","Truncated":false,"FirstCause":true,"LastCause":false},{"Number":133,"Content":" imagePullPolicy: IfNotPresent","IsCause":true,"Annotation":"","Truncated":false,"FirstCause":false,"LastCause":false},{"Number":134,"Content":" name: metrics-server","IsCause":true,"Annotation":"","Truncated":false,"FirstCause":false,"LastCause":false},{"Number":135,"Content":" resources: {}","IsCause":true,"Annotation":"","Truncated":false,"FirstCause":false,"LastCause":false},{"Number":136,"Content":" terminationMessagePath: /dev/termination-log","IsCause":true,"Annotation":"","Truncated":false,"FirstCause":false,"LastCause":false},{"Number":137,"Content":" terminationMessagePolicy: File","IsCause":true,"Annotation":"","Truncated":false,"FirstCause":false,"LastCause":false},{"Number":138,"Content":" volumeMounts:","IsCause":true,"Annotation":"","Truncated":false,"FirstCause":false,"LastCause":false},{"Number":139,"Content":" - mountPath: /tmp","IsCause":true,"Annotation":"","Truncated":false,"FirstCause":false,"LastCause":false},{"Number":140,"Content":" name: tmp-dir","IsCause":true,"Annotation":"","Truncated":false,"FirstCause":false,"LastCause":true}]}}},{"Type":"Kubernetes Security Check","ID":"KSV030","AVDID":"AVD-KSV-0030","Title":"Default Seccomp profile not set","Description":"The RuntimeDefault/Localhost seccomp profile must be required, or allow specific additional profiles.","Message":"Either Pod or Container should set 'securityContext.seccompProfile.type' to 'RuntimeDefault'","Namespace":"builtin.kubernetes.KSV030","Query":"data.builtin.kubernetes.KSV030.deny","Resolution":"Set 'spec.securityContext.seccompProfile.type', 'spec.containers[*].securityContext.seccompProfile' and 'spec.initContainers[*].securityContext.seccompProfile' to 'RuntimeDefault' or undefined.","Severity":"LOW","PrimaryURL":"https://avd.aquasec.com/misconfig/ksv030","References":["https://kubernetes.io/docs/concepts/security/pod-security-standards/#restricted","https://avd.aquasec.com/misconfig/ksv030"],"Status":"FAIL","Layer":{},"CauseMetadata":{"Provider":"Kubernetes","Service":"general","StartLine":132,"EndLine":140,"Code":{"Lines":[{"Number":132,"Content":" - image: rancher/metrics-server:v0.3.6","IsCause":true,"Annotation":"","Truncated":false,"FirstCause":true,"LastCause":false},{"Number":133,"Content":" imagePullPolicy: IfNotPresent","IsCause":true,"Annotation":"","Truncated":false,"FirstCause":false,"LastCause":false},{"Number":134,"Content":" name: metrics-server","IsCause":true,"Annotation":"","Truncated":false,"FirstCause":false,"LastCause":false},{"Number":135,"Content":" resources: {}","IsCause":true,"Annotation":"","Truncated":false,"FirstCause":false,"LastCause":false},{"Number":136,"Content":" terminationMessagePath: /dev/termination-log","IsCause":true,"Annotation":"","Truncated":false,"FirstCause":false,"LastCause":false},{"Number":137,"Content":" terminationMessagePolicy: File","IsCause":true,"Annotation":"","Truncated":false,"FirstCause":false,"LastCause":false},{"Number":138,"Content":" volumeMounts:","IsCause":true,"Annotation":"","Truncated":false,"FirstCause":false,"LastCause":false},{"Number":139,"Content":" - mountPath: /tmp","IsCause":true,"Annotation":"","Truncated":false,"FirstCause":false,"LastCause":false},{"Number":140,"Content":" name: tmp-dir","IsCause":true,"Annotation":"","Truncated":false,"FirstCause":false,"LastCause":true}]}}},{"Type":"Kubernetes Security Check","ID":"KSV037","AVDID":"AVD-KSV-0037","Title":"User Pods should not be placed in kube-system namespace","Description":"ensure that User pods are not placed in kube-system namespace","Message":"Deployment 'metrics-server' should not be set with 'kube-system' namespace","Namespace":"builtin.kubernetes.KSV037","Query":"data.builtin.kubernetes.KSV037.deny","Resolution":"Deploy the use pods into a designated namespace which is not kube-system.","Severity":"MEDIUM","PrimaryURL":"https://avd.aquasec.com/misconfig/ksv037","References":["https://kubernetes.io/docs/reference/setup-tools/kubeadm/implementation-details/","https://avd.aquasec.com/misconfig/ksv037"],"Status":"FAIL","Layer":{},"CauseMetadata":{"Provider":"Kubernetes","Service":"general","StartLine":113,"EndLine":160,"Code":{"Lines":[{"Number":113,"Content":" progressDeadlineSeconds: 600","IsCause":true,"Annotation":"","Truncated":false,"FirstCause":true,"LastCause":false},{"Number":114,"Content":" replicas: 1","IsCause":true,"Annotation":"","Truncated":false,"FirstCause":false,"LastCause":false},{"Number":115,"Content":" revisionHistoryLimit: 10","IsCause":true,"Annotation":"","Truncated":false,"FirstCause":false,"LastCause":false},{"Number":116,"Content":" selector:","IsCause":true,"Annotation":"","Truncated":false,"FirstCause":false,"LastCause":false},{"Number":117,"Content":" matchLabels:","IsCause":true,"Annotation":"","Truncated":false,"FirstCause":false,"LastCause":false},{"Number":118,"Content":" k8s-app: metrics-server","IsCause":true,"Annotation":"","Truncated":false,"FirstCause":false,"LastCause":false},{"Number":119,"Content":" strategy:","IsCause":true,"Annotation":"","Truncated":false,"FirstCause":false,"LastCause":false},{"Number":120,"Content":" rollingUpdate:","IsCause":true,"Annotation":"","Truncated":false,"FirstCause":false,"LastCause":false},{"Number":121,"Content":" maxSurge: 25%","IsCause":true,"Annotation":"","Truncated":false,"FirstCause":false,"LastCause":true},{"Number":122,"Content":"","IsCause":false,"Annotation":"","Truncated":true,"FirstCause":false,"LastCause":false}]}}},{"Type":"Kubernetes Security Check","ID":"KSV106","AVDID":"AVD-KSV-0106","Title":"Container capabilities must only include NET_BIND_SERVICE","Description":"Containers must drop ALL capabilities, and are only permitted to add back the NET_BIND_SERVICE capability.","Message":"container should drop all","Namespace":"builtin.kubernetes.KSV106","Query":"data.builtin.kubernetes.KSV106.deny","Resolution":"Set 'spec.containers[*].securityContext.capabilities.drop' to 'ALL' and only add 'NET_BIND_SERVICE' to 'spec.containers[*].securityContext.capabilities.add'.","Severity":"LOW","PrimaryURL":"https://avd.aquasec.com/misconfig/ksv106","References":["https://kubernetes.io/docs/concepts/security/pod-security-standards/#restricted","https://avd.aquasec.com/misconfig/ksv106"],"Status":"FAIL","Layer":{},"CauseMetadata":{"Provider":"Kubernetes","Service":"general","StartLine":132,"EndLine":140,"Code":{"Lines":[{"Number":132,"Content":" - image: rancher/metrics-server:v0.3.6","IsCause":true,"Annotation":"","Truncated":false,"FirstCause":true,"LastCause":false},{"Number":133,"Content":" imagePullPolicy: IfNotPresent","IsCause":true,"Annotation":"","Truncated":false,"FirstCause":false,"LastCause":false},{"Number":134,"Content":" name: metrics-server","IsCause":true,"Annotation":"","Truncated":false,"FirstCause":false,"LastCause":false},{"Number":135,"Content":" resources: {}","IsCause":true,"Annotation":"","Truncated":false,"FirstCause":false,"LastCause":false},{"Number":136,"Content":" terminationMessagePath: /dev/termination-log","IsCause":true,"Annotation":"","Truncated":false,"FirstCause":false,"LastCause":false},{"Number":137,"Content":" terminationMessagePolicy: File","IsCause":true,"Annotation":"","Truncated":false,"FirstCause":false,"LastCause":false},{"Number":138,"Content":" volumeMounts:","IsCause":true,"Annotation":"","Truncated":false,"FirstCause":false,"LastCause":false},{"Number":139,"Content":" - mountPath: /tmp","IsCause":true,"Annotation":"","Truncated":false,"FirstCause":false,"LastCause":false},{"Number":140,"Content":" name: tmp-dir","IsCause":true,"Annotation":"","Truncated":false,"FirstCause":false,"LastCause":true}]}}}]}] \ No newline at end of file diff --git a/pkg/compliance/spec/testdata/spec.yaml b/pkg/compliance/spec/testdata/spec.yaml deleted file mode 100644 index d90cdc541b..0000000000 --- a/pkg/compliance/spec/testdata/spec.yaml +++ /dev/null @@ -1,178 +0,0 @@ ---- -spec: - id: "1234" - title: nsa - description: National Security Agency - Kubernetes Hardening Guidance - related_resources : - - http://related-resource/ - version: "1.0" - controls: - - name: Non-root containers - description: 'Check that container is not running as root' - id: '1.0' - checks: - - id: AVD-KSV012 - severity: 'MEDIUM' - - name: Immutable container file systems - description: 'Check that container root file system is immutable' - id: '1.1' - checks: - - id: AVD-KSV014 - severity: 'LOW' - - name: Preventing privileged containers - description: 'Controls whether Pods can run privileged containers' - id: '1.2' - checks: - - id: AVD-KSV017 - severity: 'HIGH' - - name: Share containers process namespaces - description: 'Controls whether containers can share process namespaces' - id: '1.3' - checks: - - id: AVD-KSV008 - severity: 'HIGH' - - name: Share host process namespaces - description: 'Controls whether share host process namespaces' - id: '1.4' - checks: - - id: AVD-KSV009 - severity: 'HIGH' - - name: Use the host network - description: 'Controls whether containers can use the host network' - id: '1.5' - checks: - - id: AVD-KSV010 - severity: 'HIGH' - - name: Run with root privileges or with root group membership - description: 'Controls whether container applications can run with root privileges or with root group membership' - id: '1.6' - checks: - - id: AVD-KSV029 - severity: 'LOW' - - name: Restricts escalation to root privileges - description: 'Control check restrictions escalation to root privileges' - id: '1.7' - checks: - - id: AVD-KSV001 - severity: 'MEDIUM' - - name: Sets the SELinux context of the container - description: 'Control checks if pod sets the SELinux context of the container' - id: '1.8' - checks: - - id: AVD-KSV002 - severity: 'MEDIUM' - - name: Restrict a container's access to resources with AppArmor - description: 'Control checks the restriction of containers access to resources with AppArmor' - id: '1.9' - checks: - - id: AVD-KSV030 - severity: 'MEDIUM' - - name: Sets the seccomp profile used to sandbox containers. - description: 'Control checks the sets the seccomp profile used to sandbox containers' - id: '1.10' - checks: - - id: AVD-KSV030 - severity: 'LOW' - - name: Protecting Pod service account tokens - description: 'Control check whether disable secret token been mount ,automountServiceAccountToken: false' - id: '1.11' - checks: - - id: AVD-KSV036 - severity: 'MEDIUM' - - name: Namespace kube-system should not be used by users - description: 'Control check whether Namespace kube-system is not be used by users' - id: '1.12' - defaultStatus: 'FAIL' - checks: - - id: AVD-KSV037 - severity: 'MEDIUM' - - name: Pod and/or namespace Selectors usage - description: 'Control check validate the pod and/or namespace Selectors usage' - id: '2.0' - defaultStatus: 'FAIL' - checks: - - id: AVD-KSV038 - severity: 'MEDIUM' - - name: Use CNI plugin that supports NetworkPolicy API - description: 'Control check whether check cni plugin installed' - id: '3.0' - checks: - - id: AVD-5.3.1 - severity: 'CRITICAL' - - name: Use ResourceQuota policies to limit resources - description: 'Control check the use of ResourceQuota policy to limit aggregate resource usage within namespace' - id: '4.0' - defaultStatus: 'FAIL' - checks: - - id: "AVD-KSV040" - severity: 'MEDIUM' - - name: Use LimitRange policies to limit resources - description: 'Control check the use of LimitRange policy limit resource usage for namespaces or nodes' - id: '4.1' - defaultStatus: 'FAIL' - checks: - - id: "AVD-KSV039" - severity: 'MEDIUM' - - name: Control plan disable insecure port - description: 'Control check whether control plan disable insecure port' - id: '5.0' - checks: - - id: AVD-1.2.19 - severity: 'CRITICAL' - - name: Encrypt etcd communication - description: 'Control check whether etcd communication is encrypted' - id: '5.1' - checks: - - id: 'AVD-2.1' - severity: 'CRITICAL' - - name: Ensure kube config file permission - description: 'Control check whether kube config file permissions' - id: '6.0' - checks: - - id: AVD-4.1.3 - - id: AVD-4.1.4 - severity: 'CRITICAL' - - name: Check that encryption resource has been set - description: 'Control checks whether encryption resource has been set' - id: '6.1' - checks: - - id: AVD-1.2.31 - - id: AVD-1.2.32 - severity: 'CRITICAL' - - name: Check encryption provider - description: 'Control checks whether encryption provider has been set' - id: '6.2' - checks: - - id: AVD-1.2.3 - severity: 'CRITICAL' - - name: Make sure anonymous-auth is unset - description: 'Control checks whether anonymous-auth is unset' - id: '7.0' - checks: - - id: AVD-1.2.1 - severity: 'CRITICAL' - - name: Make sure -authorization-mode=RBAC - description: 'Control check whether RBAC permission is in use' - id: '7.1' - checks: - - id: AVD-1.2.7 - - id: AVD-1.2.8 - severity: 'CRITICAL' - - name: Audit policy is configure - description: 'Control check whether audit policy is configure' - id: '8.0' - checks: - - id: AVD-3.2.1 - severity: 'HIGH' - - name: Audit log path is configure - description: 'Control check whether audit log path is configure' - id: '8.1' - checks: - - id: AVD-1.2.22 - severity: 'MEDIUM' - - name: Audit log aging - description: 'Control check whether audit log aging is configure' - id: '8.2' - checks: - - id: AVD-1.2.23 - severity: 'MEDIUM' \ No newline at end of file diff --git a/pkg/compliance/spec/testdata/spec_dup_id.yaml b/pkg/compliance/spec/testdata/spec_dup_id.yaml deleted file mode 100644 index f5fedd2a48..0000000000 --- a/pkg/compliance/spec/testdata/spec_dup_id.yaml +++ /dev/null @@ -1,22 +0,0 @@ ---- -spec: - id: "1234" - title: nsa - description: National Security Agency - Kubernetes Hardening Guidance - related_resources : - - http://related-resource/ - version: "1.0" - controls: - - name: Non-root containers - description: 'Check that container is not running as root' - id: '1.0' - checks: - - id: AVD-KSV012 - severity: 'MEDIUM' - - name: Immutable container file systems - description: 'Check that container root file system is immutable' - id: '1.1' - checks: - - id: AVD-KSV012 - severity: 'LOW' - \ No newline at end of file diff --git a/pkg/k8s/commands/run.go b/pkg/k8s/commands/run.go index 78d562a37d..99b3df2aff 100644 --- a/pkg/k8s/commands/run.go +++ b/pkg/k8s/commands/run.go @@ -5,11 +5,8 @@ import ( "errors" "github.com/spf13/viper" - - "github.com/aquasecurity/trivy/pkg/flag" - "github.com/aquasecurity/trivy/pkg/types" - "golang.org/x/xerrors" + "gopkg.in/yaml.v3" sp "github.com/aquasecurity/defsec/pkg/spec" "github.com/aquasecurity/trivy-kubernetes/pkg/artifacts" @@ -17,9 +14,11 @@ import ( cmd "github.com/aquasecurity/trivy/pkg/commands/artifact" cr "github.com/aquasecurity/trivy/pkg/compliance/report" "github.com/aquasecurity/trivy/pkg/compliance/spec" + "github.com/aquasecurity/trivy/pkg/flag" "github.com/aquasecurity/trivy/pkg/k8s/report" "github.com/aquasecurity/trivy/pkg/k8s/scanner" "github.com/aquasecurity/trivy/pkg/log" + "github.com/aquasecurity/trivy/pkg/types" ) const ( @@ -81,15 +80,20 @@ func (r *runner) run(ctx context.Context, artifacts []*artifacts.Artifact) error }() s := scanner.NewScanner(r.cluster, runner, r.flagOpts) - var complianceSpec string + + var complianceSpec spec.ComplianceSpec // set scanners types by spec - if len(r.flagOpts.ReportOptions.Compliance) > 0 { - complianceSpec = sp.NewSpecLoader().GetSpecByName(r.flagOpts.ReportOptions.Compliance) - scannerTypes, err := spec.GetScannerTypes(complianceSpec) - if err != nil { - return err + if r.flagOpts.ReportOptions.Compliance != "" { + cs := sp.NewSpecLoader().GetSpecByName(r.flagOpts.ReportOptions.Compliance) + if err = yaml.Unmarshal([]byte(cs), &complianceSpec); err != nil { + return xerrors.Errorf("yaml unmarshal error: %w", err) } - r.flagOpts.ScanOptions.SecurityChecks = scannerTypes + + securityChecks, err := complianceSpec.SecurityChecks() + if err != nil { + return xerrors.Errorf("security check error: %w", err) + } + r.flagOpts.ScanOptions.SecurityChecks = securityChecks } rpt, err := s.Scan(ctx, artifacts) @@ -98,17 +102,16 @@ func (r *runner) run(ctx context.Context, artifacts []*artifacts.Artifact) error } if len(r.flagOpts.ReportOptions.Compliance) > 0 { - scanResults := make([]types.Results, 0) - - for _, rss := range rpt.Misconfigurations { + var scanResults []types.Results + for _, rss := range rpt.Vulnerabilities { scanResults = append(scanResults, rss.Results) } - for _, rss := range rpt.Vulnerabilities { + for _, rss := range rpt.Misconfigurations { scanResults = append(scanResults, rss.Results) } complianceReport, err := cr.BuildComplianceReport(scanResults, complianceSpec) if err != nil { - return err + return xerrors.Errorf("compliance report build error: %w", err) } return cr.Write(complianceReport, cr.Option{ Format: r.flagOpts.Format, diff --git a/pkg/types/misconfiguration.go b/pkg/types/misconfiguration.go index 5a174ae8d4..29e5828e26 100644 --- a/pkg/types/misconfiguration.go +++ b/pkg/types/misconfiguration.go @@ -39,16 +39,6 @@ const ( ) // GetID retrun misconfig ID -func (mc DetectedMisconfiguration) GetID() string { +func (mc *DetectedMisconfiguration) GetID() string { return mc.AVDID } - -// CheckType retrun misconfig check type -func (mc DetectedMisconfiguration) CheckType() string { - return "config" -} - -// CheckType retrun misconfig check pass -func (mc DetectedMisconfiguration) CheckPass() bool { - return mc.Status == StatusPassed -} diff --git a/pkg/types/vulnerability.go b/pkg/types/vulnerability.go index c66ce8fe00..b8b0057d29 100644 --- a/pkg/types/vulnerability.go +++ b/pkg/types/vulnerability.go @@ -29,6 +29,11 @@ type DetectedVulnerability struct { types.Vulnerability } +// GetID retrun Vulnerability ID +func (vuln *DetectedVulnerability) GetID() string { + return vuln.VulnerabilityID +} + // BySeverity implements sort.Interface based on the Severity field. type BySeverity []DetectedVulnerability @@ -53,18 +58,3 @@ func (v BySeverity) Less(i, j int) bool { // Swap swaps 2 vulnerability func (v BySeverity) Swap(i, j int) { v[i], v[j] = v[j], v[i] } - -// GetID retrun Vulnerability ID -func (vuln DetectedVulnerability) GetID() string { - return vuln.VulnerabilityID -} - -// CheckType retrun vulnerabilies check type -func (mc DetectedVulnerability) CheckType() string { - return "vuln" -} - -// CheckType retrun vulnerabilies check pass -func (mc DetectedVulnerability) CheckPass() bool { - return false -}