Skip to content

Mirror the new RBAC UI role grants onto rbacsync's ClusterRole (EV-6977) - #5234

Draft
dimitri-nicolo wants to merge 5 commits into
tigera:masterfrom
dimitri-nicolo:dimitri-EV-6977-rbacsync-role-grants
Draft

Mirror the new RBAC UI role grants onto rbacsync's ClusterRole (EV-6977)#5234
dimitri-nicolo wants to merge 5 commits into
tigera:masterfrom
dimitri-nicolo:dimitri-EV-6977-rbacsync-role-grants

Conversation

@dimitri-nicolo

@dimitri-nicolo dimitri-nicolo commented Aug 20, 2026

Copy link
Copy Markdown
Contributor

Description

Companion to calico-private#13388 (EV-6977). That PR cannot merge until this one does — draft until it has been reviewed alongside it.

calico-private adds resources to the managed calico-ui-* role catalogue to close gaps against what tigera-ui-user and tigera-network-admin already ship. Kubernetes' privilege-escalation guard only lets calico-kube-controllers create a ClusterRole granting permissions it already holds, so each of those grants has to be mirrored in rbacSyncControllerRules() — which is exactly what that function exists for, per its own doc comment.

The failure without this change is not partial. The rbacsync controller ensures cluster-context first and returns on error, so the gatewayapis grant alone would abort the whole sync cycle — tier roles and LMA roles included — with a forbidden error on every tick.

What's added

Grant Verbs Managed role that needs it
operator.tigera.io/gatewayapis get calico-ui-cluster-context
applicationlayer.projectcalico.org (6 WAF resources) full CRUD calico-ui-waf-{view,mod}
gateway.networking.k8s.io/gateways,httproutes get,list,watch calico-ui-waf-{view,mod}
apps/deployments get,list,watch calico-ui-waf-{view,mod}
policy.networking.k8s.io (3 resources) full CRUD calico-ui-admin-network-policies-{view,mod}
projectcalico.org/networks full CRUD calico-ui-egress-gateways-mod
projectcalico.org/securityeventwebhooks full CRUD calico-ui-webhooks-{view,mod}
crd.projectcalico.org/securityeventwebhooks get,list,watch calico-ui-webhooks-{view,mod}

Two of these deserve a second look:

  • networks is already granted watch,list,get by the common rules, for the node controller's IPAM syncer. The egress-gateways modify role writes it, so the read-only grant does not clear the guard. It joins the existing projectcalico.org CRUD rule next to externalnetworks.
  • The WAF and Gateway API rules already exist in KubeControllersEnterpriseCommonRules via wafRules() — but gated on gatewayAPIPresent. rbacsync needs them whenever RBAC management is enabled, independent of whether the GatewayAPI CR exists, so they are repeated in rbacSyncControllerRules() rather than leaning on that gate. Without that, the managed WAF roles would be creatable on Gateway API clusters and rejected by the escalation guard everywhere else. Open to instead widening the wafRules() gate to gatewayAPIPresent || rbacManagementEnabled if that reads better — it trades the duplication for a wider blast radius.

securityeventwebhooks moves out of the projectcalico.org-only list into its own rules now that it spans two API groups. The two groups are granted asymmetrically, mirroring the catalogue: the managed role writes through the aggregated projectcalico.org API, which validates the object, and only reads the CRD group behind it, so the escalation guard needs write on the former and reads on the latter. A test fails if the CRD group regains the write verbs.

Not needed, already held: configmaps (common rules), services including watch (base rules grant get,list,update,watch), and the three new lma.tigera.io resource names (the existing lma.tigera.io/cluster get rule is unscoped by resource name).

Testing

  • A DescribeTable asserting each new grant is present on the rendered calico-kube-controllers ClusterRole when the gate is on, one entry per resource.
  • A test that networks carries the modify verbs specifically, not just the IPAM syncer's reads.
  • A negative test that policy.networking.k8s.io — granted by nothing else in the role — is absent when the feature is off.
  • I confirmed the tests are not vacuous by reverting the gatewayapis and networks additions; both fail as intended.
  • go test ./pkg/enterprise/... passes.

