From da59b7e0ab4690cbbcf715fbfada2fcc9b64ec09170d9303871bb6d1aa0992c0 Mon Sep 17 00:00:00 2001 From: Vasily Ulyanov Date: Thu, 20 Jun 2024 14:00:51 +0000 Subject: [PATCH] - Collect component Role rules under operator Role instead of ClusterRole (bsc#1223965, CVE-2024-33394) 0001-Collect-component-Role-rules-under-operator-Role-ins.patch OBS-URL: https://build.opensuse.org/package/show/Virtualization/kubevirt?expand=0&rev=157 --- ...t-Role-rules-under-operator-Role-ins.patch | 455 ++++++++++++++++++ kubevirt.changes | 7 + kubevirt.spec | 1 + 3 files changed, 463 insertions(+) create mode 100644 0001-Collect-component-Role-rules-under-operator-Role-ins.patch diff --git a/0001-Collect-component-Role-rules-under-operator-Role-ins.patch b/0001-Collect-component-Role-rules-under-operator-Role-ins.patch new file mode 100644 index 0000000..01f6017 --- /dev/null +++ b/0001-Collect-component-Role-rules-under-operator-Role-ins.patch @@ -0,0 +1,455 @@ +From 5b86f015a18b4f01ed5dd475509a7bd6ccd1dc67 Mon Sep 17 00:00:00 2001 +From: Jed Lejosne +Date: Mon, 10 Jun 2024 11:34:23 -0400 +Subject: [PATCH] Collect component Role rules under operator Role instead of + ClusterRole + +Signed-off-by: Jed Lejosne +--- + manifests/generated/operator-csv.yaml.in | 124 +++++++++--------- + .../rbac-operator.authorization.k8s.yaml.in | 124 +++++++++--------- + .../resource/generate/rbac/operator.go | 35 +++-- + .../resource/generate/rbac/operator_test.go | 18 +++ + 4 files changed, 169 insertions(+), 132 deletions(-) + +diff --git a/manifests/generated/operator-csv.yaml.in b/manifests/generated/operator-csv.yaml.in +index b50caafad..e70bb676b 100644 +--- a/manifests/generated/operator-csv.yaml.in ++++ b/manifests/generated/operator-csv.yaml.in +@@ -464,14 +464,6 @@ spec: + - create + - list + - get +- - apiGroups: +- - "" +- resources: +- - configmaps +- verbs: +- - get +- - list +- - watch + - apiGroups: + - "" + resources: +@@ -721,42 +713,6 @@ spec: + verbs: + - list + - watch +- - apiGroups: +- - route.openshift.io +- resources: +- - routes +- verbs: +- - list +- - get +- - watch +- - apiGroups: +- - "" +- resources: +- - secrets +- verbs: +- - list +- - get +- - watch +- - apiGroups: +- - networking.k8s.io +- resources: +- - ingresses +- verbs: +- - list +- - get +- - watch +- - apiGroups: +- - coordination.k8s.io +- resources: +- - leases +- verbs: +- - get +- - list +- - watch +- - delete +- - update +- - create +- - patch + - apiGroups: + - kubevirt.io + resources: +@@ -813,14 +769,6 @@ spec: + - get + - list + - watch +- - apiGroups: +- - "" +- resources: +- - configmaps +- verbs: +- - get +- - list +- - watch + - apiGroups: + - export.kubevirt.io + resources: +@@ -836,16 +784,6 @@ spec: + verbs: + - list + - watch +- - apiGroups: +- - "" +- resourceNames: +- - kubevirt-export-ca +- resources: +- - configmaps +- verbs: +- - get +- - list +- - watch + - apiGroups: + - kubevirt.io + resources: +@@ -1445,6 +1383,68 @@ spec: + - update + - create + - patch ++ - apiGroups: ++ - "" ++ resources: ++ - configmaps ++ verbs: ++ - get ++ - list ++ - watch ++ - apiGroups: ++ - route.openshift.io ++ resources: ++ - routes ++ verbs: ++ - list ++ - get ++ - watch ++ - apiGroups: ++ - "" ++ resources: ++ - secrets ++ verbs: ++ - list ++ - get ++ - watch ++ - apiGroups: ++ - networking.k8s.io ++ resources: ++ - ingresses ++ verbs: ++ - list ++ - get ++ - watch ++ - apiGroups: ++ - coordination.k8s.io ++ resources: ++ - leases ++ verbs: ++ - get ++ - list ++ - watch ++ - delete ++ - update ++ - create ++ - patch ++ - apiGroups: ++ - "" ++ resources: ++ - configmaps ++ verbs: ++ - get ++ - list ++ - watch ++ - apiGroups: ++ - "" ++ resourceNames: ++ - kubevirt-export-ca ++ resources: ++ - configmaps ++ verbs: ++ - get ++ - list ++ - watch + serviceAccountName: kubevirt-operator + strategy: deployment + installModes: +diff --git a/manifests/generated/rbac-operator.authorization.k8s.yaml.in b/manifests/generated/rbac-operator.authorization.k8s.yaml.in +index e8146bb1b..c0e76e8e6 100644 +--- a/manifests/generated/rbac-operator.authorization.k8s.yaml.in ++++ b/manifests/generated/rbac-operator.authorization.k8s.yaml.in +@@ -75,6 +75,68 @@ rules: + - update + - create + - patch ++- apiGroups: ++ - "" ++ resources: ++ - configmaps ++ verbs: ++ - get ++ - list ++ - watch ++- apiGroups: ++ - route.openshift.io ++ resources: ++ - routes ++ verbs: ++ - list ++ - get ++ - watch ++- apiGroups: ++ - "" ++ resources: ++ - secrets ++ verbs: ++ - list ++ - get ++ - watch ++- apiGroups: ++ - networking.k8s.io ++ resources: ++ - ingresses ++ verbs: ++ - list ++ - get ++ - watch ++- apiGroups: ++ - coordination.k8s.io ++ resources: ++ - leases ++ verbs: ++ - get ++ - list ++ - watch ++ - delete ++ - update ++ - create ++ - patch ++- apiGroups: ++ - "" ++ resources: ++ - configmaps ++ verbs: ++ - get ++ - list ++ - watch ++- apiGroups: ++ - "" ++ resourceNames: ++ - kubevirt-export-ca ++ resources: ++ - configmaps ++ verbs: ++ - get ++ - list ++ - watch + --- + apiVersion: rbac.authorization.k8s.io/v1 + kind: RoleBinding +@@ -404,14 +466,6 @@ rules: + - create + - list + - get +-- apiGroups: +- - "" +- resources: +- - configmaps +- verbs: +- - get +- - list +- - watch + - apiGroups: + - "" + resources: +@@ -661,42 +715,6 @@ rules: + verbs: + - list + - watch +-- apiGroups: +- - route.openshift.io +- resources: +- - routes +- verbs: +- - list +- - get +- - watch +-- apiGroups: +- - "" +- resources: +- - secrets +- verbs: +- - list +- - get +- - watch +-- apiGroups: +- - networking.k8s.io +- resources: +- - ingresses +- verbs: +- - list +- - get +- - watch +-- apiGroups: +- - coordination.k8s.io +- resources: +- - leases +- verbs: +- - get +- - list +- - watch +- - delete +- - update +- - create +- - patch + - apiGroups: + - kubevirt.io + resources: +@@ -753,14 +771,6 @@ rules: + - get + - list + - watch +-- apiGroups: +- - "" +- resources: +- - configmaps +- verbs: +- - get +- - list +- - watch + - apiGroups: + - export.kubevirt.io + resources: +@@ -776,16 +786,6 @@ rules: + verbs: + - list + - watch +-- apiGroups: +- - "" +- resourceNames: +- - kubevirt-export-ca +- resources: +- - configmaps +- verbs: +- - get +- - list +- - watch + - apiGroups: + - kubevirt.io + resources: +diff --git a/pkg/virt-operator/resource/generate/rbac/operator.go b/pkg/virt-operator/resource/generate/rbac/operator.go +index 365fb0600..b90a5fae8 100644 +--- a/pkg/virt-operator/resource/generate/rbac/operator.go ++++ b/pkg/virt-operator/resource/generate/rbac/operator.go +@@ -317,15 +317,14 @@ func NewOperatorClusterRole() *rbacv1.ClusterRole { + } + + // now append all rules needed by KubeVirt's components +- operatorRole.Rules = append(operatorRole.Rules, getKubeVirtComponentsRules()...) ++ operatorRole.Rules = append(operatorRole.Rules, getKubeVirtComponentsClusterRules()...) + return operatorRole + } + +-func getKubeVirtComponentsRules() []rbacv1.PolicyRule { +- ++func getKubeVirtComponentsClusterRules() []rbacv1.PolicyRule { + var rules []rbacv1.PolicyRule + +- // namespace doesn't matter, we are only interested in the rules of both Roles and ClusterRoles ++ // namespace doesn't matter, we are only interested in the rules of ClusterRoles + all := GetAllApiServer("") + all = append(all, GetAllController("")...) + all = append(all, GetAllHandler("")...) +@@ -337,9 +336,6 @@ func getKubeVirtComponentsRules() []rbacv1.PolicyRule { + case *rbacv1.ClusterRole: + role, _ := resource.(*rbacv1.ClusterRole) + rules = append(rules, role.Rules...) +- case *rbacv1.Role: +- role, _ := resource.(*rbacv1.Role) +- rules = append(rules, role.Rules...) + } + } + +@@ -375,6 +371,27 @@ func getKubeVirtComponentsRules() []rbacv1.PolicyRule { + return rules + } + ++func getKubeVirtComponentsRules() []rbacv1.PolicyRule { ++ var rules []rbacv1.PolicyRule ++ ++ // namespace doesn't matter, we are only interested in the rules ++ all := GetAllApiServer("") ++ all = append(all, GetAllController("")...) ++ all = append(all, GetAllHandler("")...) ++ all = append(all, GetAllExportProxy("")...) ++ all = append(all, GetAllCluster()...) ++ ++ for _, resource := range all { ++ switch resource.(type) { ++ case *rbacv1.Role: ++ role, _ := resource.(*rbacv1.Role) ++ rules = append(rules, role.Rules...) ++ } ++ } ++ ++ return rules ++} ++ + func newOperatorClusterRoleBinding(namespace string) *rbacv1.ClusterRoleBinding { + return &rbacv1.ClusterRoleBinding{ + TypeMeta: metav1.TypeMeta{ +@@ -432,7 +449,7 @@ func newOperatorRoleBinding(namespace string) *rbacv1.RoleBinding { + + // NewOperatorRole creates a Role object for kubevirt-operator. + func NewOperatorRole(namespace string) *rbacv1.Role { +- return &rbacv1.Role{ ++ operatorRole := &rbacv1.Role{ + TypeMeta: metav1.TypeMeta{ + APIVersion: VersionNamev1, + Kind: "Role", +@@ -527,6 +544,8 @@ func NewOperatorRole(namespace string) *rbacv1.Role { + }, + }, + } ++ operatorRole.Rules = append(operatorRole.Rules, getKubeVirtComponentsRules()...) ++ return operatorRole + } + + func GetKubevirtComponentsServiceAccounts(namespace string) map[string]bool { +diff --git a/pkg/virt-operator/resource/generate/rbac/operator_test.go b/pkg/virt-operator/resource/generate/rbac/operator_test.go +index 51bd479cc..22c7d30c0 100644 +--- a/pkg/virt-operator/resource/generate/rbac/operator_test.go ++++ b/pkg/virt-operator/resource/generate/rbac/operator_test.go +@@ -67,6 +67,11 @@ var _ = Describe("RBAC", func() { + Expect(clusterRoleBinding.Subjects[0].Namespace).To(BeEquivalentTo(expectedNamespace)) + }) + ++ It("doesn't have critical cluster-wide permissions", func() { ++ clusterRole := getFirstItemOfType(forOperator, reflect.TypeOf(&rbacv1.ClusterRole{})).(*rbacv1.ClusterRole) ++ Expect(clusterRole).ToNot(BeNil()) ++ expectExactRuleDoesntExists(clusterRole.Rules, "", "secrets", "get", "list", "watch") ++ }) + }) + + Context("GetKubevirtComponentsServiceAccounts", func() { +@@ -96,3 +101,16 @@ func getFirstItemOfType(items []interface{}, tp reflect.Type) interface{} { + } + return nil + } ++ ++func expectExactRuleDoesntExists(rules []rbacv1.PolicyRule, apiGroup, resource string, verbs ...string) { ++ for _, rule := range rules { ++ if contains(rule.APIGroups, apiGroup) && ++ contains(rule.Resources, resource) { ++ for _, verb := range verbs { ++ if contains(rule.Verbs, verb) { ++ Fail(fmt.Sprintf("Found rule (apiGroup: %s, resource: %s, verbs: %v)", apiGroup, resource, rule.Verbs)) ++ } ++ } ++ } ++ } ++} +-- +2.45.2 + diff --git a/kubevirt.changes b/kubevirt.changes index 1b107ca..98c5f9a 100644 --- a/kubevirt.changes +++ b/kubevirt.changes @@ -1,3 +1,10 @@ +------------------------------------------------------------------- +Thu Jun 20 13:48:18 UTC 2024 - Vasily Ulyanov + +- Collect component Role rules under operator Role instead of + ClusterRole (bsc#1223965, CVE-2024-33394) + 0001-Collect-component-Role-rules-under-operator-Role-ins.patch + ------------------------------------------------------------------- Thu Jun 6 06:54:11 UTC 2024 - Vasily Ulyanov diff --git a/kubevirt.spec b/kubevirt.spec index 2b50344..a5e5ed9 100644 --- a/kubevirt.spec +++ b/kubevirt.spec @@ -41,6 +41,7 @@ Source1: kubevirt_containers_meta Source2: kubevirt_containers_meta.service Source3: %{url}/releases/download/v%{version}/disks-images-provider.yaml Source100: %{name}-rpmlintrc +Patch1: 0001-Collect-component-Role-rules-under-operator-Role-ins.patch BuildRequires: glibc-devel-static BuildRequires: golang-packaging BuildRequires: pkgconfig