Du siehst nichts, weil nichts gemessen wird — der Exporter läuft 3/3, ohne Restarts, beantwortet seine Liveness-Probe und liefert null Laufwerksmetriken. In Prometheus stehen nur smartctl_devices und smartctl_exporter_build_info. Ein grüner DaemonSet, der nichts misst: genau die Fehlerform, vor der das Caveats-Panel im Dashboard warnt.
Die Logs sagen warum — er findet alle drei Laufwerke pro Node und kann keines öffnen:
Smartctl open device: /dev/nvme0 failed: Operation not permitted
EPERM statt EACCES ist der Hinweis. Das ist die Standardaktion eines Seccomp-Profils für einen nicht gelisteten Syscall. Statt zwischen Capabilities und Seccomp zu raten, habe ich im laufenden Container /proc/1/status gelesen:
CapEff: 0000000000220000 <- Bits 17 und 21: SYS_RAWIO und SYS_ADMIN, beide wirksam
Seccomp: 2
Seccomp_filters: 1
Die Capabilities waren also nie das Problem. Das kubelet läuft mit seccompDefault: true, jeder Pod ohne eigene Angabe bekommt RuntimeDefault. SELinux habe ich auf demselben Weg ausgeschlossen: /sys/fs/selinux/enforce liest 0, also permissive.
Der Fix setzt seccompProfile: Unconfined auf dem Container. Das bleibt enger als privileged: true, das zusätzlich sämtliche Capabilities, alle Host-Geräte und Schreibzugriff auf /sys gewähren würde. Capabilities bleiben auf SYS_ADMIN und SYS_RAWIO beschränkt, keine Host-Namespaces, Read-only-Root.
Die noch engere Variante wäre ein eigenes Seccomp-Profil, das genau den ioctl erlaubt, den smartctl absetzt. Das lohnt sich, wenn diese Liste an Ausnahmen wächst — für einen Pod nicht.
Die Begründung samt Messwerten steht im Manifest, nicht nur hier, damit beim nächsten Lesen nicht wieder jemand bei den Capabilities anfängt zu suchen.
Du siehst nichts, weil nichts gemessen wird — der Exporter läuft 3/3, ohne Restarts, beantwortet seine Liveness-Probe und liefert **null Laufwerksmetriken**. In Prometheus stehen nur `smartctl_devices` und `smartctl_exporter_build_info`. Ein grüner DaemonSet, der nichts misst: genau die Fehlerform, vor der das Caveats-Panel im Dashboard warnt.
Die Logs sagen warum — er findet alle drei Laufwerke pro Node und kann keines öffnen:
```
Smartctl open device: /dev/nvme0 failed: Operation not permitted
```
**EPERM statt EACCES ist der Hinweis.** Das ist die Standardaktion eines Seccomp-Profils für einen nicht gelisteten Syscall. Statt zwischen Capabilities und Seccomp zu raten, habe ich im laufenden Container `/proc/1/status` gelesen:
```
CapEff: 0000000000220000 <- Bits 17 und 21: SYS_RAWIO und SYS_ADMIN, beide wirksam
Seccomp: 2
Seccomp_filters: 1
```
Die Capabilities waren also nie das Problem. Das kubelet läuft mit `seccompDefault: true`, jeder Pod ohne eigene Angabe bekommt RuntimeDefault. SELinux habe ich auf demselben Weg ausgeschlossen: `/sys/fs/selinux/enforce` liest `0`, also permissive.
Der Fix setzt `seccompProfile: Unconfined` auf dem Container. Das bleibt **enger als `privileged: true`**, das zusätzlich sämtliche Capabilities, alle Host-Geräte und Schreibzugriff auf `/sys` gewähren würde. Capabilities bleiben auf `SYS_ADMIN` und `SYS_RAWIO` beschränkt, keine Host-Namespaces, Read-only-Root.
Die noch engere Variante wäre ein eigenes Seccomp-Profil, das genau den ioctl erlaubt, den smartctl absetzt. Das lohnt sich, wenn diese Liste an Ausnahmen wächst — für einen Pod nicht.
Die Begründung samt Messwerten steht im Manifest, nicht nur hier, damit beim nächsten Lesen nicht wieder jemand bei den Capabilities anfängt zu suchen.
Refs #549
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
🤖Automated review — model CLI default (complexity: complex), commit 08b2fe7ef6b682f9db84a93621bc9b2be47e8a3c.
Advisory review by the review-bot pipeline. It never approves; a human merges. Push new commits to get a fresh review.
Summary
Adds seccompProfile: { type: Unconfined } to the smartctl-exporter container in kubernetes/apps/monitoring/smartctl-exporter.yaml, to fix the exporter being unable to open NVMe character devices under the kubelet's default RuntimeDefault seccomp profile. The diagnosis (EPERM despite CapEff already showing SYS_ADMIN/SYS_RAWIO effective, Seccomp: 2 with one filter loaded) is internally consistent — 0x220000 is exactly bit 17 (CAP_SYS_RAWIO) + bit 21 (CAP_SYS_ADMIN) — and the change is syntactically correct and consistent with the rest of the container's securityContext. No blocking issues.
🟡 Suggestions
kubernetes/apps/monitoring/smartctl-exporter.yaml:95-96 — This is the only manifest in the repo using seccompProfile: Unconfined; every other container (grep across kubernetes/) uses RuntimeDefault. The PR body frames Unconfined as "narrower than privileged: true," which is true for capabilities/devices//sys access, but understates one specific consequence: with CAP_SYS_ADMIN effective and no seccomp filter, the container can call syscalls like mount() that RuntimeDefault would otherwise block outright regardless of capabilities held. That combination is commonly treated as functionally close to root for container-escape purposes (e.g. remounting the read-only /dev hostPath mount, or the read-only root filesystem, as writable). Given allowPrivilegeEscalation: false and no host namespaces, the practical blast radius is still bounded, but it's worth naming explicitly in the manifest comment (which currently discusses privileged: true and device//sys access but not the mount() vector) so a future reader has the full risk picture, not just the capability count. A scoped localhostProfile allow-listing just the syscalls smartctl needs (the PR itself notes this as the tighter alternative) would close this gap if it's ever worth the maintenance cost.
Tests
No automated tests exist or are expected for this repo's Kubernetes manifests (GitOps config, not application code); the PR body documents that the fix was validated by reading live /proc/1/status state in the running container, which is the appropriate verification method here. Nothing further to add.
Recommendation
Looks reasonable — no blocking issues; comments above are optional.
🤖 **Automated review** — model `CLI default` (complexity: complex), commit `08b2fe7ef6b682f9db84a93621bc9b2be47e8a3c`.
> Advisory review by the `review-bot` pipeline. It never approves; a human merges. Push new commits to get a fresh review.
---
## Summary
Adds `seccompProfile: { type: Unconfined }` to the `smartctl-exporter` container in `kubernetes/apps/monitoring/smartctl-exporter.yaml`, to fix the exporter being unable to open NVMe character devices under the kubelet's default `RuntimeDefault` seccomp profile. The diagnosis (EPERM despite `CapEff` already showing `SYS_ADMIN`/`SYS_RAWIO` effective, `Seccomp: 2` with one filter loaded) is internally consistent — `0x220000` is exactly bit 17 (`CAP_SYS_RAWIO`) + bit 21 (`CAP_SYS_ADMIN`) — and the change is syntactically correct and consistent with the rest of the container's `securityContext`. No blocking issues.
## 🟡 Suggestions
- `kubernetes/apps/monitoring/smartctl-exporter.yaml:95-96` — This is the only manifest in the repo using `seccompProfile: Unconfined`; every other container (grep across `kubernetes/`) uses `RuntimeDefault`. The PR body frames `Unconfined` as "narrower than `privileged: true`," which is true for capabilities/devices/`/sys` access, but understates one specific consequence: with `CAP_SYS_ADMIN` effective *and* no seccomp filter, the container can call syscalls like `mount()` that `RuntimeDefault` would otherwise block outright regardless of capabilities held. That combination is commonly treated as functionally close to root for container-escape purposes (e.g. remounting the read-only `/dev` hostPath mount, or the read-only root filesystem, as writable). Given `allowPrivilegeEscalation: false` and no host namespaces, the practical blast radius is still bounded, but it's worth naming explicitly in the manifest comment (which currently discusses `privileged: true` and device/`/sys` access but not the `mount()` vector) so a future reader has the full risk picture, not just the capability count. A scoped `localhostProfile` allow-listing just the syscalls smartctl needs (the PR itself notes this as the tighter alternative) would close this gap if it's ever worth the maintenance cost.
## Tests
No automated tests exist or are expected for this repo's Kubernetes manifests (GitOps config, not application code); the PR body documents that the fix was validated by reading live `/proc/1/status` state in the running container, which is the appropriate verification method here. Nothing further to add.
## Recommendation
Looks reasonable — no blocking issues; comments above are optional.
<!-- pr-review:sha=08b2fe7ef6b682f9db84a93621bc9b2be47e8a3c -->
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Du siehst nichts, weil nichts gemessen wird — der Exporter läuft 3/3, ohne Restarts, beantwortet seine Liveness-Probe und liefert null Laufwerksmetriken. In Prometheus stehen nur
smartctl_devicesundsmartctl_exporter_build_info. Ein grüner DaemonSet, der nichts misst: genau die Fehlerform, vor der das Caveats-Panel im Dashboard warnt.Die Logs sagen warum — er findet alle drei Laufwerke pro Node und kann keines öffnen:
EPERM statt EACCES ist der Hinweis. Das ist die Standardaktion eines Seccomp-Profils für einen nicht gelisteten Syscall. Statt zwischen Capabilities und Seccomp zu raten, habe ich im laufenden Container
/proc/1/statusgelesen:Die Capabilities waren also nie das Problem. Das kubelet läuft mit
seccompDefault: true, jeder Pod ohne eigene Angabe bekommt RuntimeDefault. SELinux habe ich auf demselben Weg ausgeschlossen:/sys/fs/selinux/enforceliest0, also permissive.Der Fix setzt
seccompProfile: Unconfinedauf dem Container. Das bleibt enger alsprivileged: true, das zusätzlich sämtliche Capabilities, alle Host-Geräte und Schreibzugriff auf/sysgewähren würde. Capabilities bleiben aufSYS_ADMINundSYS_RAWIObeschränkt, keine Host-Namespaces, Read-only-Root.Die noch engere Variante wäre ein eigenes Seccomp-Profil, das genau den ioctl erlaubt, den smartctl absetzt. Das lohnt sich, wenn diese Liste an Ausnahmen wächst — für einen Pod nicht.
Die Begründung samt Messwerten steht im Manifest, nicht nur hier, damit beim nächsten Lesen nicht wieder jemand bei den Capabilities anfängt zu suchen.
Refs #549
🤖 Automated review — model
CLI default(complexity: complex), commit08b2fe7ef6b682f9db84a93621bc9b2be47e8a3c.Summary
Adds
seccompProfile: { type: Unconfined }to thesmartctl-exportercontainer inkubernetes/apps/monitoring/smartctl-exporter.yaml, to fix the exporter being unable to open NVMe character devices under the kubelet's defaultRuntimeDefaultseccomp profile. The diagnosis (EPERM despiteCapEffalready showingSYS_ADMIN/SYS_RAWIOeffective,Seccomp: 2with one filter loaded) is internally consistent —0x220000is exactly bit 17 (CAP_SYS_RAWIO) + bit 21 (CAP_SYS_ADMIN) — and the change is syntactically correct and consistent with the rest of the container'ssecurityContext. No blocking issues.🟡 Suggestions
kubernetes/apps/monitoring/smartctl-exporter.yaml:95-96— This is the only manifest in the repo usingseccompProfile: Unconfined; every other container (grep acrosskubernetes/) usesRuntimeDefault. The PR body framesUnconfinedas "narrower thanprivileged: true," which is true for capabilities/devices//sysaccess, but understates one specific consequence: withCAP_SYS_ADMINeffective and no seccomp filter, the container can call syscalls likemount()thatRuntimeDefaultwould otherwise block outright regardless of capabilities held. That combination is commonly treated as functionally close to root for container-escape purposes (e.g. remounting the read-only/devhostPath mount, or the read-only root filesystem, as writable). GivenallowPrivilegeEscalation: falseand no host namespaces, the practical blast radius is still bounded, but it's worth naming explicitly in the manifest comment (which currently discussesprivileged: trueand device//sysaccess but not themount()vector) so a future reader has the full risk picture, not just the capability count. A scopedlocalhostProfileallow-listing just the syscalls smartctl needs (the PR itself notes this as the tighter alternative) would close this gap if it's ever worth the maintenance cost.Tests
No automated tests exist or are expected for this repo's Kubernetes manifests (GitOps config, not application code); the PR body documents that the fix was validated by reading live
/proc/1/statusstate in the running container, which is the appropriate verification method here. Nothing further to add.Recommendation
Looks reasonable — no blocking issues; comments above are optional.