The module lifecycle stage: General Availability

The module has requirements for installation

The runtime map is a preview feature and is disabled by default.

The module stores behavioral models in its own built-in database instead of the cluster’s etcd. Use networked or local block devices or localpath for module data. Do not use a StorageClass based on network file storage such as NFS, S3, or CephFS.

The apiServerStorageClass parameter sets the StorageClass for security-storage. The PVC size is set by securityStoragePVCRequest (default 10 GiB).

In addition to static scanning (image vulnerabilities, configuration audit, CIS), the module can observe what each workload actually does at runtime and turn those observations into a per-workload map.

What the map contains

When enabled, a lightweight agent runs on every node and watches each container’s behaviour using eBPF — without any changes to your workloads. The observations are aggregated per workload (Deployment, DaemonSet, StatefulSet, …) into two objects:

  • ApplicationProfile — the application fingerprint: the processes a workload launches, the files it opens, and the Linux capabilities and system calls it uses.
  • NetworkNeighborhood — the network map: the inbound and outbound connections the workload makes, by peer and port.

Together they answer “what does this workload actually do, and who does it talk to?” with data observed from the running cluster rather than guessed from manifests.

Requirements

  • Node kernels must be Linux 5.4 or newer and expose BTF at /sys/kernel/btf/vmlinux (standard on current DKP node OS images).
  • The agent runs privileged with host PID access. It is scheduled on every node by default; restrict it with nodeAgent.nodeSelector if some nodes do not meet the kernel requirement. Optional nodeAgent.tolerations control scheduling on tainted nodes.

Enabling

Enable the runtime map in ModuleConfig operator-trivy:

apiVersion: deckhouse.io/v1alpha1
kind: ModuleConfig
metadata:
  name: operator-trivy
spec:
  settings:
    nodeAgent:
      enabled: true
      learningPeriod: "1h"
  version: 2

learningPeriod controls how long a workload is observed before its profile is considered complete. During this window the map keeps absorbing newly seen behaviour; afterwards the profile is finalized. Use a longer value (for example 24h) for workloads whose behaviour varies over the day.

Viewing the map

The map objects are namespaced, alongside the workloads they describe:

# Application fingerprints across the cluster
d8 k get applicationprofiles -A

# Network maps across the cluster
d8 k get networkneighborhoods -A

# Full fingerprint for one workload
d8 k get applicationprofile -n my-namespace <name> -o yaml

The recorded detail (processes, files, capabilities, connections) is only returned by a per-object get … -o yaml. A cluster-wide get applicationprofiles -A lists the objects but omits those fields for performance, so it always looks “empty” — use a named -o yaml to inspect the actual map.

Data starts appearing within a couple of minutes of a container starting; the profile keeps growing and is marked complete once its learning period elapses. Give a freshly enabled workload at least learningPeriod before expecting a complete map.

Generating least-privilege policies

Once a workload’s map is learned, the module can turn it into least-privilege policies. Enable either or both:

spec:
  settings:
    nodeAgent:
      enabled: true
      generatePolicies:
        networkPolicy: true
        seccomp: true
  version: 2

Network policies

With networkPolicy: true, a GeneratedNetworkPolicy is computed from each workload’s observed NetworkNeighborhood — a ready-to-review Kubernetes NetworkPolicy describing exactly the traffic the workload was seen to use.

d8 k get generatednetworkpolicies -A
d8 k get generatednetworkpolicy -n my-namespace <name> -o yaml

The object embeds a standard NetworkPolicy under .spec. Review it, then extract and apply it to enforce least privilege:

d8 k get generatednetworkpolicy -n my-namespace <name> \
  -o json | jq '.spec' | d8 k apply -f -

Seccomp profiles

With seccomp: true, a SeccompProfile is generated from each workload’s observed system calls.

d8 k get seccompprofiles -A
d8 k get seccompprofile -n my-namespace <name> -o yaml

Save the profile to each node’s kubelet seccomp directory (for example via the Security Profiles Operator), then reference it from the pod:

spec:
  securityContext:
    seccompProfile:
      type: Localhost
      localhostProfile: operator-trivy/<name>.json

Always review a generated policy before enforcing it. A profile only reflects behaviour seen during the learning period; rarely exercised code paths may be missing, so verify under representative load first.