diff --git a/pkg/karmadactl/cmdinit/karmada/deploy.go b/pkg/karmadactl/cmdinit/karmada/deploy.go index 41cb49b59..75ae837dd 100644 --- a/pkg/karmadactl/cmdinit/karmada/deploy.go +++ b/pkg/karmadactl/cmdinit/karmada/deploy.go @@ -26,8 +26,13 @@ import ( "github.com/karmada-io/karmada/pkg/karmadactl/cmdinit/utils" ) +const ( + clusterProxyAdminRole = "cluster-proxy-admin" + clusterProxyAdminUser = "system:admin" +) + // InitKarmadaResources Initialize karmada resource -func InitKarmadaResources(dir, caBase64 string, systemNamespace string) error { +func InitKarmadaResources(dir, caBase64, systemNamespace string) error { restConfig, err := utils.RestConfig(filepath.Join(dir, options.KarmadaKubeConfigName)) if err != nil { return err @@ -93,6 +98,11 @@ func InitKarmadaResources(dir, caBase64 string, systemNamespace string) error { klog.Exitln(err) } + // grant proxy permission to "system:admin". + if err := grantProxyPermissionToAdmin(clientSet); err != nil { + return err + } + return nil } diff --git a/pkg/karmadactl/cmdinit/karmada/rbac.go b/pkg/karmadactl/cmdinit/karmada/rbac.go new file mode 100644 index 000000000..0a4457c6d --- /dev/null +++ b/pkg/karmadactl/cmdinit/karmada/rbac.go @@ -0,0 +1,36 @@ +package karmada + +import ( + rbacv1 "k8s.io/api/rbac/v1" + "k8s.io/client-go/kubernetes" + + "github.com/karmada-io/karmada/pkg/karmadactl/cmdinit/utils" +) + +// grantProxyPermissionToAdmin grants the proxy permission to "system:admin" +func grantProxyPermissionToAdmin(clientSet *kubernetes.Clientset) error { + proxyAdminClusterRole := utils.ClusterRoleFromRules(clusterProxyAdminRole, []rbacv1.PolicyRule{ + { + APIGroups: []string{"cluster.karmada.io"}, + Resources: []string{"clusters/proxy"}, + Verbs: []string{"*"}, + }, + }, nil) + err := utils.CreateIfNotExistClusterRole(clientSet, proxyAdminClusterRole) + if err != nil { + return err + } + + proxyAdminClusterRoleBinding := utils.ClusterRoleBindingFromSubjects(clusterProxyAdminRole, clusterProxyAdminRole, + []rbacv1.Subject{ + { + Kind: "User", + Name: clusterProxyAdminUser, + }}, nil) + err = utils.CreateIfNotExistClusterRoleBinding(clientSet, proxyAdminClusterRoleBinding) + if err != nil { + return err + } + + return nil +} diff --git a/pkg/karmadactl/cmdinit/kubernetes/deploy.go b/pkg/karmadactl/cmdinit/kubernetes/deploy.go index fdda9f15b..438273287 100644 --- a/pkg/karmadactl/cmdinit/kubernetes/deploy.go +++ b/pkg/karmadactl/cmdinit/kubernetes/deploy.go @@ -418,8 +418,8 @@ func (i *CommandInitOption) RunInit(_ io.Writer, parentCommand string) error { } // Create karmada-controller-manager ClusterRole and ClusterRoleBinding - if err := i.CreateClusterRole(); err != nil { - klog.Exitln(err) + if err := i.CreateControllerManagerRBAC(); err != nil { + return err } // Create Secrets diff --git a/pkg/karmadactl/cmdinit/kubernetes/deployments.go b/pkg/karmadactl/cmdinit/kubernetes/deployments.go index 97c4698ce..c59562816 100644 --- a/pkg/karmadactl/cmdinit/kubernetes/deployments.go +++ b/pkg/karmadactl/cmdinit/kubernetes/deployments.go @@ -36,6 +36,8 @@ const ( webhookTargetPort = 8443 webhookPort = 443 karmadaAggregatedAPIServerDeploymentAndServiceName = "karmada-aggregated-apiserver" + karmadaBootstrappingLabelKey = "karmada.io/bootstrapping" + karmadaBootstrappingLabelValue = "rbac-defaults" ) var ( diff --git a/pkg/karmadactl/cmdinit/kubernetes/rbac.go b/pkg/karmadactl/cmdinit/kubernetes/rbac.go index 3f5248f93..fc55cc85f 100644 --- a/pkg/karmadactl/cmdinit/kubernetes/rbac.go +++ b/pkg/karmadactl/cmdinit/kubernetes/rbac.go @@ -1,60 +1,16 @@ package kubernetes import ( - "context" - "fmt" + "github.com/karmada-io/karmada/pkg/karmadactl/cmdinit/utils" rbacv1 "k8s.io/api/rbac/v1" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/klog/v2" ) -// ClusterRoleFromSpec ClusterRole spec -func (i *CommandInitOption) ClusterRoleFromSpec(name string, rules []rbacv1.PolicyRule) *rbacv1.ClusterRole { - return &rbacv1.ClusterRole{ - TypeMeta: metav1.TypeMeta{ - APIVersion: "rbac.authorization.k8s.io/v1", - Kind: "ClusterRole", - }, - ObjectMeta: metav1.ObjectMeta{ - Name: name, - Namespace: i.Namespace, - Labels: map[string]string{"karmada.io/bootstrapping": "rbac-defaults"}, - }, - Rules: rules, - } -} - -// ClusterRoleBindingFromSpec ClusterRoleBinding spec -func (i *CommandInitOption) ClusterRoleBindingFromSpec(clusterRoleBindingName, clusterRoleName, saName string) *rbacv1.ClusterRoleBinding { - return &rbacv1.ClusterRoleBinding{ - TypeMeta: metav1.TypeMeta{ - APIVersion: "rbac.authorization.k8s.io/v1", - Kind: "ClusterRoleBinding", - }, - ObjectMeta: metav1.ObjectMeta{ - Name: clusterRoleBindingName, - Namespace: i.Namespace, - Labels: map[string]string{"karmada.io/bootstrapping": "rbac-defaults"}, - }, - RoleRef: rbacv1.RoleRef{ - APIGroup: "rbac.authorization.k8s.io", - Kind: "ClusterRole", - Name: clusterRoleName, - }, - Subjects: []rbacv1.Subject{ - { - Kind: "ServiceAccount", - Name: saName, - Namespace: i.Namespace, - }, - }, - } -} - -// CreateClusterRole receive ClusterRoleFromSpec ClusterRole -func (i *CommandInitOption) CreateClusterRole() error { - clusterRole := i.ClusterRoleFromSpec(kubeControllerManagerClusterRoleAndDeploymentAndServiceName, []rbacv1.PolicyRule{ +// CreateControllerManagerRBAC karmada-controller-manager ClusterRole and ClusterRoleBinding +func (i *CommandInitOption) CreateControllerManagerRBAC() error { + labels := map[string]string{karmadaBootstrappingLabelKey: karmadaBootstrappingLabelValue} + // ClusterRole + clusterRole := utils.ClusterRoleFromRules(controllerManagerDeploymentAndServiceName, []rbacv1.PolicyRule{ { APIGroups: []string{"*"}, Resources: []string{"*"}, @@ -64,48 +20,25 @@ func (i *CommandInitOption) CreateClusterRole() error { NonResourceURLs: []string{"*"}, Verbs: []string{"get"}, }, - }) - - clusterRoleClient := i.KubeClientSet.RbacV1().ClusterRoles() - - clusterRoleList, err := clusterRoleClient.List(context.TODO(), metav1.ListOptions{}) + }, labels) + err := utils.CreateIfNotExistClusterRole(i.KubeClientSet, clusterRole) if err != nil { return err } - for _, v := range clusterRoleList.Items { - if clusterRole.Name == v.Name { - klog.Warningf("ClusterRole %s already exists.", clusterRole.Name) - return nil - } + // ClusterRoleBinding + clusterRoleBinding := utils.ClusterRoleBindingFromSubjects(controllerManagerDeploymentAndServiceName, controllerManagerDeploymentAndServiceName, + []rbacv1.Subject{ + { + Kind: "ServiceAccount", + Name: controllerManagerDeploymentAndServiceName, + Namespace: i.Namespace, + }, + }, labels) + err = utils.CreateIfNotExistClusterRoleBinding(i.KubeClientSet, clusterRoleBinding) + if err != nil { + return err } - _, err = clusterRoleClient.Create(context.TODO(), clusterRole, metav1.CreateOptions{}) - if err != nil { - return fmt.Errorf("create ClusterRole %s failed: %v", clusterRole.Name, err) - } - return nil -} - -// CreateClusterRoleBinding receive ClusterRoleBindingFromSpec ClusterRoleBinding -func (i *CommandInitOption) CreateClusterRoleBinding(clusterRole *rbacv1.ClusterRoleBinding) error { - crbClient := i.KubeClientSet.RbacV1().ClusterRoleBindings() - - crbList, err := crbClient.List(context.TODO(), metav1.ListOptions{}) - if err != nil { - return err - } - - for _, v := range crbList.Items { - if clusterRole.Name == v.Name { - klog.Infof("CreateClusterRoleBinding %s already exists.", clusterRole.Name) - return nil - } - } - - _, err = crbClient.Create(context.TODO(), clusterRole, metav1.CreateOptions{}) - if err != nil { - return err - } return nil } diff --git a/pkg/karmadactl/cmdinit/utils/rbac.go b/pkg/karmadactl/cmdinit/utils/rbac.go new file mode 100644 index 000000000..142c730ec --- /dev/null +++ b/pkg/karmadactl/cmdinit/utils/rbac.go @@ -0,0 +1,89 @@ +package utils + +import ( + "context" + "fmt" + + rbacv1 "k8s.io/api/rbac/v1" + apierrors "k8s.io/apimachinery/pkg/api/errors" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/client-go/kubernetes" + "k8s.io/klog/v2" +) + +// ClusterRoleFromRules ClusterRole Rules +func ClusterRoleFromRules(name string, rules []rbacv1.PolicyRule, labels map[string]string) *rbacv1.ClusterRole { + return &rbacv1.ClusterRole{ + TypeMeta: metav1.TypeMeta{ + APIVersion: "rbac.authorization.k8s.io/v1", + Kind: "ClusterRole", + }, + ObjectMeta: metav1.ObjectMeta{ + Name: name, + Labels: labels, + }, + Rules: rules, + } +} + +// ClusterRoleBindingFromSubjects ClusterRoleBinding Subjects +func ClusterRoleBindingFromSubjects(clusterRoleBindingName, clusterRoleName string, sub []rbacv1.Subject, labels map[string]string) *rbacv1.ClusterRoleBinding { + return &rbacv1.ClusterRoleBinding{ + TypeMeta: metav1.TypeMeta{ + APIVersion: "rbac.authorization.k8s.io/v1", + Kind: "ClusterRoleBinding", + }, + ObjectMeta: metav1.ObjectMeta{ + Name: clusterRoleBindingName, + Labels: labels, + }, + RoleRef: rbacv1.RoleRef{ + APIGroup: "rbac.authorization.k8s.io", + Kind: "ClusterRole", + Name: clusterRoleName, + }, + Subjects: sub, + } +} + +// CreateIfNotExistClusterRole create ClusterRole when it doesn't exist +func CreateIfNotExistClusterRole(clientSet *kubernetes.Clientset, role *rbacv1.ClusterRole) error { + clusterRoleClient := clientSet.RbacV1().ClusterRoles() + _, err := clusterRoleClient.Get(context.TODO(), role.Name, metav1.GetOptions{}) + if err != nil { + if apierrors.IsNotFound(err) { + _, err = clusterRoleClient.Create(context.TODO(), role, metav1.CreateOptions{}) + if err != nil { + return fmt.Errorf("create ClusterRole %s failed: %v", role.Name, err) + } + + klog.Infof("CreateClusterRole %s success.", role.Name) + return nil + } + return fmt.Errorf("get ClusterRole %s failed: %v", role.Name, err) + } + klog.Infof("CreateClusterRole %s already exists.", role.Name) + + return nil +} + +// CreateIfNotExistClusterRoleBinding create ClusterRoleBinding when it doesn't exist +func CreateIfNotExistClusterRoleBinding(clientSet *kubernetes.Clientset, binding *rbacv1.ClusterRoleBinding) error { + crbClient := clientSet.RbacV1().ClusterRoleBindings() + _, err := crbClient.Get(context.TODO(), binding.Name, metav1.GetOptions{}) + if err != nil { + if apierrors.IsNotFound(err) { + _, err = crbClient.Create(context.TODO(), binding, metav1.CreateOptions{}) + if err != nil { + return fmt.Errorf("create ClusterRoleBinding %s failed: %v", binding.Name, err) + } + + klog.Infof("CreateClusterRoleBinding %s success.", binding.Name) + return nil + } + return fmt.Errorf("get ClusterRoleBinding %s failed: %v", binding.Name, err) + } + klog.Infof("CreateClusterRoleBinding %s already exists.", binding.Name) + + return nil +}