Uh oh!
There was an error while loading. Please reload this page.
sec(chart): drop the unused watch verb from the resource-monitor ClusterRole - #780
Merged
Merged
Conversation
…terRole The last code item on backend#950. #731 narrowed this rule to the resources the image actually reads but left `watch` on both rules, and nothing watches. Every Kubernetes call in the resource-monitor image is a point read or a one-shot list — read_namespaced_pod, read_node, read_node_status, list_pod_for_all_namespaces, get_cluster_custom_object, list_namespaced_custom_object. There is no Watch(), no watch.stream, no watch=True anywhere in Node-deploy/, and the image shells out to nothing (CMD is `python /app/resource_monitor.py`; no kubectl is installed). The template's own comment already enumerated exactly this surface and never mentioned watch. Worth removing rather than shrugging at: this is a CLUSTER-scoped role, so `watch` on pods is a live streaming feed of every pod object in the cluster — other tenants' training pods included — held by an agent that only samples its own node. Same argument that removed `pods/log` under #950, one verb over. WHY IT SURVIVED, and the fix for that: resource_monitor_test.yaml pinned `resources` and left `verbs` unasserted, so the rule was narrowed on one axis while the other kept an unused grant. Both axes are asserted now, and the new test was checked against the unfixed template — re-adding `watch` fails it, so it is not vacuous. helm unittest 492 passed (was 488), helm lint clean. Refs backend#950 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
saqlainsyed007
approved these changes
Aug 21, 2026
saqlainsyed007
left a comment
Contributor
There was a problem hiding this comment.
Approving. Verified against the code:
- The trim is correct and worth doing. Every Kubernetes call in the resource-monitor image is a point read or a one-shot list (
read_namespaced_pod,read_node,read_node_status,list_pod_for_all_namespaces,get_cluster_custom_object,list_namespaced_custom_object) — noWatch(), nowatch.stream, nowatch=True, and no kubectl in the image. A cluster-scopedwatchon pods is a live feed of every pod object across all tenants, held by an agent that only samples its own node — dropping it is a real least-privilege win, the same argument that removedpods/logunder #950. - The test is mutation-proof, which is the whole point.
watchsurvived the #950 trim precisely because the suite pinnedresourcesand leftverbsopen. Now both rules assert the exact verb set andnotContains: watch— restoringwatchreddens it on both rules, so this axis can't silently regrant. Chart bump present for the drift gate.
Least-privilege on a cluster-scoped role, closed on both axes so it stays closed. LGTM.
Uh oh!
There was an error while loading. Please reload this page.
LukasWodka
commented
Aug 21, 2026
Contributor
/fr-pass |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for freeto join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
The last code item on backend#950. Refs backend#950.
Why
#731 narrowed this rule to the resources the image actually reads, but left
watchon both rules. Nothing watches.Every Kubernetes call in the resource-monitor image is a point read or a one-shot list:
""read_namespaced_pod,read_node,read_node_status,list_pod_for_all_namespacesmetrics.k8s.ioget_cluster_custom_object,list_namespaced_custom_object×2No
Watch(), nowatch.stream, nowatch=Trueanywhere inNode-deploy/, and the image shells out to nothing — its CMD ispython /app/resource_monitor.pyand no kubectl is installed. The template's own comment already enumerated exactly this surface and never mentionedwatch.Worth removing rather than shrugging at: this is a cluster-scoped role, so
watchon pods is a live streaming feed of every pod object in the cluster — other tenants' training pods included — held by an agent that only samples its own node's metrics. Same argument that removedpods/logunder #950, one verb over.Why it survived, and the fix for that
resource_monitor_test.yamlpinnedresourcesand leftverbsunasserted. The rule got narrowed on one axis while the other kept an unused grant — which is exactly how you end up doing a security trim twice.Both axes are asserted now. The new test was checked against the unfixed template: re-adding
watchfails it with- watch / +- watchon both rules, so it isn't vacuous.Verification
helm unittest ./client— 492 passed, 33 suites (was 488)helm lint ./client— cleanscripts/chart-version-guard.sh— bump present ✓["get", "list"]Chart 1.9.50 → 1.9.51.
Note on closing backend#950
This clears the last code item. What remains there is operational and not mine to do: rotating the exposed resource-monitor credential (the finding-1 token was in Datadog-scraped logs, so the fix stops future exposure but doesn't un-expose it), flipping
POD_TOKEN_REQUIRE_BOUND_CLAIMS=1once pre-#950 tokens have drained, and FR on staging. The chart-rollout bullet there is stale — develop is on 1.9.50, well past the 1.9.45 it names.🤖 Generated with Claude Code
Note
Medium Risk
Touches cluster-scoped RBAC for a node telemetry ServiceAccount. The change only drops unused
watch(least privilege), so blast radius is a failed rollout if the image actually watched, which tests and comments say it does not.Overview
Tightens the resource-monitor ClusterRole so both core and
metrics.k8s.iorules grant onlyget/list. Unused cluster-widewatchon pods/nodes is dropped (backend#950 follow-up): the agent only does point reads and one-shot lists, and a live watch would stream every pod object in the cluster.Helm unittest now asserts verbs on both rules (
get/listonly, nowatch) so an unused grant cannot return silently. Chart version 1.9.50 → 1.9.51.Reviewed by Cursor Bugbot for commit 2c638a8. Bugbot is set up for automated code reviews on this repo. Configure here.