Skip to content

Add opt-in RBAC management UI via rbacManagement flag#4865

Open
dimitri-nicolo wants to merge 30 commits into
tigera:masterfrom
dimitri-nicolo:dimitri-PMREQ-824-rbac-mgmt
Open

Add opt-in RBAC management UI via rbacManagement flag#4865
dimitri-nicolo wants to merge 30 commits into
tigera:masterfrom
dimitri-nicolo:dimitri-PMREQ-824-rbac-mgmt

Conversation

@dimitri-nicolo

@dimitri-nicolo dimitri-nicolo commented May 26, 2026

Copy link
Copy Markdown
Contributor

Description

Type: New feature (Calico Enterprise only). Addresses PMREQ-824.

Adds an opt-in RBAC management UI feature, toggled by a new Manager.spec.rbac.ui field (Enabled | Disabled, defaults to Disabled). When enabled, the operator renders the additional RBAC and network access the UI needs to let an administrator manage role/group assignments from the Manager: maintaining a catalog of managed ClusterRoles, binding IdP groups to roles via the rbacsync controller, and resolving groups from an external LDAP/AD directory.

This should be merged because it is the operator-side enablement for the RBAC management UI; without it the UI's backend has no RBAC or egress to function. Gating on spec.rbac.ui keeps the feature — and its escalation-capable permissions — entirely dormant on clusters that don't opt in.

What the flag turns on, by layer

  • API (api/v1/manager_types.go) — new RBAC spec struct with a UI RBACUI enum field and a nil-safe Manager.RBACManagementEnabled() helper (returns false for a nil Manager or any value other than Enabled). Regenerated deepcopy and the Manager CRD.
  • Render
    • calico-manager role (pkg/render/manager.go): adds the cluster-scoped RBAC management UI rules (full CRUD on managed RBAC objects + escalation-prevention coverage for tier/resource roles), plus a namespaced Role+RoleBinding in calico-system that scopes the create/named-resource access to the IdP ConfigMap/Secrets (tigera-idp-groups, tigera-idp-ldap-config) instead of granting it cluster-wide. Sets RBAC_UI_ENABLED on the ui-apis container and opens LDAP/AD egress (389/636) when OIDC authentication is configured.
    • calico-kube-controllers (pkg/render/kubecontrollers/kube-controllers.go): enables the rbacsync controller and its RBAC only when the flag is set (dormant otherwise), and adds a namespaced Role+RoleBinding granting rbacsync read on the tigera-idp-groups ConfigMap in calico-system.
    • tigera-network-admin (pkg/render/apiserver.go): grants the bind/escalate-capable rule a network-admin needs to assign managed roles via the UI, also gated on the flag.
    • Shared escalation-prevention rules live in a new pkg/render/rbac_management.go so the manager and kube-controllers roles stay aligned (the SA writing a managed role must already hold every permission it grants, or K8s rejects the write as privilege escalation).

Why the installation and apiserver controllers read the Manager CR

The flag conceptually belongs to the Manager, but two of the resources it gates are not rendered by the manager controller:

  • The rbacsync controller runs inside calico-kube-controllers, rendered by the installation controller.
  • The tigera-network-admin ClusterRole is rendered by the apiserver controller.

So each of those controllers reads the Manager CR itself and passes a RBACManagementEnabled bool into its render config. To support this, GetManager was moved out of the manager controller into pkg/controller/utils so the apiserver and installation controllers can reuse it without importing the manager controller package. Both callers treat a missing Manager as not-found (feature off) rather than an error, and the installation controller only reads it for the enterprise variant.

Both controllers also add a watch on the Manager CR. Without it, toggling spec.rbac.ui would not re-trigger an installation/apiserver reconcile, so the rbacsync controller and the network-admin rule wouldn't appear or disappear until some unrelated event re-ran those controllers.

Per-cluster behavior

The feature is keyed off each cluster's own Manager.spec.rbac.ui, so a management cluster and a managed cluster opt in independently. Calico Enterprise evaluates a user's managed-cluster actions against that managed cluster's own RBAC (Voltron proxies the request to the managed cluster's apiserver), so the network-admin bind/escalate grant and the manager-SA rules are intentionally rendered on managed clusters too — that is where a user managing per-cluster RBAC needs them. In multi-tenant management clusters the manager-side rules and namespaced Role are not rendered (gated on !MultiTenant()).

