Skip to content

fix: harden CacheRuntime controller ClusterRole to least privilege - #6071

Merged
RongGu merged 7 commits into
fluid-cloudnative:masterfrom
cheyang:fix/harden-cacheruntime-permissions
Jun 27, 2026
Merged

fix: harden CacheRuntime controller ClusterRole to least privilege#6071
RongGu merged 7 commits into
fluid-cloudnative:masterfrom
cheyang:fix/harden-cacheruntime-permissions

Conversation

@cheyang

@cheyang cheyang commented Jun 26, 2026

Copy link
Copy Markdown
Collaborator

Summary

  • Remove high-risk permissions that enable privilege escalation: clusterroles, clusterrolebindings, and serviceaccounts create/delete (unused by cache engine code)
  • Remove entire duplicate "advance stateful set resources" block: pods create/delete/patch, pods/status, events full CRUD, duplicate persistentvolumeclaims, controllerrevisions (all unused)
  • Remove native statefulsets/statefulsets/status (cache runtime uses AdvancedStatefulSet from workload.fluid.io, not native StatefulSet)
  • Tighten verbs to match actual code usage: pods to read-only, PVC remove update/patch, services remove patch, configmaps remove patch, CRDs remove create/delete
  • Add missing cacheruntimes/finalizers permission (used by controller but was absent)

Security risks addressed

Risk Resource Issue
Critical clusterroles/clusterrolebindings create/delete Enables privilege escalation — a compromised controller could grant itself cluster-admin
High serviceaccounts create/delete Combined with above, completes the escalation chain
High pods create/delete (duplicate block) Allows arbitrary pod creation/deletion beyond what the controller needs
Medium pods/status update/patch Cache engine never modifies pod status
Medium events get/list/watch/update/delete Only create/patch needed for EventRecorder
Medium controllerrevisions full CRUD Zero references in entire codebase

Test plan

  • Deploy Fluid with the updated Helm chart
  • Create a CacheRuntime CR and verify the controller reconciles successfully (master/worker/client components created)
  • Verify node labels are applied correctly for cache scheduling
  • Verify pods/exec still works for UFS mount commands
  • Delete the CacheRuntime and verify cleanup (node label removal, PV/PVC deletion) completes
  • Run existing e2e tests for CacheRuntime

🤖 Generated with Claude Code

Remove overly broad permissions that pose security risks:

- Remove clusterroles/clusterrolebindings create/delete (privilege escalation risk)
- Remove serviceaccounts create/delete (unused by cache engine)
- Remove duplicate "advance stateful set resources" block (pods create/delete,
  pods/status, events full CRUD, duplicate PVC, controllerrevisions)
- Remove native statefulsets/statefulsets/status (cache uses AdvancedStatefulSet)
- Remove cacheruntimes create/delete (controller reconciles, not creates CRDs)
- Tighten PVC verbs to get/list/watch/create/delete (no update/patch needed)
- Tighten pods to read-only (pods managed by workload controllers)
- Tighten services to remove patch (only create/delete used)
- Tighten configmaps to remove patch (only update used)
- Consolidate advancedstatefulsets/status/finalizers into single rule block
- Add cacheruntimes/finalizers (needed by controller but was missing)

Signed-off-by: cheyang <cheyang.cy@alibaba-inc.com>

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request refactors and tightens the RBAC permissions in the cache role's RBAC configuration by removing several unused resources (such as service accounts, cluster roles, pods, and persistent volume claims) and restricting verbs. The review feedback suggests further tightening these permissions to better adhere to the principle of least privilege. Specifically, it recommends separating the read-only cacheruntimeclasses from write-enabled resources, removing unused daemonsets/status permissions and unnecessary verbs for daemonsets, and removing unused subresource permissions (status and finalizers) for advancedstatefulsets.

Important

The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.

Comment on lines 86 to 100
- apiGroups:
- data.fluid.io
resources:
- cacheruntimes
- cacheruntimes/status
- cacheruntimes/finalizers
- cacheruntimeclasses
- datasets
- cacheruntimes/status
- datasets/status
verbs:
- get
- list
- watch
- create
- update
- patch

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The cacheruntimeclasses resource is a read-only reference configuration for the controller. The controller only needs to read (get, list, watch) these classes and never updates or patches them. Separating cacheruntimeclasses from the other data.fluid.io resources that require write permissions (update, patch) ensures better adherence to the principle of least privilege.

