Kubernetes Aggregated ClusterRole Has Empty Rules - Fix Missing Labels in CI
An aggregated ClusterRole gets its rules from other ClusterRoles whose labels match its aggregationRule.clusterRoleSelectors. If no ClusterRole carries the matching label, the aggregation controller fills it with empty rules - so it grants nothing and bound identities are Forbidden.
What this error means
A binding to an aggregated ClusterRole still yields Forbidden, and kubectl get clusterrole <name> -o yaml shows an empty (or near-empty) rules: list despite an aggregationRule. The controller found no matching member roles.
$ kubectl get clusterrole monitoring-aggregate -o jsonpath='{.rules}'; echo
[]
# aggregationRule selector: matchLabels: rbac.example.com/aggregate-to-monitoring: "true"
# but no ClusterRole carries that labelCommon causes
No member ClusterRole carries the aggregation label
The aggregated role’s selector matches a label no ClusterRole has (typo, or the member role was never created/labeled), so the controller aggregates nothing.
Editing rules directly on an aggregated role
Rules on an aggregated ClusterRole are controller-managed; hand-added rules are overwritten back to the aggregated (empty) set on the next reconcile.
How to fix it
Check the selector and member labels
kubectl get clusterrole <name> -o jsonpath='{.aggregationRule}'; echo
kubectl get clusterroles -l <aggregate-label>=trueLabel a member ClusterRole to feed the aggregate
Add the matching label to the ClusterRole(s) whose rules should be aggregated; the controller fills the aggregate automatically.
kubectl label clusterrole monitoring-reader \
rbac.example.com/aggregate-to-monitoring=trueHow to prevent it
- Define permissions in labeled member ClusterRoles, not on the aggregate.
- Keep aggregation labels and selectors consistent and in version control.
- Verify the aggregate’s
rulesis non-empty after applying member roles.