fix(monitoring): unconfine seccomp so smartctl can open the devices
ci/woodpecker/pr/ci-manifests-test Pipeline was successful
ci/woodpecker/pr/ci-scripts-test Pipeline was successful
ci/woodpecker/pr/pr-review Pipeline was successful

The exporter deployed cleanly, ran 3/3 with no restarts, answered its liveness
probe, and produced no drive metrics at all. Only smartctl_devices and
smartctl_exporter_build_info reached Prometheus — a green DaemonSet measuring
nothing, which is the failure mode the dashboard's own caveats panel warns
about.

The logs said why: it found all three drives per node and could open none of
them, with 'Smartctl open device: /dev/nvme0 failed: Operation not permitted'.

EPERM rather than EACCES is the tell — it is the default seccomp action for a
syscall a profile does not list. Rather than guess between that and the
capabilities, I read /proc/1/status in the running container: CapEff was
0x220000, so SYS_ADMIN and SYS_RAWIO were both effective, while Seccomp was 2
with one filter loaded. The capabilities were never the problem. The kubelet
runs with seccompDefault: true, so every pod that does not say otherwise gets
RuntimeDefault.

SELinux was ruled out the same way: /sys/fs/selinux/enforce reads 0.

This stays narrower than privileged: true, which would additionally grant every
capability, all host devices and write access to /sys. The tighter option is a
custom seccomp profile allowing exactly the ioctl smartctl issues; that is worth
building if this set of exceptions ever grows, and is not worth it for one pod.

Refs #549
This commit is contained in:
2026-08-27 15:03:34 +02:00
parent 04df5da041
commit 08b2fe7ef6
@@ -75,6 +75,25 @@ spec:
capabilities:
drop: ["ALL"]
add: ["SYS_ADMIN", "SYS_RAWIO"]
# The capabilities alone are not enough, and this was measured
# rather than assumed. With the default profile the exporter found
# all three drives and could open none of them:
# "Smartctl open device: /dev/nvme0 failed: Operation not
# permitted"
# EPERM is the default seccomp action for a syscall the profile
# does not list. Reading /proc/1/status in the running container
# separated the two candidates: CapEff was 0x220000, so SYS_ADMIN
# and SYS_RAWIO were both effective — while Seccomp was 2 with one
# filter loaded. The kubelet sets seccompDefault: true, so every
# pod that does not say otherwise gets RuntimeDefault.
#
# This is still narrower than `privileged: true`, which would also
# grant every capability, all devices and write access to /sys.
# Narrowing further would mean shipping a custom seccomp profile
# that allows exactly the ioctl smartctl needs — worth doing if
# this list of exceptions ever grows, not worth it for one pod.
seccompProfile:
type: Unconfined
volumeMounts:
- name: dev
mountPath: /dev