How Trivy Kubernetes Cluster Scanning Works: Architecture and Implementation

Trivy Kubernetes cluster scanning connects to a target cluster via the trivy-kubernetes library, collects manifests and runtime data through an optional node-collector Job, and processes artifacts through a specialized scanner that delegates to Trivy's existing vulnerability, secret, and misconfiguration engines.

The trivy k8s command in the aquasecurity/trivy repository orchestrates a multi-stage pipeline that treats Kubernetes resources as scannable artifacts. This architecture bridges cluster API objects with Trivy's generic scanner to detect vulnerabilities in container images, misconfigurations in manifests, and security issues in core cluster components like the kubelet and API server.

Architecture Overview

When you execute trivy k8s, the scanner runs a six-step pipeline defined across three core packages:

  1. Cluster Connection – Builds a k8s.Cluster object using the current kube-config or a specified context.
  2. Artifact Collection – Uses the trivy-kubernetes library to enumerate manifests and optionally deploy a node-collector Job for runtime data.
  3. Scanner Initialization – Creates a scanner.Scanner in pkg/k8s/scanner/scanner.go that wraps Trivy's standard scanners.
  4. Parallel Execution – Processes artifacts concurrently, invoking image, OS, language, and Infrastructure-as-Code (IaC) scanners as needed.
  5. Result Aggregation – Constructs a k8s/report.Report containing resources, findings, and summary metadata.
  6. Output Generation – Emits results via pkg/k8s/report/report.go in JSON, table, or CycloneDX SBOM formats.

CLI Entry Point

The k8s subcommand is registered in pkg/commands/app.go. When invoked, it delegates to pkg/k8s/commands/run.go:

func Run(ctx context.Context, args []string, opts flag.Options) error {
    // build k8s.Cluster based on kube-config and optional context argument
    return k8scommands.Run(ctx, args, opts)
}

This entry point handles context parsing and passes control to the Kubernetes-specific command layer.

Cluster Initialization

In pkg/k8s/commands/run.go, Trivy constructs a k8s.Cluster interface using user-supplied options:

clusterOptions := []k8s.ClusterOption{
    k8s.WithKubeConfig(opts.K8sOptions.KubeConfig),
    k8s.WithBurst(opts.K8sOptions.Burst),
    k8s.WithQPS(opts.K8sOptions.QPS),
}
if len(args) > 0 {
    clusterOptions = append(clusterOptions, k8s.WithContext(args[0]))
}
cluster, err := k8s.GetCluster(clusterOptions...)

The resulting cluster object exposes methods like GetClusterVersion() and GetCurrentContext(), abstracting the underlying Kubernetes API interactions.

Artifact Collection

The clusterRun function in pkg/k8s/commands/cluster.go determines which artifacts to collect based on the output format and scanner flags:

Format Collection Strategy
CycloneDX ListClusterBomInfo() gathers version metadata for SBOM generation only.
JSON / Table ListArtifacts() fetches all manifests. If misconfiguration scanning is enabled and node collection is not disabled, ListArtifactAndNodeInfo() runs the node-collector Job to extract runtime data.

The node-collector is an optional short-lived Job that executes embedded command files from trivy-checks to gather kubelet versions and container runtime details directly from cluster nodes.

Scanner Implementation

The core scanning logic resides in pkg/k8s/scanner/scanner.go. The Scan method orchestrates three distinct analysis paths:

func (s *Scanner) Scan(ctx context.Context, artifactsData []*artifacts.Artifact) (report.Report, error) {
    // (a) Separate core components (ControlPlane, Node, Cluster) from regular manifests.
    // (b) Run misconfiguration scans on raw YAML/Helm manifests via s.scanMisconfigs().
    // (c) For each container image, invoke s.scanVulns() using the generic Trivy image scanner.
    // (d) Scan core components via s.scanK8sVulns() for kubelet and control-plane binary vulnerabilities.
    // (e) Assemble the final report with resources, cluster name and schema version.
}

Misconfiguration Scanning – The scanMisconfigs function writes manifests to a temporary directory and calls runner.ScanFilesystem to execute Trivy's config scanner on raw YAML.

Vulnerability Scanning – The scanVulns function iterates over container images discovered in manifests, sets opts.Target to the image reference, and calls runner.ScanImage.

Core Component Scanning – The scanK8sVulns function extracts version strings from control-plane and node components, creates pseudo-applications (ftypes.Application) with LangType: "k8s", and invokes the Kubernetes-specific scanner.

