Unresolved include directive in modules/en/pages/user-guide/scanning-nodes.adoc - include::partial$variables.adoc[]
Scanning Nodes
Overview
SUSE Security Vulnerability Scanner can scan container images through Registry configurations and workload scanning, but the security posture of a cluster also depends on the nodes themselves. Nodes run the operating system, the container runtime, the kubelet, and other system-level packages that are invisible to image-based scanners.
The Node Scan feature closes this gap. It deploys a worker on every
eligible node as a DaemonSet, scans the host filesystem, and produces a
NodeSBOM and a NodeVulnerabilityReport per node. This gives you a
comprehensive overview of node-level vulnerabilities, helping you secure
the infrastructure your workloads run on.
Under the hood, SUSE Security Vulnerability Scanner creates a NodeScanJob resource for each
matching node, on the configured schedule or on demand. The worker pod
on the node scans the host filesystem and produces a NodeSBOM (in SPDX
format) and a NodeVulnerabilityReport for that node.
Enabling Node Scan
Node scanning is inactive until you create a NodeScanConfiguration
resource. Without it, no scans run and manually created NodeScanJob
resources fail with the reason NodeScanConfigurationMissing.
To enable node scanning, apply the sample configuration from the examples folder:
kubectl apply -f https://raw.githubusercontent.com/kubewarden/sbomscanner/main/examples/nodescanconfiguration.yaml
Configuration
The NodeScanConfiguration is a cluster-scoped singleton resource named
default. It is the single entry point for controlling the node
scanning behavior, and it is required: without this resource, no node is
scanned, either on a schedule or on demand. Only one instance is
allowed.
Example configuration:
apiVersion: sbomscanner.kubewarden.io/v1alpha1
kind: NodeScanConfiguration
metadata:
name: default
spec:
scanInterval: 24h
nodeSelector:
matchExpressions:
- key: kubernetes.io/hostname
operator: In
values:
- "node1"
- "node2"
skipPatterns:
- "/run/k3s/containerd/"
platforms:
- arch: "amd64"
os: "linux"
Fields
| Field | Description | Default |
|---|---|---|
|
Enable or disable node scanning. See Disabling node scanning for details. |
|
|
How often nodes are scanned. If not specified, automatic scanning is
disabled and you must create |
- |
|
A standard Kubernetes label selector. Only nodes matching the selector are scanned. |
All nodes |
|
Gitignore-style patterns for files and directories to exclude from the
scan. Patterns ending with |
Container runtime directories |
|
Which OS/architecture combinations to scan. Each entry specifies an
|
All platforms |
Selecting which nodes to scan
Use the nodeSelector field to restrict scanning to a subset of nodes.
This is useful when some nodes do not have enough resources for scanning
or when you only want to target specific node pools.
Scan only nodes with a specific label:
spec:
nodeSelector:
matchLabels:
node-role.kubernetes.io/worker: ""
Scan specific nodes by hostname:
spec:
nodeSelector:
matchExpressions:
- key: kubernetes.io/hostname
operator: In
values:
- "worker-1"
- "worker-2"
If nodeSelector is omitted, all nodes in the cluster are scanned.
Excluding files and directories
The skipPatterns field accepts gitignore-style patterns to exclude
paths from the filesystem scan. This is useful to reduce noise or avoid
scanning sensitive or irrelevant paths.
If unset, a default list of patterns is applied that excludes container
runtime directories. See the
CRD reference
for the default list. Set skipPatterns to an empty list to scan
everything, including those directories.
spec:
skipPatterns:
- "/run/k3s/containerd/"
- "/tmp/"
- ".git/"
- "node_modules/"
- "*.min.js"
- "package-lock.json"
Patterns ending with / match directories. All other patterns match
files. Glob patterns such as **/vendor/ are supported.
Scanning specific platforms
By default, SUSE Security Vulnerability Scanner scans all nodes regardless of their platform. In clusters with mixed architectures, you can restrict scanning to specific OS/architecture combinations:
spec:
platforms:
- arch: "amd64"
os: "linux"
- arch: "arm64"
os: "linux"
Running a scan on demand
You can trigger a one-time scan by creating a NodeScanJob resource
manually. A NodeScanConfiguration must already exist in the cluster,
since the job depends on its settings (skip patterns, platforms).
apiVersion: sbomscanner.kubewarden.io/v1alpha1
kind: NodeScanJob
metadata:
name: scan-worker-1
spec:
nodeName: worker-1
Apply the job:
kubectl apply -f nodescanjob.yaml
If another NodeScanJob is already in progress for the same node, the
new job is marked as Failed with the reason ScanAlreadyInProgress.
Triggering an immediate rescan
To bypass the scan interval timer and trigger an immediate rescan of all
matching nodes, annotate the NodeScanConfiguration:
kubectl annotate nodescanconfiguration default \
sbomscanner.kubewarden.io/node-rescan-requested=true
The annotation is removed automatically after the scan jobs are created.
Monitoring scan progress
Check the status of node scan jobs:
kubectl get nodescanjobs
Example output:
NAME STATUS REASON AGE
scan-worker-1 Complete Complete 5m
scan-worker-2 InProgress InProgress 1m
Get detailed status of a specific job:
kubectl get nodescanjob scan-worker-1 -o yaml
Example status:
status:
startTime: "2026-06-01T10:00:00Z"
completionTime: "2026-06-01T10:02:30Z"
conditions:
- type: Complete
status: "True"
reason: Complete
message: "NodeScanJob completed successfully"
- type: Failed
status: "False"
reason: Complete
- type: InProgress
status: "False"
reason: Complete
- type: Scheduled
status: "False"
reason: Complete
Status conditions
Each NodeScanJob has status conditions that track the scan lifecycle:
| Status | Meaning |
|---|---|
|
The system has accepted the request and scheduled the scan. |
|
The scan is actively running on the node. |
|
The scan finished successfully. The |
|
The scan encountered a terminal error. Check the condition’s |
Common failure reasons:
| Reason | Description |
|---|---|
|
Another scan job is already running for the same node. |
|
No |
|
The target node does not match the |
|
An unexpected error occurred during the scan. |
Viewing results
NodeSBOM
Once a scan completes, a NodeSBOM resource is created containing the
Software Bill of Materials in SPDX format.
List node SBOMs:
kubectl get nodesboms
Query by node name:
kubectl get nodesboms --field-selector='nodeMetadata.name=worker-1'
Query by platform:
kubectl get nodesboms --field-selector='nodeMetadata.platform=linux/amd64'
View the full SBOM:
kubectl get nodesbom worker-node-1 -o yaml
Example output (truncated):
apiVersion: storage.sbomscanner.kubewarden.io/v1alpha1
kind: NodeSBOM
metadata:
name: worker-node-1
nodeMetadata:
name: worker-node-1
platform: linux/amd64
spdx:
spdxVersion: SPDX-2.3
dataLicense: CC0-1.0
name: worker-node-1
packages:
- name: libc6
versionInfo: 2.39-0ubuntu8.3
primaryPackagePurpose: LIBRARY
- name: containerd
versionInfo: 1.7.24-0ubuntu1~24.04.1
primaryPackagePurpose: APPLICATION
- name: kubelet
versionInfo: 1.31.2-1.1
primaryPackagePurpose: APPLICATION
NodeVulnerabilityReport
The vulnerability analysis results are stored in
NodeVulnerabilityReport resources.
List node vulnerability reports:
kubectl get nodevulnerabilityreports
Query by node name:
kubectl get nodevulnerabilityreports --field-selector='nodeMetadata.name=worker-1'
View the full report:
kubectl get nodevulnerabilityreport worker-node-1 -o yaml
Supported nodeMetadata fields
NodeSBOM and NodeVulnerabilityReport resources share a common
nodeMetadata field. These fields are useful when filtering resources
with kubectl get --field-selector.
| Field | Type | Description |
|---|---|---|
|
string |
The name of the node in the cluster. |
|
string |
The OS and CPU architecture of the node, in |
Disabling node scanning
There are two levels of disabling the feature:
Disabling at the configuration level either sets enabled: false in
the NodeScanConfiguration resource or deletes the resource entirely:
apiVersion: sbomscanner.kubewarden.io/v1alpha1
kind: NodeScanConfiguration
metadata:
name: default
spec:
enabled: false
# ...
In both cases, all NodeScanJob and NodeSBOM resources are deleted
from the cluster. NodeVulnerabilityReport resources are owned by their
NodeSBOM and are garbage collected with it. Scanning starts again when
you set enabled back to true or recreate the configuration.
Disabling at the Helm chart level prevents the reconcilers from starting entirely. No node-scan-related resources are watched or cached, which saves controller memory and avoids the extra load on the Kubernetes API. Use this when you don’t need node scanning at all:
controller:
nodeScan:
enabled: false
Pod Security Admission
To scan the host filesystem, the worker DaemonSet mounts the node root
filesystem read-only through a hostPath volume, runs as root, and adds
the DAC_READ_SEARCH capability so the scanner can traverse the entire
filesystem. These settings are rejected by both the restricted and the
baseline
Pod Security Admission
profiles. When node scanning is enabled, the namespace where
SUSE Security Vulnerability Scanner is installed cannot enforce either profile.