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:
- Cluster Connection – Builds a
k8s.Clusterobject using the current kube-config or a specified context. - Artifact Collection – Uses the
trivy-kuberneteslibrary to enumerate manifests and optionally deploy a node-collector Job for runtime data. - Scanner Initialization – Creates a
scanner.Scannerinpkg/k8s/scanner/scanner.gothat wraps Trivy's standard scanners. - Parallel Execution – Processes artifacts concurrently, invoking image, OS, language, and Infrastructure-as-Code (IaC) scanners as needed.
- Result Aggregation – Constructs a
k8s/report.Reportcontaining resources, findings, and summary metadata. - Output Generation – Emits results via
pkg/k8s/report/report.goin 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
clusterInfoToReportResourcesto 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-kuberneteslibrary inpkg/k8s/commandshandles Kubernetes API communication and optional node-collector deployment. - Core scanning logic in
pkg/k8s/scanner/scanner.goseparates misconfiguration checks, image vulnerability scans, and core component analysis. - All scans ultimately delegate to Trivy's standard
local.Serviceinpkg/k8s/k8s.goto ensure consistent detection rules across targets. - Output formatting in
pkg/k8s/report/report.gosupports 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:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →