fix(security): disposition the six unreachable-probe checkov findings - #3017
Conversation
CKV_K8S_8/_9 fire on three workloads that no kubelet probe can reach: two Prometheus agents bound to 127.0.0.1 with no Service, and the autoscaler capacity buffer whose pods are virtual and never instantiated. Scoped per-resource checkov.io/skip annotations naming the constraint, not a disabled check — a new probe-less workload is still flagged. Part of #2787
✅
|
CI green at this head (31 checks). The change adds scoped @coderabbitai review |
|
✅ Action performedReview finished.
|
📝 WalkthroughWalkthroughAdded Checkov skip annotations for CKV_K8S_8 and CKV_K8S_9 in the Crossplane sync exporter, OpenCost usage scraper, and Hetzner overprovisioning PodTemplate. The annotations document loopback-only listeners, remote-write-only operation, unreachable kubelet probes, and the non-instantiated nature of capacity-buffer pods. Possibly related PRs
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In
`@k8s/bases/infrastructure/coroot/components/crossplane-sync-exporter/deployment.yaml`:
- Around line 13-21: Remove the Checkov suppression annotations from the
immutable base deployments and add both exceptions to the relevant provider or
cluster Kustomize overlay patches. Apply this to
k8s/bases/infrastructure/coroot/components/crossplane-sync-exporter/deployment.yaml
lines 13-21 and
k8s/bases/infrastructure/opencost/components/usage-scraper/deployment.yaml lines
13-19; preserve the existing loopback-only rationale and annotation values in
each overlay.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Repository YAML (base), Organization UI (inherited)
Review profile: ASSERTIVE
Plan: Pro Plus
Run ID: 800c172c-6f50-4481-82c0-b1fb9c4f9282
📒 Files selected for processing (3)
k8s/bases/infrastructure/coroot/components/crossplane-sync-exporter/deployment.yamlk8s/bases/infrastructure/opencost/components/usage-scraper/deployment.yamlk8s/providers/hetzner/infrastructure/overprovisioning/pod-template.yaml
📜 Review details
🧰 Additional context used
📓 Path-based instructions (3)
k8s/**/*.yaml
📄 CodeRabbit inference engine (AGENTS.md)
k8s/**/*.yaml: Kubernetes base files underk8s/bases/are immutable; modify them through Kustomizepatches:in provider or cluster overlays.
Preserve Flux dependency order:bootstrap→infrastructure-controllers→infrastructure→apps.
Use one Kubernetes resource per file, except explicitly whitelisted vendored CDI and KubeVirt operator bundles.
Use kebab-case directories and Kind-led filenames in component folders; qualify filenames with a purpose when multiple resources share a Kind.
Before a manifest PR, run schema-aware KSail validation when available, otherwise build bothk8s/clusters/local/andk8s/clusters/prod/withkubectl kustomize; use client-side dry-run for changed individual manifests.
Files:
k8s/bases/infrastructure/coroot/components/crossplane-sync-exporter/deployment.yamlk8s/providers/hetzner/infrastructure/overprovisioning/pod-template.yamlk8s/bases/infrastructure/opencost/components/usage-scraper/deployment.yaml
**/*.{yaml,yml}
📄 CodeRabbit inference engine (AGENTS.md)
Use Conventional Commit messages and create pull requests as drafts; keep changes small and focused.
Files:
k8s/bases/infrastructure/coroot/components/crossplane-sync-exporter/deployment.yamlk8s/providers/hetzner/infrastructure/overprovisioning/pod-template.yamlk8s/bases/infrastructure/opencost/components/usage-scraper/deployment.yaml
k8s/bases/infrastructure/**/*.yaml
📄 CodeRabbit inference engine (AGENTS.md)
k8s/bases/infrastructure/**/*.yaml: Place infrastructure resources in component-first folders; split CRs into plural-Kind folders only for dependency-order or cluster-scoped/cross-cutting reasons.
FeatureFlag CRs belong in theinfrastructurelayer, never the controllers layer, because their CRD is installed by the controller.
Files:
k8s/bases/infrastructure/coroot/components/crossplane-sync-exporter/deployment.yamlk8s/bases/infrastructure/opencost/components/usage-scraper/deployment.yaml
🧠 Learnings (1)
📚 Learning: 2026-07-01T21:13:36.950Z
Learnt from: devantler
Repo: devantler-tech/platform PR: 2359
File: k8s/bases/apps/actual-budget/helm-release.yaml:62-111
Timestamp: 2026-07-01T21:13:36.950Z
Learning: When reviewing Kustomize/Helm YAML in this repo, keep the base vs provider overlay split: `k8s/bases/apps/**` and `k8s/bases/infrastructure/**` should contain each app’s full, environment-agnostic configuration (including base-level postRenderer Kustomize patches such as deployment strategy, topology spread, probes, and env injection). `k8s/providers/{docker,hetzner}/**` should only add small provider-specific deltas (e.g., `interval`, `persistence.size`) via patch files (like `k8s/providers/<provider>/apps/<app>/patches/helm-release-patch.yaml`). If configuration is identical across providers (e.g., OIDC/OAuth env vars where `${domain}` is resolved per cluster via envsubst), it belongs in the base and must not be duplicated into provider overlays.
Applied to files:
k8s/bases/infrastructure/coroot/components/crossplane-sync-exporter/deployment.yamlk8s/providers/hetzner/infrastructure/overprovisioning/pod-template.yamlk8s/bases/infrastructure/opencost/components/usage-scraper/deployment.yaml
🔇 Additional comments (1)
k8s/providers/hetzner/infrastructure/overprovisioning/pod-template.yaml (1)
38-44: LGTM!
The one actionable finding at this head is refuted with measured evidence and its thread resolved — the change touches no files, so the head is unchanged and the loop restarts here rather than on a new commit. @coderabbitai review |
|
|
Readiness — user evaluation at
|
| Ref | Failing checks | Probe checks present |
|---|---|---|
main (fe7579f0) |
18 | CKV_K8S_8 ×3, CKV_K8S_9 ×3 |
this head (d17fccaf) |
12 | none |
The delta is exactly the six unreachable-probe findings this PR dispositions — no other check class moved.
Ablation — the checks are still enabled, and the suppression is per-resource. Removing only the
two probe skips from crossplane-sync-exporter/deployment.yaml (leaving everything else untouched)
moved the count 12 → 14, and precisely CKV_K8S_9 ×1 and CKV_K8S_8 ×1 returned. So nothing was
disabled globally: an unannotated workload with an unreachable probe is still flagged. A separately
added probe-less deployment was also still flagged (31 total), confirming the same from the other
direction. Working tree restored and verified clean after both ablations.
Pentad at this head: 31/31 checks green · 0 unresolved review threads · 0 actionable review-body
findings (the one body section is 🔇 Additional comments, CodeRabbit's informational class) ·
mergeStateStatus: CLEAN · green review cr@d17fccaf3a — review object at head begins
**Actionable comments posted: 1** (positively identified, not an empty reply container) and the head
CodeRabbit status reads Review completed. That one actionable comment was resolved at 15:10Z.

Why
The Kubernetes misconfiguration backlog (#2787) is what keeps checkov and trivy reporting without
failing the build. Three of its workloads are flagged for missing liveness and readiness probes,
and none of them can be probed at all: two Prometheus agents listen on loopback only and are
scraped from inside their own pod, and the autoscaler capacity buffer's pods are virtual — the
controller simulates them and never creates one.
Adding a probe to any of the three would mean opening an admin port to the pod network that has no
consumer. That trades real attack surface for a green scanner line, which is the wrong direction.
What
Each of the three carries a scoped
checkov.io/skipannotation naming its specific constraint —never a disabled check. A new workload that genuinely forgets a probe is still flagged.
Backlog moves 18 → 12 on the repository's own CI-equivalent scan.
Part of #2787