Note: Please also remember to update the corresponding kubebuilder RBAC annotations in pkg/controllers/v1alpha1/cacheruntime/cacheruntime_controller.go to keep them in sync with these tightened Helm chart permissions.

  - apiGroups:
      - data.fluid.io
    resources:
      - cacheruntimes
      - cacheruntimes/status
      - cacheruntimes/finalizers
      - datasets
      - datasets/status
    verbs:
      - get
      - list
      - watch
      - update
      - patch
  - apiGroups:
      - data.fluid.io
    resources:
      - cacheruntimeclasses
    verbs:
      - get
      - list
      - watch

Comment on lines 101 to 112
- apiGroups:
- apps
resources:
- daemonsets
- statefulsets
- daemonsets/status
- statefulsets/status
verbs:
- get
- list
- watch
- create
- update
- patch
- delete
# advance stateful set resources begin
- apiGroups:
- ""
resources:
- pods
verbs:
- get
- list
- watch
- create
- update
- patch
- delete
- apiGroups:
- ""
resources:
- pods/status
verbs:
- get
- update
- patch
- apiGroups:
- ""
resources:
- events
verbs:
- get
- list
- watch
- create
- update
- patch
- delete
- apiGroups:
- ""
resources:
- persistentvolumeclaims
verbs:
- get
- list
- watch
- create
- update
- patch
- delete

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The CacheRuntime controller only reads and creates DaemonSet workloads (via DaemonSetManager). It does not support updating/patching them (as SyncComponentSpec is explicitly not supported for DaemonSet components), and deletion is handled automatically by Kubernetes garbage collection via OwnerReferences. Additionally, the controller only reads the daemonset status as part of the main resource Get call, so the daemonsets/status subresource permission is completely unused. We can safely remove daemonsets/status and restrict the verbs to get, list, watch, and create to achieve true least privilege.

  - apiGroups:
      - apps
    resources:
      - daemonsets
    verbs:
      - get
      - list
      - watch
      - create

Comment on lines 113 to 125
- apiGroups:
- workload.fluid.io
resources:
- advancedstatefulsets
- advancedstatefulsets/status
- advancedstatefulsets/finalizers
verbs:
- get
- list
- watch
- create
- update
- patch

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The CacheRuntime controller (via AdvancedStatefulSetManager) only gets, creates, and patches the main advancedstatefulsets resource. It does not update or patch the advancedstatefulsets/status or advancedstatefulsets/finalizers subresources directly. Therefore, these subresource permissions are unused and can be safely removed to adhere to the principle of least privilege.

  - apiGroups:
      - workload.fluid.io
    resources:
      - advancedstatefulsets
    verbs:
      - get
      - list
      - watch
      - create
      - update
      - patch

- Separate cacheruntimeclasses into read-only rule (get/list/watch only)
- Remove daemonsets/status and update/delete verbs from daemonsets
  (DaemonSetManager only does get and create, no in-place update)
- Remove advancedstatefulsets/status and advancedstatefulsets/finalizers
  (controller does not update these subresources directly)

Signed-off-by: cheyang <cheyang.cy@alibaba-inc.com>

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR hardens the CacheRuntime controller RBAC in the Helm chart by removing high-risk/unneeded permissions and aligning allowed verbs/resources with the CacheRuntime controller’s actual Kubernetes API usage.

Changes:

  • Removes write access to high-risk RBAC resources and other unused permissions (e.g., clusterroles/clusterrolebindings, serviceaccounts create/delete, broad pod/event/controllerrevision access).
  • Updates the cache controller’s workload permissions to focus on AdvancedStatefulSet (workload.fluid.io) rather than native StatefulSet.
  • Adds missing subresource permissions (e.g., cacheruntimes/finalizers) and tightens verbs across several core resources.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines 30 to 34
verbs:
- get
- list
- watch
- create
Comment on lines 88 to 92
resources:
- cacheruntimes
- cacheruntimes/status
- cacheruntimes/finalizers
- cacheruntimeclasses
@codecov