Affects Calico Enterprise only, and only when RBAC management is enabled.

Release Note

None

For PR author

  • Tests for change.
  • If changing pkg/apis/, run make gen-files
  • If changing versions, run make gen-versions

calico-private adds resources to the managed calico-ui-* role catalogue to
close gaps against what tigera-ui-user and tigera-network-admin ship.
Kubernetes' privilege-escalation guard only lets calico-kube-controllers
create a ClusterRole granting permissions it already holds, so every one
of those grants has to be mirrored in rbacSyncControllerRules() or the
create is rejected.

The failure would not be partial: the rbacsync controller ensures
cluster-context first and returns on error, so the gatewayapis grant alone
would abort the whole sync cycle, tier and LMA roles included.

Added:

- operator.tigera.io/gatewayapis, joining the feature-enabled checks.
- The six applicationlayer.projectcalico.org WAF resources, and
  gateways/httproutes as their attach targets.
- apps/deployments, which the WAF configuration page displays. The base
  rules grant apps/daemonsets scoped to calico-node only.
- The three policy.networking.k8s.io admin network policy resources.
- networks with the modify verbs. The common rules already grant it
  watch/list/get for the node controller's IPAM syncer, which is not
  enough for the egress-gateways modify role.
- securityeventwebhooks under crd.projectcalico.org as well as
  projectcalico.org, moved to its own rule now that it spans two groups.

The WAF and Gateway API rules already exist in
KubeControllersEnterpriseCommonRules via wafRules(), but gated on the
GatewayAPI CR being present. rbacsync needs them whenever RBAC management
is enabled, so they are repeated here rather than relying on that gate —
otherwise the managed WAF roles are creatable on Gateway API clusters and
rejected everywhere else.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
dimitri-nicolo and others added 4 commits August 20, 2026 16:39
projectcalico/calico master added CEL validation rules to the IPPool
CRD after the last sync, so validate-gen-versions' dirty-check fails on
every PR until the copies under pkg/imports/crds/calico are refreshed.
Same content the CI regen produces; no operator code change.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The IPPool CRD synced from projectcalico/calico master carries CEL
validation rules whose estimated cost the k8s 1.31 apiserver rejects
("estimated rule cost exceeds budget by factor of more than 100x");
1.33 accepts them, and upstream calico CI applies the same CRDs on
kindest v1.35.5. Verified against real apiservers: kindest/node v1.33.0
accepts both IPPool CRD flavors and boots with the kind v0.31.0 binary
this repo pins in go.mod, while v1.31.4 reproduces the rejection.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The managed webhooks role writes securityeventwebhooks through the
aggregated projectcalico.org API only and reads the CRD group behind it,
so the escalation guard needs the write verbs on the aggregated group
and reads on the CRD group. Granting write on both handed
kube-controllers privilege the catalogue never passes on.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
calico-ui-waf-mod now patches a deployment's pod template to toggle
sidecar WAF (calico-private EV-6977), so the escalation guard requires
the rbacsync controller to hold apps/deployments patch itself, or
creating and repairing that role is rejected. Nothing else grants it:
the base rules cover apps/daemonsets only, scoped to calico-node, and
the migration role is read-only.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@dimitri-nicolo

Copy link
Copy Markdown
Contributor Author

@electricjesus there's one decision here I'd like you to sign off on. The WAF grants from wafRules() are repeated in rbacSyncControllerRules() without the GatewayAPI gate, because rbacsync needs them whenever RBAC management is enabled. As a result, kube-controllers can patch any Deployment in the cluster while the feature is on. That is what lets it create the calico-ui-waf-mod role, which grants the same verb for the sidecar WAF toggle (see tigera/calico-private#13388). Let me know if that's too broad for this service account.

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.

2 participants