@@ -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
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
Reference in New Issue
Block a user