Testing: unit tests added for all three render surfaces (manager, apiserver, kube-controllers) covering the enabled/disabled gate and the multi-tenant exclusion; make gen-files produces no drift; go build ./... and the affected pkg/render* / pkg/controller/apiserver suites pass.

Components affected: apiserver (tigera-network-admin), manager (calico-manager role + namespaced Role + network policy), kube-controllers (rbacsync), Manager CRD, installation & apiserver controllers, pkg/controller/utils.

Release Note

Added an opt-in `Manager.spec.rbacManagement.enabled` flag that enables the RBAC management UI. When enabled, the operator grants the additional RBAC and LDAP egress the UI requires; it defaults to disabled and is supported in zero-tenant management clusters only. Disabling the flag does not remove RBAC objects already created while it was enabled.

For PR author

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

For PR reviewers

A note for code reviewers - all pull requests must have the following:

  • Milestone set according to targeted release.
  • Appropriate labels:
    • kind/bug if this is a bugfix.
    • kind/enhancement if this is a a new feature.
    • enterprise if this PR applies to Calico Enterprise only.

@marvin-tigera marvin-tigera added this to the v1.43.0 milestone May 26, 2026
@dimitri-nicolo dimitri-nicolo changed the title Dimitri pmreq 824 rbac mgmt manager: add opt-in RBAC management UI via rbacManagement flag May 26, 2026
@dimitri-nicolo dimitri-nicolo changed the title manager: add opt-in RBAC management UI via rbacManagement flag Add opt-in RBAC management UI via rbacManagement flag May 26, 2026
@dimitri-nicolo dimitri-nicolo force-pushed the dimitri-PMREQ-824-rbac-mgmt branch from 504568c to 8239694 Compare May 27, 2026 00:13
@dimitri-nicolo dimitri-nicolo marked this pull request as ready for review May 27, 2026 00:33
@dimitri-nicolo dimitri-nicolo requested a review from a team as a code owner May 27, 2026 00:33
Comment thread api/v1/manager_types.go Outdated
Comment thread api/v1/manager_types.go Outdated
Comment thread pkg/controller/utils/utils.go Outdated
// that need a tenant-scoped Manager (the manager controller itself) must use
// GetManager from pkg/controller/manager. Non-manager controllers reading
// zero-tenant-only flags (e.g. spec.rbacManagement) belong here.
func GetZeroTenantManagerOrNil(ctx context.Context, c client.Client) (*operatorv1.Manager, error) {

@rene-dekker rene-dekker May 27, 2026

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.

Can't we move the GetManager func from manager_controller to the utils package and re-use it? There is no reason that apiserver should throw an error if manager is not present. We should however only fetch it when enterprise CRDs exist and we are not running in cloud.

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.

I see that you moved the func to here, but I also meant to delete this func entirely as well.

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.

I think the code is more clear if we delete this method, remove any notion of "zero tenant" from the code including comments (it's not yargon that is used today) and use the multitenant booleans explicitly at the caller. I think that will be more understandable to the average reader.

Comment thread api/v1/manager_types.go Outdated
// +optional
ManagerDeployment *ManagerDeployment `json:"managerDeployment,omitempty"`

// RBAC configures the RBAC management UI feature. Only honored in

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.

I don't think we should leak cloud (internal) implications into the API comments. Our users don't need to be aware/think about those.

Comment thread api/v1/manager_types.go Outdated
// Disabled.
// +optional
// +kubebuilder:validation:Enum=Enabled;Disabled
Mode RBACMode `json:"mode,omitempty"`

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.

What do you think of the following field names?

  • Management: Enabled|Disabled
  • UI: Enabled|Disabled

or values: Visible | Hidden

@dimitri-nicolo dimitri-nicolo force-pushed the dimitri-PMREQ-824-rbac-mgmt branch from b9493a6 to 94159c6 Compare May 28, 2026 21:53

// RBAC management UI: when enabled on the Manager CR, the rbacsync
// controller runs inside calico-kube-controllers to reconcile the
// catalog of managed ClusterRoles (per-tier + 32 fine-grained + 6

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.

nit: This number is not likely to hold up over time, best to keep the comment succinct.

@rene-dekker

rene-dekker commented May 28, 2026

Copy link
Copy Markdown
Member

General comment: the AI generated comments in this code are a bit excessive. An extreme example may be the permissions. The func explains in comments twice which permissions are added + the code to add them. They are making the code less readable. And now we need to also keep the comments up to date when we add more. The operator code is not super complicated, I'd much rather have comments be only used if it adds critical information you couldn't get from simply reading the code (or have your ai read it for you).

Comment thread pkg/render/manager.go Outdated
},
// Escalation coverage for webhook-mod resource roles (create/patch on
// Secrets to wire up webhook auth).
rbacv1.PolicyRule{

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.

Could we be more specific with secrets and configmaps and bind them to the namespaces we actually need?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

The named-resource access moved to a new Role + RoleBinding in calico-system, where tigera-idp-groups and tigera-idp-ldap-config actually live. The broad create is bound to that one namespace now.

Dropped the tigera-known-oidc-users rule (it lives in tigera-elasticsearch and is already granted by logstorage.go), and tightened the activation gate to !Tenant.MultiTenant() since the IdP resources are pinned to calico-system and the RBAC UI is zero-tenant-only anyway.

Is that what you meant by "bind them to the namespaces we actually need" — or were you pointing at something narrower?

Comment thread pkg/render/manager.go Outdated
@dimitri-nicolo dimitri-nicolo force-pushed the dimitri-PMREQ-824-rbac-mgmt branch from 8833288 to 2b749da Compare May 29, 2026 22:19
Comment thread pkg/render/rbac_management.go Outdated
// management UI's directory cache and the cascading cleanup of managed
// bindings when a group is removed).
{
APIGroups: []string{""},

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.

This one should be in a role.

@radTuti radTuti modified the milestones: v1.43.0, v1.44.0 Jun 12, 2026
@dimitri-nicolo dimitri-nicolo force-pushed the dimitri-PMREQ-824-rbac-mgmt branch from 2b749da to 6af6ea3 Compare June 18, 2026 21:04
return reconcile.Result{}, err
}

if instance.Spec.Variant.IsEnterprise() {

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.

Wondering if you found the variant check to be necessary here?

rbacv1.PolicyRule{
APIGroups: []string{"rbac.authorization.k8s.io"},
Resources: []string{"clusterroles", "clusterrolebindings"},
Verbs: []string{"escalate", "bind"},

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.

Is it possible to avoid giving escalate and bind privileges? It essentially means that this controller can become a superuser if it chooses to be (i.e. is compromised)

Comment thread pkg/render/apiserver.go Outdated
rules = append(rules, rbacv1.PolicyRule{
APIGroups: []string{"rbac.authorization.k8s.io"},
Resources: []string{"clusterroles", "roles", "clusterrolebindings", "rolebindings"},
Verbs: []string{"get", "list", "watch", "create", "update", "patch", "delete", "bind", "escalate"},

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.

Similar to previous comment - can we avoid bind and escalate? This one seems a bit more serious since it is given to users

rbacv1.PolicyRule{
APIGroups: []string{""},
Resources: []string{"configmaps"},
ResourceNames: []string{"tigera-known-oidc-users"},

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.

Does this controller access this config map? I thought only the ui-apis endpoint would consult this config map when listing users

Comment thread pkg/render/manager.go Outdated
// UI adds to calico-manager-role. Named-resource access is scoped separately
// on rbacManagementUINamespacedRole.
func rbacManagementUIRules() []rbacv1.PolicyRule {
rules := RBACManagementEscalationRules()

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.

Does the manager use its own SA when creating RBAC via the UI? Or is it impersonating the user?

Comment thread pkg/render/manager.go Outdated
})
}

if c.cfg.Manager.RBACManagementEnabled() && c.cfg.Authentication != nil && c.cfg.Authentication.Spec.OIDC != nil {

@pasanw pasanw Jun 24, 2026

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.

Why do we gate on OIDC being enabled? I'm wondering what that has do to with the user deciding they want to do an LDAP sync for RBAC UI.

To me I would have expected that this block conditionally renders depending on whether the LDAP secret is placed by the user, and that we could parse the LDAP URL to scope the network policy (we do a similar thing for guardian policy)

dimitri-nicolo added a commit to dimitri-nicolo/operator that referenced this pull request Jun 26, 2026
…ileges (PR tigera#4865 review)

Addresses Pasan's review comment on the tigera-network-admin escalate/bind grant.
The RBAC management UI must never let an admin grant more than they already hold,
so this grants NO escalate and NO bind.

ui-apis performs the /team/* RBAC writes by impersonating the calling user, so the
kube-apiserver runs its privilege-escalation check against the admin's own
permissions. Without escalate/bind that means: an admin can assign a calico-ui-
role to a group only if they personally hold every rule in it, and can edit a role
only if they already hold its rules — otherwise the apiserver returns 403. The UI
is a convenience layer over the user's own privileges, not an amplifier; deciding
which admins may delegate which capabilities is then a matter of what those admins
are granted, under the operator's control.

The grant is also narrowed to what the handlers actually do (verified against the
/team/* implementation): roles are read-only (the UI lists/inspects the catalog,
never authors roles); clusterrolebindings get create/update/delete for group and
member writes; rolebindings are never created (only cluster-scoped groups are), so
they get update/delete only. Gated behind the RBAC-UI feature flag.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
dimitri-nicolo added a commit to dimitri-nicolo/operator that referenced this pull request Jun 26, 2026
…issions instead (PR tigera#4865 review)

Addresses Pasan's review comment that the rbacsync controller can become a
superuser if compromised, via cluster-wide escalate/bind on RBAC objects.

The verbs aren't actually needed: rbacSyncControllerRules already grants the SA
the full permission set the calico-ui- roles contain (RBACManagementEscalationRules),
so it satisfies Kubernetes' privilege-escalation check by *holding* the rules it
writes, rather than by escalate/bind. Removing the verbs means a compromised SA
can only assign permissions it already has — it cannot mint an arbitrary
cluster-admin role.

This relies on RBACManagementEscalationRules staying a superset of the managed
roles' contents (which live in calico/kube-controllers). That drift risk is
accepted here and is better caught by E2Es than guarded by a standing escalate
grant.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
dimitri-nicolo and others added 9 commits June 30, 2026 11:44
…review)

Reviewer noted that a field named `rbac` reads as configuration for the
Manager's K8s RBAC rather than the RBAC management UI feature. Rename the
top-level field and its type from `RBAC`/`spec.rbac` to `RBACUI`/`spec.rbacUI`,
and the inner toggle from `ui` to `enabled` (a named `Enabled`/`Disabled`
enum), so the API reads as `spec.rbacUI.enabled: Enabled|Disabled`. Keeping
the wrapper struct leaves room for future RBAC-UI sub-configuration.

Updates the RBACManagementEnabled() helper, the render unit tests, and the
regenerated deepcopy and Manager CRD.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
… as an error (PR tigera#4865 review)

Two related review points on how callers read the Manager CR:

- GetManager now swallows IsNotFound and returns (nil, nil), matching the
  sibling GetManagementCluster helper, so callers branch on a nil instance
  instead of inspecting the error.
- A NoMatchError (the Manager CRD is not registered yet) is propagated
  rather than treated as not-found. In enterprise the CRD is expected;
  hitting NoMatchError means it has not loaded yet, and we cannot infer the
  user's intent, so the installation and apiserver controllers now degrade
  and requeue instead of assuming the RBAC management UI is off.

Callers simplified accordingly; the manager controller branches on
`instance == nil` for the not-found path, and its unit test now asserts the
(nil, nil) contract.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…nt its rules (PR tigera#4865 review)

Addresses two review points on the rbacsync controller RBAC:

- Scope down the secrets rule: the controller's cluster-scoped
  `secrets: get/create/patch` is replaced by named/namespaced access in
  the existing rbacSyncIDPGroupsRole (calico-system) -- named get/patch on
  the tigera-idp-ldap-config secret, with create kept broad within the
  namespace since create cannot be name-scoped.
- Comment the remaining cluster-scoped rules (compliances read, pods list
  for leader election) and document why the escalation rules belong on this
  SA: rbacsync acts as its own identity, unlike the UI which impersonates
  the user, so it must hold every permission it grants.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…ments (PR tigera#4865 review)

The RBAC management UI is rendered on every management cluster except
multi-tenant ones (the gate is `!Tenant.MultiTenant()`, which covers both
the zero-tenant and single-tenant cases). Word the manager cluster-role gate
comment and the manager controller LDAP egress comment to match that gate
rather than naming a single tenancy mode. Leaves the pre-existing generic
tenancy-mode descriptions untouched.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…urces (PR tigera#4865 review)

The calico-system Role for the RBAC management UI carried a broad
`secrets: patch` rule. Reviewer noted patch can take a resource name, so
fold patch into the two named-resource rules (tigera-idp-ldap-config and
tigera-idp-groups) instead. The create rule stays broad within the
namespace, since create cannot be scoped to a not-yet-existing object.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…mpliances:get (PR tigera#4865 review)

rbacManagementUIRules added the shared RBACManagementEscalationRules to the
calico-manager cluster role. Reviewer pointed out the RBAC management UI
writes managed RBAC objects via user impersonation (Voltron impersonates
the caller), so the privilege-escalation check runs against the impersonated
user, not the manager SA -- making those rules dead weight on this SA. The
escalation rules remain on the rbacsync controller SA, which acts as its own
identity. The manager SA keeps only the compliances:get rule that ui-apis
itself consumes.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…igera#4865 review)

This case asserted that OIDC being configured does not by itself open LDAP
egress. Now that the egress gate keys solely on the LDAP config secret (not
on Authentication.Spec.OIDC), the oidc input is irrelevant and the case
duplicates the "secret absent" test directly above it. Reviewer noted it is
not really a regression case; remove it.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…tigera#4865 review)

The ui-apis RBAC_UI_ENABLED env was set from Manager.RBACManagementEnabled()
alone, but every resource backing the feature is gated on
`enabled && !MultiTenant()`. On a multi-tenant management cluster the
container would advertise the feature with no supporting RBAC behind it.
Gate the env value the same way so the backing resources exist whenever
ui-apis reports the feature on.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Sync the bundled CRDs with the current projectcalico/calico and
tigera/calico-private master sources via `make gen-versions`. Upstream
dropped the deprecated `preserveUnknownFields: false` field from the CRDs
and updated felixconfigurations/ipamblocks schemas; this regenerates the
bundle to match so `make validate-gen-versions` / dirty-check passes.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Comment thread api/v1/manager_types.go Outdated
// Disabled.
// +optional
// +kubebuilder:validation:Enum=Enabled;Disabled
Enabled RBACUIStatus `json:"enabled,omitempty"`

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.

Suggested change
Enabled RBACUIStatus `json:"enabled,omitempty"`
Type *RBACUIType `json:"rbacUI,omitempty"`

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

What about the following options:

// RBACUI configures the RBAC management UI.
type RBACUI struct {
	// Type selects the RBAC management UI mode. Unmanaged leaves Calico
	// Enterprise RBAC to be configured manually; ManagedCalicoEnterpriseRBAC
	// enables the RBAC management UI for Calico Enterprise RBAC. Defaults to
	// Unmanaged.
	// +optional
	// +kubebuilder:validation:Enum=Unmanaged;ManagedCalicoEnterpriseRBAC
	Type *RBACUIType `json:"type,omitempty"`
}

// RBACUIType selects the RBAC management UI mode.
type RBACUIType string

const (
	// RBACUIUnmanaged leaves RBAC to be configured manually.
	RBACUIUnmanaged RBACUIType = "Unmanaged"
	// RBACUIManagedCalicoEnterpriseRBAC enables the RBAC management UI for
	// Calico Enterprise RBAC.
	RBACUIManagedCalicoEnterpriseRBAC RBACUIType = "ManagedCalicoEnterpriseRBAC"
)

return reconcile.Result{}, err
}

// A nil managerCR (no Manager created) means callers fall back to their

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.

nit: this comment serves as storage of rationale/history that is useful for the author, rather than context that helps the reader - would just remove (personally)

// On Calico/OSS the Manager CRD is absent, so the read returns NoMatchError.
// We are in enterprise, so the Manager CRD is expected. A nil managerCR
// (no Manager created) means callers fall back to their defaults. A
// NoMatchError (Manager CRD not registered yet) is treated as an error:

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.

nit: this comment serves as storage of rationale/history that is useful for the author, rather than context that helps the reader - would just remove (personally)

// needs on top of render.RBACManagementEscalationRules.
func rbacSyncControllerRules() []rbacv1.PolicyRule {
rules := render.RBACManagementEscalationRules()
return append(rules,

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.

What I meant was that it would be nice to have comments that store the context behind why we need these specific rules - my understanding is that they map to a specific permission needed from a specific managed role - can we reference the name of that managed role here?

Comment thread pkg/render/rbac_management.go Outdated
// and calico-kube-controllers roles for the RBAC management UI. The SA writing
// a managed role must already hold every permission it grants, else K8s rejects
// the write as privilege escalation; keep this aligned with the managed roles.
// RBACManagementEscalationRules returns the permission set the rbacsync

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.

Sorry for catching this just now and not as part of my previous feedback, but if we have realized now that escalation rules only apply to the rbacsync controller and not ui-apis, I guess this no longer needs to be shared code? Everything should just be defined within rbacSyncControllerRules and everything there is an escalation rule? (and as per my other comment, each rule can have a comment explaining which managed role it covers)

Comment thread pkg/render/manager.go Outdated
{Name: "ELASTIC_KIBANA_DISABLED", Value: strconv.FormatBool(c.cfg.Tenant.MultiTenant())},
{Name: "VOLTRON_URL", Value: ManagerService(c.cfg.Tenant)},
{Name: "RBAC_UI_ENABLED", Value: strconv.FormatBool(c.cfg.Manager.RBACManagementEnabled())},
// The RBAC management UI is not supported on multi-tenant management

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.

nit: I would remove this comment, feels like a comment written for the person steering Claude rather than the eventual reader of the code

Comment thread pkg/render/manager.go Outdated
})
}

if c.cfg.Manager.RBACManagementEnabled() && c.cfg.RBACManagementLDAPConfigured {

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.

Should this also gate on multi-tenancy?

dimitri-nicolo and others added 7 commits July 2, 2026 15:21
… review)

Rename the RBAC management UI toggle field from Enabled (RBACUIStatus) to
Type (*RBACUIType) per review. Keep the Enabled/Disabled enum idiom; the
pointer distinguishes unset from the zero value.
…#4865 review)

The comment stored authoring rationale rather than reader-useful context;
remove it per review.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…era#4865 review)

The comment stored authoring rationale rather than reader-useful context;
remove it per review.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…ers (PR tigera#4865 review)

Explain in the appended rbacSyncControllerRules comments which managed role's
grant each escalation rule mirrors: the tigera-network-admin ClusterRole for
compliances, and the per-cluster log-access ClusterRoles for pods:list.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
… (PR tigera#4865 review)

The escalation rules only apply to the rbacsync controller (not ui-apis), so
the shared render.RBACManagementEscalationRules is no longer shared. Fold every
rule into rbacSyncControllerRules — where they all belong as escalation
coverage — each annotated with the managed role whose grant it mirrors, and
delete the now-dead rbac_management.go.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…4865 review)

The comment read as authoring context rather than something useful to the
eventual reader; remove it per review.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…s (PR tigera#4865 review)

The RBAC management UI is unsupported on multi-tenant clusters, so its LDAP
egress rule now carries the same !MultiTenant() gate as the rest of the
feature. Adds a test that the egress is omitted in multi-tenant mode even with
the UI enabled and the LDAP config Secret present.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@dimitri-nicolo dimitri-nicolo requested a review from pasanw July 2, 2026 22:30

@pasanw pasanw 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.

LGTM 🎉 As discussed, let's see what the other maintainers think about the API changes before we merge

Comment thread api/v1/manager_types.go Outdated
type RBACUI struct {
// Enabled turns the RBAC management UI on or off. Defaults to false.
// +optional
Enabled *bool `json:"enabled,omitempty"`

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.

We have an updated api spec in the docs that specifies these toggles,

Use a named string type with Enabled/Disabled constants and an Enum marker — not a *bool. This is the established repo idiom:

type NotificationMode string

const (
    Disabled NotificationMode = "Disabled"
    Enabled  NotificationMode = "Enabled"
)
// +kubebuilder:validation:Enum=Enabled;Disabled

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

@Brian-McM Thanks, I had considered raising the boolean vs. enum question with the maintainers before merging anything, but I'm happy to follow the idiom. Done in the latest commit: replaced the *bool with a named RBACUIStatusType enum (Enabled/Disabled + Enum marker), exposed as a State field.

cc: @pasanw

// cert above.
WAFWebhookCABundle: certificateManager.KeyPair().GetCertificatePEM(),
WAFWebhookCABundle: certificateManager.KeyPair().GetCertificatePEM(),
RBACManagementEnabled: managerCR.RBACManagementEnabled(),

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.

Since utils.GetManager returns nil, nil on not found won't this now panic?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

@Brian-McM It shouldn't panic, RBACManagementEnabled() guards m == nil before touching the pointer. The latest commit adds a table test (api/v1/manager_types_test.go) covering the nil-managerCR, nil-RBACUI, and nil-State cases.

@rene-dekker rene-dekker 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.

The host should be taken from Authentication.spec.ldap.host.

@rene-dekker

Copy link
Copy Markdown
Member

I reviewed only the ldap changes, which look good now.

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.

6 participants