From 0ef1e6930adc719d523f72b29399ccb0e5aa5d27 Mon Sep 17 00:00:00 2001 From: skoryk-oleksandr Date: Wed, 25 Feb 2026 12:16:55 -0800 Subject: [PATCH 1/3] CORE-12219: Add kubevirt.io RBAC to CNI plugin for KubeVirt IPAM --- pkg/render/node.go | 6 ++++++ pkg/render/node_test.go | 8 ++++++++ 2 files changed, 14 insertions(+) diff --git a/pkg/render/node.go b/pkg/render/node.go index 45174fd668..6cdfcf0d2d 100644 --- a/pkg/render/node.go +++ b/pkg/render/node.go @@ -633,6 +633,12 @@ func (c *nodeComponent) cniPluginRole() *rbacv1.ClusterRole { }, Verbs: []string{"get", "list", "create", "update", "delete"}, }, + { + // The CNI plugin reads KubeVirt resources for IPAM of KubeVirt workloads. + APIGroups: []string{"kubevirt.io"}, + Resources: []string{"virtualmachineinstances", "virtualmachines"}, + Verbs: []string{"get", "list", "watch"}, + }, }, } return role diff --git a/pkg/render/node_test.go b/pkg/render/node_test.go index 4f7dc49ace..54c431d5c1 100644 --- a/pkg/render/node_test.go +++ b/pkg/render/node_test.go @@ -191,6 +191,14 @@ var _ = Describe("Node rendering tests", func() { i++ } + // calico-cni-plugin clusterRole should have kubevirt.io PolicyRule for IPAM of KubeVirt workloads. + cniRole := rtest.GetResource(resources, "calico-cni-plugin", "", "rbac.authorization.k8s.io", "v1", "ClusterRole").(*rbacv1.ClusterRole) + Expect(cniRole.Rules).To(ContainElement(rbacv1.PolicyRule{ + APIGroups: []string{"kubevirt.io"}, + Resources: []string{"virtualmachineinstances", "virtualmachines"}, + Verbs: []string{"get", "list", "watch"}, + })) + // Check CNI configmap. cniCmResource := rtest.GetResource(resources, "cni-config", "calico-system", "", "v1", "ConfigMap") Expect(cniCmResource).ToNot(BeNil()) From c8d98a8840f253075ef686272a3badda179f0047 Mon Sep 17 00:00:00 2001 From: skoryk-oleksandr Date: Wed, 25 Feb 2026 12:43:54 -0800 Subject: [PATCH 2/3] CORE-12219: Adjust kubevirt.io RBAC for CNI plugin and Kubecontrollers --- .../kubecontrollers/kube-controllers.go | 6 ++++++ .../kubecontrollers/kube-controllers_test.go | 19 ++++++++++++++++--- pkg/render/node.go | 2 +- pkg/render/node_test.go | 2 +- 4 files changed, 24 insertions(+), 5 deletions(-) diff --git a/pkg/render/kubecontrollers/kube-controllers.go b/pkg/render/kubecontrollers/kube-controllers.go index 722fa5a5cd..93a99a626f 100644 --- a/pkg/render/kubecontrollers/kube-controllers.go +++ b/pkg/render/kubecontrollers/kube-controllers.go @@ -379,6 +379,12 @@ func kubeControllersRoleCommonRules(cfg *KubeControllersConfiguration) []rbacv1. }, Verbs: []string{"get", "list", "watch", "create", "update", "delete"}, }, + { + // The IPAM GC controller reads KubeVirt resources to verify VM/VMI existence for IP garbage collection. + APIGroups: []string{"kubevirt.io"}, + Resources: []string{"virtualmachineinstances", "virtualmachines"}, + Verbs: []string{"get"}, + }, } if cfg.Installation.KubernetesProvider.IsOpenShift() { diff --git a/pkg/render/kubecontrollers/kube-controllers_test.go b/pkg/render/kubecontrollers/kube-controllers_test.go index 35ca3294ea..82af6245cb 100644 --- a/pkg/render/kubecontrollers/kube-controllers_test.go +++ b/pkg/render/kubecontrollers/kube-controllers_test.go @@ -138,6 +138,19 @@ var _ = Describe("kube-controllers rendering tests", func() { })) }) + It("should include kubevirt.io RBAC rules in calico-kube-controllers ClusterRole", func() { + component := kubecontrollers.NewCalicoKubeControllers(&cfg) + Expect(component.ResolveImages(nil)).To(BeNil()) + resources, _ := component.Objects() + + role := rtest.GetResource(resources, "calico-kube-controllers", "", "rbac.authorization.k8s.io", "v1", "ClusterRole").(*rbacv1.ClusterRole) + Expect(role.Rules).To(ContainElement(rbacv1.PolicyRule{ + APIGroups: []string{"kubevirt.io"}, + Resources: []string{"virtualmachineinstances", "virtualmachines"}, + Verbs: []string{"get"}, + })) + }) + It("should render all resources for a custom configuration", func() { expectedResources := []struct { name string @@ -252,7 +265,7 @@ var _ = Describe("kube-controllers rendering tests", func() { Expect(len(dp.Spec.Template.Spec.Volumes)).To(Equal(1)) clusterRole := rtest.GetResource(resources, kubecontrollers.KubeControllerRole, "", "rbac.authorization.k8s.io", "v1", "ClusterRole").(*rbacv1.ClusterRole) - Expect(clusterRole.Rules).To(HaveLen(24), "cluster role should have 24 rules") + Expect(clusterRole.Rules).To(HaveLen(25), "cluster role should have 25 rules") ms := rtest.GetResource(resources, kubecontrollers.KubeControllerMetrics, common.CalicoNamespace, "", "v1", "Service").(*corev1.Service) Expect(ms.Spec.ClusterIP).To(Equal("None"), "metrics service should be headless") @@ -339,7 +352,7 @@ var _ = Describe("kube-controllers rendering tests", func() { Expect(dp.Spec.Template.Spec.Volumes[0].ConfigMap.Name).To(Equal("tigera-ca-bundle")) clusterRole := rtest.GetResource(resources, kubecontrollers.EsKubeControllerRole, "", "rbac.authorization.k8s.io", "v1", "ClusterRole").(*rbacv1.ClusterRole) - Expect(clusterRole.Rules).To(HaveLen(22), "cluster role should have 22 rules") + Expect(clusterRole.Rules).To(HaveLen(23), "cluster role should have 23 rules") Expect(clusterRole.Rules).To(ContainElement( rbacv1.PolicyRule{ APIGroups: []string{""}, @@ -550,7 +563,7 @@ var _ = Describe("kube-controllers rendering tests", func() { Expect(dp.Spec.Template.Spec.Containers[0].Image).To(Equal("test-reg/tigera/kube-controllers:" + components.ComponentTigeraKubeControllers.Version)) clusterRole := rtest.GetResource(resources, kubecontrollers.EsKubeControllerRole, "", "rbac.authorization.k8s.io", "v1", "ClusterRole").(*rbacv1.ClusterRole) - Expect(clusterRole.Rules).To(HaveLen(22), "cluster role should have 22 rules") + Expect(clusterRole.Rules).To(HaveLen(23), "cluster role should have 23 rules") Expect(clusterRole.Rules).To(ContainElement( rbacv1.PolicyRule{ APIGroups: []string{""}, diff --git a/pkg/render/node.go b/pkg/render/node.go index 6cdfcf0d2d..0e46efa923 100644 --- a/pkg/render/node.go +++ b/pkg/render/node.go @@ -637,7 +637,7 @@ func (c *nodeComponent) cniPluginRole() *rbacv1.ClusterRole { // The CNI plugin reads KubeVirt resources for IPAM of KubeVirt workloads. APIGroups: []string{"kubevirt.io"}, Resources: []string{"virtualmachineinstances", "virtualmachines"}, - Verbs: []string{"get", "list", "watch"}, + Verbs: []string{"get"}, }, }, } diff --git a/pkg/render/node_test.go b/pkg/render/node_test.go index 54c431d5c1..8b52ac2e89 100644 --- a/pkg/render/node_test.go +++ b/pkg/render/node_test.go @@ -196,7 +196,7 @@ var _ = Describe("Node rendering tests", func() { Expect(cniRole.Rules).To(ContainElement(rbacv1.PolicyRule{ APIGroups: []string{"kubevirt.io"}, Resources: []string{"virtualmachineinstances", "virtualmachines"}, - Verbs: []string{"get", "list", "watch"}, + Verbs: []string{"get"}, })) // Check CNI configmap. From be2641ed60ca8a95df97160d751c2bbba063a9bd Mon Sep 17 00:00:00 2001 From: skoryk-oleksandr Date: Tue, 3 Mar 2026 14:21:39 -0800 Subject: [PATCH 3/3] CORE-12219: Update RBAC permissions for IPAM GC controller to include list and watch verbs --- pkg/render/kubecontrollers/kube-controllers.go | 4 ++-- pkg/render/kubecontrollers/kube-controllers_test.go | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/pkg/render/kubecontrollers/kube-controllers.go b/pkg/render/kubecontrollers/kube-controllers.go index 93a99a626f..462abd2cde 100644 --- a/pkg/render/kubecontrollers/kube-controllers.go +++ b/pkg/render/kubecontrollers/kube-controllers.go @@ -380,10 +380,10 @@ func kubeControllersRoleCommonRules(cfg *KubeControllersConfiguration) []rbacv1. Verbs: []string{"get", "list", "watch", "create", "update", "delete"}, }, { - // The IPAM GC controller reads KubeVirt resources to verify VM/VMI existence for IP garbage collection. + // The IPAM GC controller uses informers to list/watch KubeVirt VMs/VMIs for IP garbage collection. APIGroups: []string{"kubevirt.io"}, Resources: []string{"virtualmachineinstances", "virtualmachines"}, - Verbs: []string{"get"}, + Verbs: []string{"get", "list", "watch"}, }, } diff --git a/pkg/render/kubecontrollers/kube-controllers_test.go b/pkg/render/kubecontrollers/kube-controllers_test.go index 82af6245cb..f5d380e3d4 100644 --- a/pkg/render/kubecontrollers/kube-controllers_test.go +++ b/pkg/render/kubecontrollers/kube-controllers_test.go @@ -147,7 +147,7 @@ var _ = Describe("kube-controllers rendering tests", func() { Expect(role.Rules).To(ContainElement(rbacv1.PolicyRule{ APIGroups: []string{"kubevirt.io"}, Resources: []string{"virtualmachineinstances", "virtualmachines"}, - Verbs: []string{"get"}, + Verbs: []string{"get", "list", "watch"}, })) })