Skip to content

Commit

Permalink
BREAKING: add support for k8s disable-node-collector flag (aquasecu…
Browse files Browse the repository at this point in the history
…rity#6311)

Signed-off-by: chenk <[email protected]>
  • Loading branch information
chen-keinan authored May 2, 2024
1 parent 194a814 commit c6d5d85
Show file tree
Hide file tree
Showing 11 changed files with 114 additions and 114 deletions.
2 changes: 1 addition & 1 deletion docs/docs/references/configuration/cli/trivy_kubernetes.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,11 +34,11 @@ trivy kubernetes [flags] [CONTEXT]
--cache-ttl duration cache TTL when using redis as cache backend
--clear-cache clear image caches without scanning
--compliance string compliance report to generate (k8s-nsa,k8s-cis,k8s-pss-baseline,k8s-pss-restricted)
--components strings specify which components to scan (workload,infra) (default [workload,infra])
--config-data strings specify paths from which data for the Rego policies will be recursively loaded
--config-policy strings specify the paths to the Rego policy files or to the directories containing them, applying config files
--db-repository string OCI repository to retrieve trivy-db from (default "ghcr.io/aquasecurity/trivy-db:2")
--dependency-tree [EXPERIMENTAL] show dependency origin tree of vulnerable packages
--disable-node-collector When the flag is activated, the node-collector job will not be executed, thus skipping misconfiguration findings on the node.
--download-db-only download/update vulnerability database but don't run a scan
--download-java-db-only download/update Java index database but don't run a scan
--exclude-kinds strings indicate the kinds exclude from scanning (example: node)
Expand Down
28 changes: 10 additions & 18 deletions pkg/flag/kubernetes_flags.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,19 +15,6 @@ var (
ConfigName: "kubernetes.kubeconfig",
Usage: "specify the kubeconfig file path to use",
}
ComponentsFlag = Flag[[]string]{
Name: "components",
ConfigName: "kubernetes.components",
Default: []string{
"workload",
"infra",
},
Values: []string{
"workload",
"infra",
},
Usage: "specify which components to scan",
}
K8sVersionFlag = Flag[string]{
Name: "k8s-version",
ConfigName: "kubernetes.k8s-version",
Expand All @@ -38,6 +25,11 @@ var (
ConfigName: "kubernetes.tolerations",
Usage: "specify node-collector job tolerations (example: key1=value1:NoExecute,key2=value2:NoSchedule)",
}
DisableNodeCollector = Flag[bool]{
Name: "disable-node-collector",
ConfigName: "kubernetes.disableNodeCollector",
Usage: "When the flag is activated, the node-collector job will not be executed, thus skipping misconfiguration findings on the node.",
}
NodeCollectorNamespace = Flag[string]{
Name: "node-collector-namespace",
ConfigName: "kubernetes.node-collector.namespace",
Expand Down Expand Up @@ -97,9 +89,9 @@ var (

type K8sFlagGroup struct {
KubeConfig *Flag[string]
Components *Flag[[]string]
K8sVersion *Flag[string]
Tolerations *Flag[[]string]
DisableNodeCollector *Flag[bool]
NodeCollectorImageRef *Flag[string]
NodeCollectorNamespace *Flag[string]
ExcludeOwned *Flag[bool]
Expand All @@ -114,12 +106,12 @@ type K8sFlagGroup struct {

type K8sOptions struct {
KubeConfig string
Components []string
K8sVersion string
Tolerations []corev1.Toleration
NodeCollectorImageRef string
NodeCollectorNamespace string
ExcludeOwned bool
DisableNodeCollector bool
ExcludeNodes map[string]string
ExcludeKinds []string
IncludeKinds []string
Expand All @@ -132,9 +124,9 @@ type K8sOptions struct {
func NewK8sFlagGroup() *K8sFlagGroup {
return &K8sFlagGroup{
KubeConfig: KubeConfigFlag.Clone(),
Components: ComponentsFlag.Clone(),
K8sVersion: K8sVersionFlag.Clone(),
Tolerations: TolerationsFlag.Clone(),
DisableNodeCollector: DisableNodeCollector.Clone(),
NodeCollectorNamespace: NodeCollectorNamespace.Clone(),
ExcludeOwned: ExcludeOwned.Clone(),
ExcludeNodes: ExcludeNodes.Clone(),
Expand All @@ -155,8 +147,8 @@ func (f *K8sFlagGroup) Name() string {
func (f *K8sFlagGroup) Flags() []Flagger {
return []Flagger{
f.KubeConfig,
f.Components,
f.K8sVersion,
f.DisableNodeCollector,
f.Tolerations,
f.NodeCollectorNamespace,
f.ExcludeOwned,
Expand Down Expand Up @@ -199,9 +191,9 @@ func (f *K8sFlagGroup) ToOptions() (K8sOptions, error) {

return K8sOptions{
KubeConfig: f.KubeConfig.Value(),
Components: f.Components.Value(),
K8sVersion: f.K8sVersion.Value(),
Tolerations: tolerations,
DisableNodeCollector: f.DisableNodeCollector.Value(),
NodeCollectorNamespace: f.NodeCollectorNamespace.Value(),
ExcludeOwned: f.ExcludeOwned.Value(),
ExcludeNodes: exludeNodeLabels,
Expand Down
7 changes: 1 addition & 6 deletions pkg/flag/options.go
Original file line number Diff line number Diff line change
Expand Up @@ -360,15 +360,10 @@ func (o *Options) Align() {
}

// Vulnerability scanning is disabled by default for CycloneDX.
if o.Format == types.FormatCycloneDX && !viper.IsSet(ScannersFlag.ConfigName) && len(o.K8sOptions.Components) == 0 { // remove K8sOptions.Components validation check when vuln scan is supported for k8s report with cycloneDX
if o.Format == types.FormatCycloneDX && !viper.IsSet(ScannersFlag.ConfigName) {
log.Info(`"--format cyclonedx" disables security scanning. Specify "--scanners vuln" explicitly if you want to include vulnerabilities in the CycloneDX report.`)
o.Scanners = nil
}

if o.Format == types.FormatCycloneDX && len(o.K8sOptions.Components) > 0 {
log.Info(`"k8s with --format cyclonedx" disable security scanning`)
o.Scanners = nil
}
}

// RegistryOpts returns options for OCI registries
Expand Down
8 changes: 6 additions & 2 deletions pkg/k8s/commands/cluster.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,13 @@ package commands
import (
"context"

"golang.org/x/exp/slices"
"golang.org/x/xerrors"

k8sArtifacts "github.com/aquasecurity/trivy-kubernetes/pkg/artifacts"
"github.com/aquasecurity/trivy-kubernetes/pkg/k8s"
"github.com/aquasecurity/trivy-kubernetes/pkg/trivyk8s"
"github.com/aquasecurity/trivy/pkg/flag"
"github.com/aquasecurity/trivy/pkg/log"
"github.com/aquasecurity/trivy/pkg/types"
)

Expand All @@ -34,7 +34,7 @@ func clusterRun(ctx context.Context, opts flag.Options, cluster k8s.Cluster) err
trivyk8s.WithIncludeKinds(opts.IncludeKinds),
trivyk8s.WithExcludeOwned(opts.ExcludeOwned),
}
if opts.Scanners.AnyEnabled(types.MisconfigScanner) && slices.Contains(opts.Components, "infra") {
if opts.Scanners.AnyEnabled(types.MisconfigScanner) && !opts.DisableNodeCollector {
artifacts, err = trivyk8s.New(cluster, k8sOpts...).ListArtifactAndNodeInfo(ctx,
trivyk8s.WithScanJobNamespace(opts.NodeCollectorNamespace),
trivyk8s.WithIgnoreLabels(opts.ExcludeNodes),
Expand All @@ -53,6 +53,10 @@ func clusterRun(ctx context.Context, opts flag.Options, cluster k8s.Cluster) err
return xerrors.Errorf(`unknown format %q. Use "json" or "table" or "cyclonedx"`, opts.Format)
}

if !opts.DisableNodeCollector && !opts.Quiet {
log.InfoContext(ctx, "Node scanning is enabled")
log.InfoContext(ctx, "If you want to disable Node scanning via an in-cluster Job, please try '--disable-node-collector' to disable the Node-Collector job.")
}
runner := newRunner(opts, cluster.GetCurrentContext())
return runner.run(ctx, artifacts)
}
1 change: 0 additions & 1 deletion pkg/k8s/commands/run.go
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,6 @@ func (r *runner) run(ctx context.Context, artifacts []*k8sArtifacts.Artifact) er
Report: r.flagOpts.ReportFormat,
Output: output,
Severities: r.flagOpts.Severities,
Components: r.flagOpts.Components,
Scanners: r.flagOpts.ScanOptions.Scanners,
APIVersion: r.flagOpts.AppVersion,
}); err != nil {
Expand Down
28 changes: 12 additions & 16 deletions pkg/k8s/report/report.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,6 @@ type Option struct {
Severities []dbTypes.Severity
ColumnHeading []string
Scanners types.Scanners
Components []string
APIVersion string
}

Expand Down Expand Up @@ -134,12 +133,12 @@ type reports struct {
// - misconfiguration report
// - rbac report
// - infra checks report
func SeparateMisconfigReports(k8sReport Report, scanners types.Scanners, components []string) []reports {
func SeparateMisconfigReports(k8sReport Report, scanners types.Scanners) []reports {

var workloadMisconfig, infraMisconfig, rbacAssessment, workloadVulnerabilities, infraVulnerabilities, workloadResource []Resource
for _, resource := range k8sReport.Resources {
switch {
case vulnerabilitiesOrSecretResource(resource):
case vulnerabilitiesOrSecretResource(resource) && !infraResource(resource):
if resource.Namespace == infraNamespace || nodeInfoResource(resource) {
infraVulnerabilities = append(infraVulnerabilities, nodeKind(resource))
} else {
Expand All @@ -150,31 +149,29 @@ func SeparateMisconfigReports(k8sReport Report, scanners types.Scanners, compone
case infraResource(resource):
infraMisconfig = append(infraMisconfig, nodeKind(resource))
case scanners.Enabled(types.MisconfigScanner) &&
!rbacResource(resource) &&
slices.Contains(components, workloadComponent):
!rbacResource(resource):
workloadMisconfig = append(workloadMisconfig, resource)
}
}

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

}
infraMisconfig = append(infraMisconfig, infraVulnerabilities...)
if shouldAddToReport(scanners, components, infraComponent) {
if shouldAddToReport(scanners) {
r = append(r, reports{
Report: Report{
SchemaVersion: 0,
Expand Down Expand Up @@ -266,12 +263,11 @@ func (r Report) PrintErrors() {
}
}

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

func vulnerabilitiesOrSecretResource(resource Resource) bool {
Expand Down
42 changes: 23 additions & 19 deletions pkg/k8s/report/report_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -515,7 +515,6 @@ func Test_separateMisconfigReports(t *testing.T) {
name string
k8sReport Report
scanners types.Scanners
components []string
expectedReports []Report
}{
{
Expand All @@ -525,10 +524,6 @@ func Test_separateMisconfigReports(t *testing.T) {
types.MisconfigScanner,
types.RBACScanner,
},
components: []string{
workloadComponent,
infraComponent,
},
expectedReports: []Report{
// the order matter for the test
{
Expand All @@ -545,10 +540,6 @@ func Test_separateMisconfigReports(t *testing.T) {
name: "Config and Infra for the same resource",
k8sReport: k8sReport,
scanners: types.Scanners{types.MisconfigScanner},
components: []string{
workloadComponent,
infraComponent,
},
expectedReports: []Report{
// the order matter for the test
{
Expand All @@ -569,26 +560,39 @@ func Test_separateMisconfigReports(t *testing.T) {
},
},
{
name: "Config Report Only",
k8sReport: k8sReport,
scanners: types.Scanners{types.MisconfigScanner},
components: []string{workloadComponent},
name: "Config Report Only",
k8sReport: k8sReport,
scanners: types.Scanners{types.MisconfigScanner},
expectedReports: []Report{
{
Resources: []Resource{
{Kind: "Deployment"},
{Kind: "StatefulSet"},
},
},
{
Resources: []Resource{
{Kind: "Pod"},
},
},
},
},
{
name: "Infra Report Only",
k8sReport: k8sReport,
scanners: types.Scanners{types.MisconfigScanner},
components: []string{infraComponent},
name: "Infra Report Only",
k8sReport: k8sReport,
scanners: types.Scanners{types.MisconfigScanner},
expectedReports: []Report{
{Resources: []Resource{{Kind: "Pod"}}},
{
Resources: []Resource{
{Kind: "Deployment"},
{Kind: "StatefulSet"},
},
},
{
Resources: []Resource{
{Kind: "Pod"},
},
},
},
},

Expand All @@ -597,7 +601,7 @@ func Test_separateMisconfigReports(t *testing.T) {
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
reports := SeparateMisconfigReports(tt.k8sReport, tt.scanners, tt.components)
reports := SeparateMisconfigReports(tt.k8sReport, tt.scanners)
assert.Equal(t, len(tt.expectedReports), len(reports))

for i := range reports {
Expand Down
9 changes: 2 additions & 7 deletions pkg/k8s/report/summary.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ func NewSummaryWriter(output io.Writer, requiredSevs []dbTypes.Severity, columnH
}
}

func ColumnHeading(scanners types.Scanners, components, availableColumns []string) []string {
func ColumnHeading(scanners types.Scanners, availableColumns []string) []string {
columns := []string{
NamespaceColumn,
ResourceColumn,
Expand All @@ -47,12 +47,7 @@ func ColumnHeading(scanners types.Scanners, components, availableColumns []strin
case types.VulnerabilityScanner:
securityOptions[VulnerabilitiesColumn] = nil
case types.MisconfigScanner:
if slices.Contains(components, workloadComponent) {
securityOptions[MisconfigurationsColumn] = nil
}
if slices.Contains(components, infraComponent) {
securityOptions[MisconfigurationsColumn] = nil
}
securityOptions[MisconfigurationsColumn] = nil
case types.SecretScanner:
securityOptions[SecretsColumn] = nil
case types.RBACScanner:
Expand Down
Loading

0 comments on commit c6d5d85

Please sign in to comment.