From af73b78bbb03ceb950ef73c0c3bb974b6da26488 Mon Sep 17 00:00:00 2001 From: Brad Davidson Date: Mon, 1 Jul 2024 22:56:48 +0000 Subject: [PATCH] Fix ClusterRoleBinding subject growth Fixed an issue where failing to include APIGroup on the subjects caused the reconcile helpers to think the subject needed to be re-added every time RKE2 starts up. Signed-off-by: Brad Davidson --- pkg/rke2/clusterrole.go | 35 +++++++++++++++++++++++++++++++ pkg/rke2/clusterrole_bootstrap.go | 4 ++-- 2 files changed, 37 insertions(+), 2 deletions(-) diff --git a/pkg/rke2/clusterrole.go b/pkg/rke2/clusterrole.go index 543fa28279..bc2bc110e2 100644 --- a/pkg/rke2/clusterrole.go +++ b/pkg/rke2/clusterrole.go @@ -2,11 +2,16 @@ package rke2 import ( "context" + "encoding/json" "sync" "github.com/k3s-io/k3s/pkg/cli/cmds" "github.com/sirupsen/logrus" + rbacv1 "k8s.io/api/rbac/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/types" genericapiserver "k8s.io/apiserver/pkg/server" + "k8s.io/client-go/kubernetes" "k8s.io/client-go/tools/clientcmd" rbacrest "k8s.io/kubernetes/pkg/registry/rbac/rest" ) @@ -21,6 +26,10 @@ func setClusterRoles() cmds.StartupHook { logrus.Info("Applying Cluster Role Bindings") config, err := clientcmd.BuildConfigFromFlags("", args.KubeConfigSupervisor) + if err != nil { + logrus.Fatalf("clusterrole: new k8s restConfig: %v", err) + } + client, err := kubernetes.NewForConfig(config) if err != nil { logrus.Fatalf("clusterrole: new k8s client: %v", err) } @@ -45,6 +54,32 @@ func setClusterRoles() cmds.StartupHook { logrus.Fatalf("clusterrole: EnsureRBACPolicy failed: %v", err) } + // Begin remediation for https://github.com/rancher/rke2/issues/6272 + // This can be removed after ~1 year of shipping releases not affected by this issue. + + // stub binding/clusterrolebinding for marshalling the patch json + type binding struct { + Subjects []rbacv1.Subject `json:"subjects"` + } + + // It is not critical if these fail, the excess subjects just need to be cleaned up eventually + for ns, rbs := range policy.RoleBindings { + for _, rb := range rbs { + b, _ := json.Marshal(binding{Subjects: rb.Subjects}) + if _, err := client.RbacV1().RoleBindings(ns).Patch(ctx, rb.Name, types.MergePatchType, b, metav1.PatchOptions{}); err != nil { + logrus.Debugf("Failed to patch RoleBinding %s/%s subjects: %v", ns, rb.Name, err) + } + } + } + for _, crb := range policy.ClusterRoleBindings { + b, _ := json.Marshal(binding{Subjects: crb.Subjects}) + if _, err := client.RbacV1().ClusterRoleBindings().Patch(ctx, crb.Name, types.MergePatchType, b, metav1.PatchOptions{}); err != nil { + logrus.Debugf("Failed to patch ClusterRoleBinding %s subjects: %v", crb.Name, err) + } + } + + // End remediation for https://github.com/rancher/rke2/issues/6272 + logrus.Info("Cluster Role Bindings applied successfully") }() return nil diff --git a/pkg/rke2/clusterrole_bootstrap.go b/pkg/rke2/clusterrole_bootstrap.go index b023536283..5268789a3f 100644 --- a/pkg/rke2/clusterrole_bootstrap.go +++ b/pkg/rke2/clusterrole_bootstrap.go @@ -102,7 +102,7 @@ func roleBindings() map[string][]rbacv1.RoleBinding { // For some reason the core helpers don't have any methods for adding namespaced users, only namespaced service accounts. func RoleBindingNamespacedUsers(r *rbacv1helpers.RoleBindingBuilder, namespace string, users ...string) *rbacv1helpers.RoleBindingBuilder { for _, user := range users { - r.RoleBinding.Subjects = append(r.RoleBinding.Subjects, rbacv1.Subject{Kind: rbacv1.UserKind, Namespace: namespace, Name: user}) + r.RoleBinding.Subjects = append(r.RoleBinding.Subjects, rbacv1.Subject{APIGroup: rbacv1.GroupName, Kind: rbacv1.UserKind, Namespace: namespace, Name: user}) } return r } @@ -119,7 +119,7 @@ func RoleBindingName(r *rbacv1helpers.RoleBindingBuilder, name string) *rbacv1he // For some reason the core helpers don't have any methods for adding namespaced users, only namespaced service accounts. func ClusterRoleBindingNamespacedUsers(r *rbacv1helpers.ClusterRoleBindingBuilder, namespace string, users ...string) *rbacv1helpers.ClusterRoleBindingBuilder { for _, user := range users { - r.ClusterRoleBinding.Subjects = append(r.ClusterRoleBinding.Subjects, rbacv1.Subject{Kind: rbacv1.UserKind, Namespace: namespace, Name: user}) + r.ClusterRoleBinding.Subjects = append(r.ClusterRoleBinding.Subjects, rbacv1.Subject{APIGroup: rbacv1.GroupName, Kind: rbacv1.UserKind, Namespace: namespace, Name: user}) } return r }