codecov Bot commented Jun 26, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 64.77%. Comparing base (795a7a1) to head (bd9559d).
⚠️ Report is 1 commits behind head on master.

Additional details and impacted files
@@           Coverage Diff           @@
##           master    #6071   +/-   ##
=======================================
  Coverage   64.77%   64.77%           
=======================================
  Files         484      484           
  Lines       33892    33892           
=======================================
  Hits        21954    21954           
  Misses      10215    10215           
  Partials     1723     1723           

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

- update
- patch
- delete
# advance stateful set resources begin

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this is need for advancestatefulset controller, see the README.md in https://github.com/fluid-cloudnative/advanced-statefulset ?

- apiGroups:
- apps
resources:
- daemonsets

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As the advancestatefulset part can not be modified, daemonset should be keeped.

@cheyang
cheyang force-pushed the fix/harden-cacheruntime-permissions branch from c1f812b to 20f4053 Compare June 26, 2026 05:55
Restore permissions required by the embedded advanced-statefulset
controller (controllerrevisions, pods full CRUD, pods/status, events,
PVC update/patch, advancedstatefulsets/status and finalizers) and keep
daemonsets update/patch/status per reviewer feedback.

Also print key diagnostic logs (controller logs, runtime/dataset
describe, pod list, events) directly to CI console on e2e test failure
so issues can be diagnosed without downloading artifacts.

Signed-off-by: cheyang <cheyang@163.com>
Signed-off-by: cheyang <cheyang.cy@alibaba-inc.com>
@cheyang
cheyang requested a review from Copilot June 26, 2026 07:29
@cheyang

cheyang commented Jun 26, 2026

Copy link
Copy Markdown
Collaborator Author

/gemini review

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request updates RBAC rules in the cache role template and enhances E2E test scripts to collect and dump diagnostic logs upon test failure. Feedback on the RBAC changes highlights that the permissions for pods have been expanded to full CRUD, which contradicts the goal of tightening permissions to read-only and violates the principle of least privilege.

Important

The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.

Comment on lines 53 to +59
- get
- list
- watch
- update
- apiGroups:
- ""
resources:
- pods/exec
verbs:
- create
- update
- patch
- delete

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

security-high high

The PR description states: "Tighten verbs to match actual code usage: pods to read-only". However, the actual changes in rbac.yaml expand the pods verbs to include create, update, patch, and delete (full CRUD).

Since the CacheRuntime controller manages pods indirectly via AdvancedStatefulSet and DaemonSet, it does not need write permissions on pods directly. To adhere to the principle of least privilege and match the PR's stated goal, these verbs should be restricted to read-only (get, list, watch).

      - get
      - list
      - watch

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 5 out of 5 changed files in this pull request and generated 3 comments.

Comments suppressed due to low confidence (1)

charts/fluid/fluid/templates/role/cache/rbac.yaml:90

  • The events rule grants get/list/watch/update/delete in addition to create/patch. The controller uses an EventRecorder (Eventf), which typically only requires create and patch; there’s no code path reading or deleting Events. Tightening this reduces permissions without impacting normal recording.
      - events
    verbs:
      - get
      - list
      - watch

Comment on lines 52 to 56
verbs:
- get
- list
- watch
- update
- apiGroups:
- ""
resources:
- pods/exec
verbs:
- create
Comment on lines +63 to 67
- pods/status
verbs:
- get
- list
- watch
- update
- patch
Comment on lines +128 to 132
- apps
resources:
- persistentvolumeclaims
- controllerrevisions
verbs:
- get
- Move diagnostic collection and console log dump inside the failure
  check so successful tests skip the verbose collection entirely
- Replace bash-specific &> and &>> redirections with POSIX-compatible
  > and >> forms for shell compatibility

Signed-off-by: cheyang <cheyang@163.com>
Signed-off-by: cheyang <cheyang.cy@alibaba-inc.com>

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 9 out of 9 changed files in this pull request and generated 14 comments.

Comment on lines 55 to +59
- watch
- update
- apiGroups:
- ""
resources:
- pods/exec
verbs:
- create
- update
- patch
- delete
Comment on lines 64 to 67
verbs:
- get
- list
- watch
- update
- patch
Comment on lines 88 to 92
@@ -138,43 +92,42 @@
- update
Comment on lines 135 to 138
- create
- update
- patch
- delete

helm_get() {
run helm get all -n ${runtime_namespace} "${1}" &>"$diagnose_dir/helm-${1}.yaml"
run helm get all -n ${runtime_namespace} "${1}" >"$diagnose_dir/helm-${1}.yaml"
Comment on lines +41 to +42
run kubectl get po -owide -n ${namespace} >"$diagnose_dir/pods-${namespace}.log"
run kubectl get po -oyaml -n ${namespace} >>"$diagnose_dir/pods-${namespace}.log"

helm_get() {
run helm get all -n ${runtime_namespace} "${1}" &>"$diagnose_dir/helm-${1}.yaml"
run helm get all -n ${runtime_namespace} "${1}" >"$diagnose_dir/helm-${1}.yaml"

helm_get_runtime() {
run env HELM_DRIVER=configmap helm get all -n ${runtime_namespace} "${1}" &>"$diagnose_dir/helm-${1}.yaml"
run env HELM_DRIVER=configmap helm get all -n ${runtime_namespace} "${1}" >"$diagnose_dir/helm-${1}.yaml"
Comment on lines +41 to +42
run kubectl get po -owide -n ${namespace} >"$diagnose_dir/pods-${namespace}.log"
run kubectl get po -oyaml -n ${namespace} >>"$diagnose_dir/pods-${namespace}.log"
Comment on lines 90 to +96
function dump_env_and_clean_up() {
bash tools/diagnose-fluid-juicefs.sh collect --name $dataset_name --namespace default --collect-path ./e2e-tmp/testcase-juicefs.tgz
local exit_code=$?
if [[ $exit_code -ne 0 ]]; then
bash tools/diagnose-fluid-juicefs.sh collect --name $dataset_name --namespace default --collect-path ./e2e-tmp/testcase-juicefs.tgz
syslog "=== Diagnostic logs for failed test ==="
syslog "--- juicefsruntime-controller logs (last 100 lines) ---"
kubectl logs -n fluid-system -l control-plane=juicefsruntime-controller -c manager --tail=100 2>&1 || true
cheyang added 3 commits June 26, 2026 17:04
Verify that after deleting CacheRuntime and Dataset:
- AdvancedStatefulSet, DaemonSet, Service are garbage collected via
  OwnerReferences (validates that delete verb is not needed)
- Node labels are cleaned up by controller Shutdown
- PV/PVC are properly removed

Signed-off-by: cheyang <cheyang@163.com>
Signed-off-by: cheyang <cheyang.cy@alibaba-inc.com>
Scale worker from 1 to 2 then back to 1 to exercise:
- patch on advancedstatefulsets (controller updates replicas)
- delete on pods (advanced-statefulset controller removes excess pods)
- status reconciliation after scaling

This validates that the RBAC permissions for advancedstatefulsets
(without delete verb) and pods (with delete verb) are sufficient
for scale operations.

Signed-off-by: cheyang <cheyang@163.com>
Signed-off-by: cheyang <cheyang.cy@alibaba-inc.com>
KIND CI uses a single-node cluster where pod anti-affinity prevents
scheduling a second worker pod. Skip the scale-up/scale-down test
when fewer than 2 nodes are available.

Signed-off-by: cheyang <cheyang@163.com>
Signed-off-by: cheyang <cheyang.cy@alibaba-inc.com>

@RongGu RongGu left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

/lgtm
/approve

@RongGu RongGu left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

/lgtm
/approve

@fluid-e2e-bot

fluid-e2e-bot Bot commented Jun 27, 2026

Copy link
Copy Markdown

[APPROVALNOTIFIER] This PR is APPROVED

This pull-request has been approved by: RongGu, xliuqq

The full list of commands accepted by this bot can be found here.

The pull request process is described here

Details Needs approval from an approver in each of these files:

Approvers can indicate their approval by writing /approve in a comment
Approvers can cancel approval by writing /approve cancel in a comment

@RongGu
RongGu merged commit bf04633 into fluid-cloudnative:master Jun 27, 2026
24 checks passed
@sonarqubecloud

Copy link
Copy Markdown

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants