Skip to content

Drift detection incorrectly detects aggregated ClusterRole/Role rules as drift #1419

@markussiebert

Description

@markussiebert

Describe the bug

When using Kubernetes RBAC aggregation (aggregationRule in ClusterRoles/Roles), helm-controller's drift detection incorrectly identifies the auto-populated rules field as drift and attempts to remove it, causing a reconciliation loop.

Steps to reproduce

  1. Deploy a HelmRelease with drift detection enabled
  2. Include a ClusterRole with aggregationRule but no rules field in the Helm chart:
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  name: my-aggregated-role
aggregationRule:
  clusterRoleSelectors:
  - matchLabels:
      rbac.example.com/aggregate: "true"
  1. Kubernetes' clusterrole-aggregation-controller automatically populates the rules field
  2. helm-controller detects drift (rules present in cluster vs. absent in chart manifest)
  3. helm-controller attempts to remove the rules via drift correction
  4. Aggregation controller immediately re-adds them
  5. Loop continues on next reconciliation

Expected behavior

helm-controller should automatically ignore the rules field during drift detection when aggregationRule is present, similar to how kustomize-controller handles this (see fluxcd/kustomize-controller#1041).

Actual behavior

Continuous drift detection and correction attempts, causing unnecessary reconciliation loops and events.

Workaround

Add an ignore rule to the HelmRelease:

spec:
  driftDetection:
    mode: enabled
    ignore:
    - paths:
      - /rules
      target:
        kind: ClusterRole

Or disable drift detection entirely for the resource with an annotation:

metadata:
  annotations:
    helm.toolkit.fluxcd.io/driftDetection: disabled

Proposed solution

Automatically ignore /rules path during drift detection when:

  • Resource kind is ClusterRole or Role
  • Resource apiVersion is rbac.authorization.k8s.io/v1
  • Resource has aggregationRule field present

This should be implemented in the Diff() function in internal/action/diff.go by dynamically adding an ignore rule for aggregated RBAC resources.

Additional context

  • Related issue in kustomize-controller: Oscillating reconciles for aggregated clusterroles kustomize-controller#1041
  • The normalization skip for ClusterRole/Role already exists in fluxcd/pkg/ssa/normalize but only prevents setting rules: null during normalization, not during drift detection comparison
  • Root cause: Kubernetes API design where the rules field lacks omitempty despite being optional when aggregationRule is used

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions