From ed4d046b6df457deb9aa0eb22382684f04602d4d Mon Sep 17 00:00:00 2001 From: hongming Date: Sun, 23 Feb 2020 18:34:14 +0800 Subject: [PATCH] fix: role binding change Signed-off-by: hongming --- .../clusterrolebinding_controller.go | 128 ++++++---------- .../namespace/namespace_controller.go | 139 +++++++----------- pkg/models/iam/am.go | 16 +- 3 files changed, 110 insertions(+), 173 deletions(-) diff --git a/pkg/controller/clusterrolebinding/clusterrolebinding_controller.go b/pkg/controller/clusterrolebinding/clusterrolebinding_controller.go index 81815ba41..a3c2f53aa 100644 --- a/pkg/controller/clusterrolebinding/clusterrolebinding_controller.go +++ b/pkg/controller/clusterrolebinding/clusterrolebinding_controller.go @@ -20,7 +20,6 @@ package clusterrolebinding import ( "context" - "fmt" corev1 "k8s.io/api/core/v1" rbac "k8s.io/api/rbac/v1" "k8s.io/apimachinery/pkg/api/errors" @@ -29,6 +28,7 @@ import ( "k8s.io/apimachinery/pkg/types" log "k8s.io/klog" "kubesphere.io/kubesphere/pkg/constants" + "kubesphere.io/kubesphere/pkg/models/iam" "kubesphere.io/kubesphere/pkg/utils/k8sutil" "reflect" "sigs.k8s.io/controller-runtime/pkg/client" @@ -99,8 +99,8 @@ func (r *ReconcileClusterRoleBinding) Reconcile(request reconcile.Request) (reco workspaceName := instance.Labels[constants.WorkspaceLabelKey] if workspaceName != "" && k8sutil.IsControlledBy(instance.OwnerReferences, "Workspace", workspaceName) { - if instance.Name == getWorkspaceAdminRoleBindingName(workspaceName) || - instance.Name == getWorkspaceViewerRoleBindingName(workspaceName) { + if instance.Name == iam.GetWorkspaceAdminRoleBindingName(workspaceName) || + instance.Name == iam.GetWorkspaceViewerRoleBindingName(workspaceName) { nsList := &corev1.NamespaceList{} options := client.ListOptions{LabelSelector: labels.SelectorFromSet(labels.Set{constants.WorkspaceLabelKey: workspaceName})} @@ -121,100 +121,60 @@ func (r *ReconcileClusterRoleBinding) Reconcile(request reconcile.Request) (reco return reconcile.Result{}, nil } -func (r *ReconcileClusterRoleBinding) updateRoleBindings(clusterRoleBinding *rbac.ClusterRoleBinding, namespace *corev1.Namespace) error { - - workspaceName := namespace.Labels[constants.WorkspaceLabelKey] - - if clusterRoleBinding.Name == getWorkspaceAdminRoleBindingName(workspaceName) { - adminBinding := &rbac.RoleBinding{} - adminBinding.Name = "admin" - adminBinding.Namespace = namespace.Name - adminBinding.RoleRef = rbac.RoleRef{Name: "admin", APIGroup: "rbac.authorization.k8s.io", Kind: "Role"} - adminBinding.Subjects = clusterRoleBinding.Subjects - - found := &rbac.RoleBinding{} - - err := r.Get(context.TODO(), types.NamespacedName{Namespace: namespace.Name, Name: adminBinding.Name}, found) - +func (r *ReconcileClusterRoleBinding) createRoleBindingsIfNotExist(roleBinding *rbac.RoleBinding) error { + found := &rbac.RoleBinding{} + if err := r.Get(context.TODO(), types.NamespacedName{Namespace: roleBinding.Namespace, Name: roleBinding.Name}, found); err != nil { if errors.IsNotFound(err) { - err = r.Create(context.TODO(), adminBinding) + err := r.Create(context.TODO(), roleBinding) if err != nil { - log.Error(err) + log.Errorln(err) } return err - } else if err != nil { - log.Error(err) - return err - } - - if !reflect.DeepEqual(found.RoleRef, adminBinding.RoleRef) { - err = r.Delete(context.TODO(), found) - if err != nil { - log.Error(err) - return err - } - return fmt.Errorf("conflict role binding %s.%s, waiting for recreate", namespace.Name, adminBinding.Name) - } - - if !reflect.DeepEqual(found.Subjects, adminBinding.Subjects) { - found.Subjects = adminBinding.Subjects - err = r.Update(context.TODO(), found) - if err != nil { - log.Error(err) - return err - } } + log.Errorln(err) + return err } - if clusterRoleBinding.Name == getWorkspaceViewerRoleBindingName(workspaceName) { - - found := &rbac.RoleBinding{} - - viewerBinding := &rbac.RoleBinding{} - viewerBinding.Name = "viewer" - viewerBinding.Namespace = namespace.Name - viewerBinding.RoleRef = rbac.RoleRef{Name: "viewer", APIGroup: "rbac.authorization.k8s.io", Kind: "Role"} - viewerBinding.Subjects = clusterRoleBinding.Subjects - - err := r.Get(context.TODO(), types.NamespacedName{Namespace: namespace.Name, Name: viewerBinding.Name}, found) - - if errors.IsNotFound(err) { - err = r.Create(context.TODO(), viewerBinding) - if err != nil { - log.Error(err) - } + if !reflect.DeepEqual(found.Subjects, roleBinding.Subjects) { + found.Subjects = roleBinding.Subjects + if err := r.Update(context.TODO(), found); err != nil { + log.Errorln(err) return err - } else if err != nil { - log.Error(err) - return err - } - - if !reflect.DeepEqual(found.RoleRef, viewerBinding.RoleRef) { - err = r.Delete(context.TODO(), found) - if err != nil { - log.Error(err) - return err - } - return fmt.Errorf("conflict role binding %s.%s, waiting for recreate", namespace.Name, viewerBinding.Name) - } - - if !reflect.DeepEqual(found.Subjects, viewerBinding.Subjects) { - found.Subjects = viewerBinding.Subjects - err = r.Update(context.TODO(), found) - if err != nil { - log.Error(err) - return err - } } } return nil } -func getWorkspaceAdminRoleBindingName(workspaceName string) string { - return fmt.Sprintf("workspace:%s:admin", workspaceName) -} +func (r *ReconcileClusterRoleBinding) updateRoleBindings(clusterRoleBinding *rbac.ClusterRoleBinding, namespace *corev1.Namespace) error { -func getWorkspaceViewerRoleBindingName(workspaceName string) string { - return fmt.Sprintf("workspace:%s:viewer", workspaceName) + workspaceName := namespace.Labels[constants.WorkspaceLabelKey] + + if clusterRoleBinding.Name == iam.GetWorkspaceAdminRoleBindingName(workspaceName) { + adminBinding := &rbac.RoleBinding{} + adminBinding.Name = iam.NamespaceAdminRoleBindName + adminBinding.Namespace = namespace.Name + adminBinding.RoleRef = rbac.RoleRef{Name: iam.NamespaceAdminRoleName, APIGroup: "rbac.authorization.k8s.io", Kind: iam.RoleKind} + adminBinding.Subjects = clusterRoleBinding.Subjects + + if err := r.createRoleBindingsIfNotExist(adminBinding); err != nil { + log.Errorln(err) + return err + } + } + + if clusterRoleBinding.Name == iam.GetWorkspaceViewerRoleBindingName(workspaceName) { + viewerBinding := &rbac.RoleBinding{} + viewerBinding.Name = iam.NamespaceViewerRoleBindName + viewerBinding.Namespace = namespace.Name + viewerBinding.RoleRef = rbac.RoleRef{Name: iam.NamespaceViewerRoleName, APIGroup: "rbac.authorization.k8s.io", Kind: iam.RoleKind} + viewerBinding.Subjects = clusterRoleBinding.Subjects + + if err := r.createRoleBindingsIfNotExist(viewerBinding); err != nil { + log.Errorln(err) + return err + } + } + + return nil } diff --git a/pkg/controller/namespace/namespace_controller.go b/pkg/controller/namespace/namespace_controller.go index 96bfd68a7..3026f00b5 100644 --- a/pkg/controller/namespace/namespace_controller.go +++ b/pkg/controller/namespace/namespace_controller.go @@ -32,9 +32,9 @@ import ( "k8s.io/klog" "kubesphere.io/kubesphere/pkg/apis/tenant/v1alpha1" "kubesphere.io/kubesphere/pkg/constants" + "kubesphere.io/kubesphere/pkg/models/iam" cs "kubesphere.io/kubesphere/pkg/simple/client" "kubesphere.io/kubesphere/pkg/simple/client/openpitrix" - "kubesphere.io/kubesphere/pkg/utils/k8sutil" "kubesphere.io/kubesphere/pkg/utils/sliceutil" "openpitrix.io/openpitrix/pkg/pb" "reflect" @@ -54,12 +54,12 @@ const ( ) var ( - admin = rbac.Role{ObjectMeta: metav1.ObjectMeta{Name: "admin", Annotations: map[string]string{constants.DescriptionAnnotationKey: adminDescription, constants.CreatorAnnotationKey: constants.System}}, Rules: []rbac.PolicyRule{{Verbs: []string{"*"}, APIGroups: []string{"*"}, Resources: []string{"*"}}}} - operator = rbac.Role{ObjectMeta: metav1.ObjectMeta{Name: "operator", Annotations: map[string]string{constants.DescriptionAnnotationKey: operatorDescription, constants.CreatorAnnotationKey: constants.System}}, Rules: []rbac.PolicyRule{{Verbs: []string{"get", "list", "watch"}, APIGroups: []string{"*"}, Resources: []string{"*"}}, + admin = rbac.Role{ObjectMeta: metav1.ObjectMeta{Name: iam.NamespaceAdminRoleName, Annotations: map[string]string{constants.DescriptionAnnotationKey: adminDescription, constants.CreatorAnnotationKey: constants.System}}, Rules: []rbac.PolicyRule{{Verbs: []string{"*"}, APIGroups: []string{"*"}, Resources: []string{"*"}}}} + operator = rbac.Role{ObjectMeta: metav1.ObjectMeta{Name: iam.NamespaceOperatorRoleName, Annotations: map[string]string{constants.DescriptionAnnotationKey: operatorDescription, constants.CreatorAnnotationKey: constants.System}}, Rules: []rbac.PolicyRule{{Verbs: []string{"get", "list", "watch"}, APIGroups: []string{"*"}, Resources: []string{"*"}}, {Verbs: []string{"*"}, APIGroups: []string{"apps", "extensions", "batch", "logging.kubesphere.io", "monitoring.kubesphere.io", "iam.kubesphere.io", "autoscaling", "alerting.kubesphere.io", "openpitrix.io", "app.k8s.io", "servicemesh.kubesphere.io", "operations.kubesphere.io", "devops.kubesphere.io"}, Resources: []string{"*"}}, {Verbs: []string{"*"}, APIGroups: []string{"", "resources.kubesphere.io"}, Resources: []string{"jobs", "cronjobs", "daemonsets", "deployments", "horizontalpodautoscalers", "ingresses", "endpoints", "configmaps", "events", "persistentvolumeclaims", "pods", "podtemplates", "pods", "secrets", "services"}}, }} - viewer = rbac.Role{ObjectMeta: metav1.ObjectMeta{Name: "viewer", Annotations: map[string]string{constants.DescriptionAnnotationKey: viewerDescription, constants.CreatorAnnotationKey: constants.System}}, Rules: []rbac.PolicyRule{{Verbs: []string{"get", "list", "watch"}, APIGroups: []string{"*"}, Resources: []string{"*"}}}} + viewer = rbac.Role{ObjectMeta: metav1.ObjectMeta{Name: iam.NamespaceViewerRoleName, Annotations: map[string]string{constants.DescriptionAnnotationKey: viewerDescription, constants.CreatorAnnotationKey: constants.System}}, Rules: []rbac.PolicyRule{{Verbs: []string{"get", "list", "watch"}, APIGroups: []string{"*"}, Resources: []string{"*"}}}} defaultRoles = []rbac.Role{admin, operator, viewer} ) @@ -243,119 +243,84 @@ func (r *ReconcileNamespace) checkAndCreateRoles(namespace *corev1.Namespace) er return nil } +func (r *ReconcileNamespace) createRoleBindingsIfNotExist(roleBinding *rbac.RoleBinding) error { + found := &rbac.RoleBinding{} + if err := r.Get(context.TODO(), types.NamespacedName{Namespace: roleBinding.Namespace, Name: roleBinding.Name}, found); err != nil { + if errors.IsNotFound(err) { + err := r.Create(context.TODO(), roleBinding) + if err != nil { + klog.Errorln(err) + } + return err + } + klog.Errorln(err) + return err + } + + if !reflect.DeepEqual(found.Subjects, roleBinding.Subjects) { + found.Subjects = roleBinding.Subjects + if err := r.Update(context.TODO(), found); err != nil { + klog.Errorln(err) + return err + } + } + + return nil +} + func (r *ReconcileNamespace) checkAndCreateRoleBindings(namespace *corev1.Namespace) error { workspaceName := namespace.Labels[constants.WorkspaceLabelKey] creatorName := namespace.Annotations[constants.CreatorAnnotationKey] - creator := rbac.Subject{APIGroup: "rbac.authorization.k8s.io", Kind: "User", Name: creatorName} + if creatorName != "" { + creatorRoleBinding := &rbac.RoleBinding{} + creatorRoleBinding.Name = fmt.Sprintf("%s-%s", admin.Name, creatorName) + creatorRoleBinding.Namespace = namespace.Name + creatorRoleBinding.RoleRef = rbac.RoleRef{Name: admin.Name, APIGroup: "rbac.authorization.k8s.io", Kind: "Role"} + creatorRoleBinding.Subjects = []rbac.Subject{{APIGroup: "rbac.authorization.k8s.io", Kind: "User", Name: creatorName}} + if err := r.createRoleBindingsIfNotExist(creatorRoleBinding); err != nil { + klog.Errorln(err) + return err + } + } workspaceAdminBinding := &rbac.ClusterRoleBinding{} - err := r.Get(context.TODO(), types.NamespacedName{Name: fmt.Sprintf("workspace:%s:admin", workspaceName)}, workspaceAdminBinding) - - if err != nil { + if err := r.Get(context.TODO(), types.NamespacedName{Name: iam.GetWorkspaceAdminRoleBindingName(workspaceName)}, workspaceAdminBinding); err != nil { + klog.Errorln(err) return err } adminBinding := &rbac.RoleBinding{} - adminBinding.Name = admin.Name + adminBinding.Name = iam.NamespaceAdminRoleBindName adminBinding.Namespace = namespace.Name - adminBinding.RoleRef = rbac.RoleRef{Name: admin.Name, APIGroup: "rbac.authorization.k8s.io", Kind: "Role"} + adminBinding.RoleRef = rbac.RoleRef{Name: admin.Name, APIGroup: "rbac.authorization.k8s.io", Kind: iam.RoleKind} adminBinding.Subjects = workspaceAdminBinding.Subjects - if creator.Name != "" { - if adminBinding.Subjects == nil { - adminBinding.Subjects = make([]rbac.Subject, 0) - } - if !k8sutil.ContainsUser(adminBinding.Subjects, creatorName) { - adminBinding.Subjects = append(adminBinding.Subjects, creator) - } - } - - found := &rbac.RoleBinding{} - - err = r.Get(context.TODO(), types.NamespacedName{Namespace: namespace.Name, Name: adminBinding.Name}, found) - - if errors.IsNotFound(err) { - err = r.Create(context.TODO(), adminBinding) - if err != nil { - klog.Errorf("creating role binding namespace: %s,role binding: %s, error: %s", namespace.Name, adminBinding.Name, err) - return err - } - found = adminBinding - } else if err != nil { - klog.Errorf("get role binding namespace: %s,role binding: %s, error: %s", namespace.Name, adminBinding.Name, err) + if err := r.createRoleBindingsIfNotExist(adminBinding); err != nil { + klog.Errorln(err) return err } - if !reflect.DeepEqual(found.RoleRef, adminBinding.RoleRef) { - err = r.Delete(context.TODO(), found) - if err != nil { - klog.Errorf("deleting role binding namespace: %s, role binding: %s, error: %s", namespace.Name, adminBinding.Name, err) - return err - } - err = fmt.Errorf("conflict role binding %s.%s, waiting for recreate", namespace.Name, adminBinding.Name) - klog.Errorf("conflict role binding namespace: %s, role binding: %s, error: %s", namespace.Name, adminBinding.Name, err) - return err - } - - if !reflect.DeepEqual(found.Subjects, adminBinding.Subjects) { - found.Subjects = adminBinding.Subjects - err = r.Update(context.TODO(), found) - if err != nil { - klog.Errorf("updating role binding namespace: %s, role binding: %s, error: %s", namespace.Name, adminBinding.Name, err) - return err - } - } - workspaceViewerBinding := &rbac.ClusterRoleBinding{} - err = r.Get(context.TODO(), types.NamespacedName{Name: fmt.Sprintf("workspace:%s:viewer", workspaceName)}, workspaceViewerBinding) - - if err != nil { + if err := r.Get(context.TODO(), types.NamespacedName{Name: iam.GetWorkspaceViewerRoleBindingName(workspaceName)}, workspaceViewerBinding); err != nil { + klog.Errorln(err) return err } viewerBinding := &rbac.RoleBinding{} - viewerBinding.Name = viewer.Name + viewerBinding.Name = iam.NamespaceViewerRoleBindName viewerBinding.Namespace = namespace.Name - viewerBinding.RoleRef = rbac.RoleRef{Name: viewer.Name, APIGroup: "rbac.authorization.k8s.io", Kind: "Role"} + viewerBinding.RoleRef = rbac.RoleRef{Name: viewer.Name, APIGroup: "rbac.authorization.k8s.io", Kind: iam.RoleKind} viewerBinding.Subjects = workspaceViewerBinding.Subjects - err = r.Get(context.TODO(), types.NamespacedName{Namespace: namespace.Name, Name: viewerBinding.Name}, found) - - if errors.IsNotFound(err) { - err = r.Create(context.TODO(), viewerBinding) - if err != nil { - klog.Errorf("creating role binding namespace: %s, role binding: %s, error: %s", namespace.Name, viewerBinding.Name, err) - return err - } - found = viewerBinding - } else if err != nil { + if err := r.createRoleBindingsIfNotExist(viewerBinding); err != nil { + klog.Errorln(err) return err } - if !reflect.DeepEqual(found.RoleRef, viewerBinding.RoleRef) { - err = r.Delete(context.TODO(), found) - if err != nil { - klog.Errorf("deleting conflict role binding namespace: %s, role binding: %s, %s", namespace.Name, viewerBinding.Name, err) - return err - } - err = fmt.Errorf("conflict role binding %s.%s, waiting for recreate", namespace.Name, viewerBinding.Name) - klog.Errorf("conflict role binding namespace: %s, role binding: %s, error: %s", namespace.Name, viewerBinding.Name, err) - return err - } - - if !reflect.DeepEqual(found.Subjects, viewerBinding.Subjects) { - found.Subjects = viewerBinding.Subjects - err = r.Update(context.TODO(), found) - if err != nil { - klog.Errorf("updating role binding namespace: %s, role binding: %s, error: %s", namespace.Name, viewerBinding.Name, err) - return err - } - } - return nil } diff --git a/pkg/models/iam/am.go b/pkg/models/iam/am.go index 5251ea43b..0c0ed9e9e 100644 --- a/pkg/models/iam/am.go +++ b/pkg/models/iam/am.go @@ -42,10 +42,22 @@ import ( const ( ClusterRoleKind = "ClusterRole" - NamespaceAdminRoleBindName = "admin" - NamespaceViewerRoleBindName = "viewer" + RoleKind = "Role" + NamespaceAdminRoleName = "admin" + NamespaceOperatorRoleName = "operator" + NamespaceViewerRoleName = "viewer" + NamespaceAdminRoleBindName = NamespaceAdminRoleName + NamespaceViewerRoleBindName = NamespaceViewerRoleName ) +func GetWorkspaceAdminRoleBindingName(workspaceName string) string { + return fmt.Sprintf("workspace:%s:admin", workspaceName) +} + +func GetWorkspaceViewerRoleBindingName(workspaceName string) string { + return fmt.Sprintf("workspace:%s:viewer", workspaceName) +} + func GetDevopsRoleSimpleRules(role string) []models.SimpleRule { var rules []models.SimpleRule