Low-Level Kubernetes Scanner

pkg/k8s/k8s.go implements a thin wrapper around Trivy's local.Scanner service:

type ScanKubernetes struct {
    localScanner local.Service
}

func (sk ScanKubernetes) Scan(ctx context.Context, target types.ScanTarget, options types.ScanOptions) (types.Results, ftypes.OS, error) {
    return sk.localScanner.ScanTarget(ctx, target, options)
}

This design ensures that core component scans reuse the same detection logic as file-system and container image scans, maintaining consistent vulnerability data across all target types.

Reporting and Output

pkg/k8s/report/report.go handles the final serialization of report.Report objects:

  • JSON – Marshals the complete report structure including all findings and resource metadata.
  • Table – Renders a human-readable summary with cluster-wide statistics.
  • CycloneDX – Uses clusterInfoToReportResources to build a Software Bill of Materials (SBOM) suitable for supply chain documentation.

Practical Usage Examples

Basic Cluster Scan

Scan the current context and display a summary table:

trivy k8s --report summary

Scan a specific context named prod-cluster and output detailed JSON results:

trivy k8s prod-cluster --format json > prod-cluster.json

Generate a CycloneDX SBOM for the entire cluster:

trivy k8s --format cyclonedx --output cluster-sbom.json

Enabling Runtime Data Collection

To scan nodes and collect runtime information (kubelet version, container runtime):

trivy k8s --include-namespaces default,kube-system \
          --node-collector-namespace trivy-node-collector \
          --node-collector-image-ref aquasec/trivy-node-collector:latest

This deploys the node-collector Job in the specified namespace to gather information unavailable through the Kubernetes API alone.

Programmatic Scanning

Import the Kubernetes commands package to scan programmatically:

import (
    "context"
    "github.com/aquasecurity/trivy/pkg/k8s/commands"
    "github.com/aquasecurity/trivy/pkg/flag"
)

func main() {
    ctx := context.Background()
    opts := flag.Options{
        ScanOptions: flag.ScanOptions{
            Scanners: types.AllScanners,
        },
        K8sOptions: flag.K8sOptions{
            KubeConfig: "/path/to/kubeconfig",
        },
    }

    if err := commands.Run(ctx, nil, opts); err != nil {
        panic(err)
    }
}

This Go implementation mirrors the CLI behavior, building the cluster connection and executing the full scanner pipeline.

Summary

  • Trivy Kubernetes cluster scanning uses a six-stage pipeline from cluster connection to final report generation.
  • The trivy-kubernetes library in pkg/k8s/commands handles Kubernetes API communication and optional node-collector deployment.
  • Core scanning logic in pkg/k8s/scanner/scanner.go separates misconfiguration checks, image vulnerability scans, and core component analysis.
  • All scans ultimately delegate to Trivy's standard local.Service in pkg/k8s/k8s.go to ensure consistent detection rules across targets.
  • Output formatting in pkg/k8s/report/report.go supports JSON, table, and CycloneDX SBOM representations.

Frequently Asked Questions

What Kubernetes resources does Trivy scan?

Trivy scans all cluster artifacts discovered through the Kubernetes API, including Pod specifications, Deployment manifests, ConfigMaps, and cluster nodes. When misconfiguration scanning is enabled, it analyzes raw YAML/Helm manifests for security issues. When vulnerability scanning is enabled, it identifies container images referenced in workloads and scans them for CVEs.

How does Trivy scan Kubernetes cluster nodes?

Trivy can scan nodes by deploying a node-collector Job inside the cluster. This Job runs on cluster nodes and executes embedded scripts from the trivy-checks repository to extract runtime data such as kubelet versions, container runtime details, and configuration file paths. You enable this by omitting the --node-collector-disable flag and optionally specifying --node-collector-image-ref.

Can Trivy generate SBOMs for Kubernetes clusters?

Yes. When you specify --format cyclonedx, Trivy generates a CycloneDX Software Bill of Materials (SBOM) representing the cluster state. In this mode, Trivy uses ListClusterBomInfo() to collect version information for core components and container images without performing full vulnerability analysis, creating a comprehensive inventory of cluster software.

What is the difference between trivy k8s and scanning individual container images?

The trivy k8s command performs contextual scanning that understands Kubernetes-specific resources and relationships. It can detect misconfigurations in manifests, scan core cluster components like the kubelet and API server that aren't container images, and correlate findings with specific cluster resources. Scanning individual images with trivy image only analyzes the image contents without Kubernetes context or infrastructure configuration.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →