#2119·kube-bench

CNI file checks 1.1.9/1.1.10 false-FAIL on CNIs without host-local IPAM (absent /var/lib/cni/networks)

Author: lexfreiCreated Jul 6, 2026Updated Sep 4, 2026

Summary

On a node whose CNI does not use the host-local IPAM plugin (Cilium, Calico, ...), checks 1.1.9 and 1.1.10 report a FAIL that is unrelated to any real file permission or ownership problem. The audit inspects /var/lib/cni/networks, which does not exist under those CNIs, so it produces no output, and an empty use_multiple_values result is scored as a failure.

Affected checks

  • 1.1.9 "Ensure that the Container Network Interface file permissions are set to 600 or more restrictive"
  • 1.1.10 "Ensure that the Container Network Interface file ownership is set to root:root"

Audit (k3s profiles):

find /var/lib/cni/networks -type f ! -name lock 2> /dev/null | xargs --no-run-if-empty stat -c permissions=%a
find /var/lib/cni/networks -type f 2> /dev/null | xargs --no-run-if-empty stat -c %U:%G

Root cause

/var/lib/cni/networks is the state directory of the host-local IPAM plugin: one file per allocated pod IP. Only CNIs that use host-local IPAM create it — including the flannel backend that ships as the k3s default. CNIs that manage their own IPAM (Cilium, Calico, ...) never create it, so the directory is absent.

When the directory is absent, find prints nothing (the "No such file or directory" error is swallowed by 2> /dev/null), xargs --no-run-if-empty runs stat zero times, and the audit output is empty. With use_multiple_values: true an empty output means zero values to test, which the runner scores as a failure instead of a pass.

Impact differs by profile

The generic cis-* profiles keep these checks scored: false, so the empty result surfaces as WARN. Several distro profiles mark them scored: true (Automated), where the same empty result becomes a hard FAIL. So on, for example, a k3s cluster running Cilium, kube-bench reports 1.1.9 and 1.1.10 as FAIL even though there is nothing to check.

Affected profiles

Active checks that hardcode /var/lib/cni/networks and can produce this false result: k3s-cis-1.7, k3s-cis-1.8, k3s-cis-1.9 (several marked Automated), and rke-cis-1.7/1.23/1.24, rke2-cis-1.7/1.8/1.23 (mostly Manual; rke-cis-1.24 1.1.10 is Automated). The generic cis-* profiles carry the same /var/lib/cni/networks fallback but keep the checks Manual (WARN).

Already handled: k3s-cis-1.23 and k3s-cis-1.24 mark these checks type: skip; rke2-cis-1.24 1.1.10 already guards with an else echo "File not found" branch plus bin_op: or.

Reproduction

On a k3s node using Cilium:

$ sudo ls /var/lib/cni/networks
ls: cannot access '/var/lib/cni/networks': No such file or directory

$ sudo find /var/lib/cni/networks -type f ! -name lock 2>/dev/null | xargs --no-run-if-empty stat -c permissions=%a
      # (no output)

$ sudo kube-bench run --benchmark k3s-cis-1.9 --targets master | grep -E '1\.1\.(9|10) '
[FAIL] 1.1.9 Ensure that the Container Network Interface file permissions are set to 600 or more restrictive (Automated)
[FAIL] 1.1.10 Ensure that the Container Network Interface file ownership is set to root:root (Automated)

Related

  • #1669 — same FAIL symptom via the generic profile and the deprecated --cni-conf-dir kubelet flag; the /var/lib/cni/networks case is a distinct trigger.
  • #867 / #877 — silenced the "No such file or directory" stderr, but did not change the empty-output scoring.
  • #902 — a similar Calico false positive, closed as too CNI-specific.

Proposed fix

Make the audit tolerate an absent or empty /var/lib/cni/networks: when no host-local IPAM files exist, emit a passing sentinel so the check reports PASS; when files do exist, evaluate their real permissions/ownership unchanged. This keeps the checks Automated and meaningful on flannel-based clusters while removing the false positive on other CNIs. I have a patch ready.