调用k8s api实现添加用户并授权

一、k8s中根据用户名创建config文件

在k8s中如果想给一个用户创建授权文件,并让用户可用通过该config文件操作k8s集群,流程如下

1、生成私钥和证书签名请求(CSR)

# 生成私钥
[root@k8s-master01 config]# openssl genrsa -out dujie.key 2048
Generating RSA private key, 2048 bit long modulus (2 primes)
..................................................................+++++
...................................+++++
e is 65537 (0x010001)

# 生成证书签名请求(CSR)
[root@k8s-master01 config]# openssl req -new -key dujie.key -out dujie.csr -subj "/CN=username/O=organization"
[root@k8s-master01 config]# ll
总用量 8
-rw-r--r-- 1 root root  920 725 09:38 dujie.csr
-rw------- 1 root root 1679 725 09:38 dujie.key

2、创建CertificateSigningRequest资源

[root@k8s-master01 config]# kubectl create -f - <<EOF
apiVersion: certificates.k8s.io/v1
kind: CertificateSigningRequest
metadata:
  name: dujie-csr
spec:
  signerName: kubernetes.io/kube-apiserver-client
  groups:
  - system:authenticated
  request: $(cat dujie.csr | base64 | tr -d '\n')
  usages:
  - client auth
EOF

3、查看和审批CSR

[root@k8s-master01 config]# kubectl get csr 
NAME           AGE   SIGNERNAME                            REQUESTOR          REQUESTEDDURATION   CONDITION
dujie-csr      16s   kubernetes.io/kube-apiserver-client   kubernetes-admin   <none>              Pending

[root@k8s-master01 config]# kubectl certificate approve dujie-csr
certificatesigningrequest.certificates.k8s.io/dujie-csr approved

[root@k8s-master01 config]# kubectl get csr 
NAME           AGE   SIGNERNAME                            REQUESTOR          REQUESTEDDURATION   CONDITION
dujie-csr      35s   kubernetes.io/kube-apiserver-client   kubernetes-admin   <none>              Approved,Issued

4、获取已颁发的证书

你获取的是 Kubernetes 集群的 CA(Certificate Authority)证书的 Base64 编码数据。这些数据用于验证 Kubernetes API 服务器证书的根证书。

[root@k8s-master01 config]# kubectl get csr username-csr -o jsonpath='{.status.certificate}' | base64 --decode > dujie.crt

[root@k8s-master01 config]# 
[root@k8s-master01 config]# ll
总用量 12
-rw-r--r-- 1 root root 1123 725 09:40 dujie.crt
-rw-r--r-- 1 root root  920 725 09:38 dujie.csr
-rw------- 1 root root 1679 725 09:38 dujie.key
[root@k8s-master01 config]# cat dujie.crt 
-----BEGIN CERTIFICATE-----
MIIDEDCCAfigAwIBAgIRAKd4kXjh8llahVKABkuybNYwDQYJKoZIhvcNAQELBQAw
FTETMBEGA1UEAxMKa3ViZXJuZXRlczAeFw0yNDA3MjUwMDU3MzVaFw0yNTA3MjUw
MDU3MzVaMCoxFTATBgNVBAoTDG9yZ2FuaXphdGlvbjERMA8GA1UEAxMIdXNlcm5h
bWUwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDLckKDsUnp9ZMynLba
yZ47S8eldOtQSYP8637WzHJ1q2XZsTmGFXTAkJS9riMkV8BuDzhrOLHjJ/hmXZuR
QrCNGSLhXXsUfDlIa4iXtZNorv7kYzT7vkT0565wGnN1TPPQ9M18Z5PuaP/UpPtt
6K65rRRvi/zyVET/aT+WDd4b7J2WwH93dDbVqONIy7+Q/9BCo1UOobI5fWAiixTA
dZasKAQVaD8GD+ZMl8+kZrLA+TL8gdtapSYBrNbZplguTAWUDAcpXkvtMEoQiC4S
bp8VistfQ3Oxy3aLdycrNbdRrgjW6HHjMLBidQ+efVliQ4MP3rjjwB2VnSgpYZ8q
cPcbAgMBAAGjRjBEMBMGA1UdJQQMMAoGCCsGAQUFBwMCMAwGA1UdEwEB/wQCMAAw
HwYDVR0jBBgwFoAUDkfKuT1zeRu8QhIUBQWl6nwkCkAwDQYJKoZIhvcNAQELBQAD
ggEBABN0tqHPZMpxge0HmbjWkzGxqbbhkqHXgZx/ltG1MHF4nb5FQvUUaTwrY3xD
zYd7Wk6iBOQRS/Hh4bcDJd6iBVHfSk0vEfERYTO1GJRbJ8n4RWCJg89xVkuD6MBD
4MfVRRD5IW3zG58ycbIPmw428HvIwMFIFpZ+JURFwRyIFqfwgQxl61Sgr9RyQze7
H4Fd9xItRjFocwqrNXj6bbIctLC8XkhuT1teDQNhIiGvLxbaVsgaEdglkU0P2btZ
0cbxoCCwPcIWsKGL8YZtyCEAmNGD0BXIPydX5GDIX3xVgrDUxh1RL9YmUWFpyZo7
dRKpPWWwfWLFG/OWgToROVTfuSs=
-----END CERTIFICATE-----

5、配置kubernetes客户端

[root@k8s-master01 config]# kubectl config set-credentials dujie --client-certificate=dujie.crt --client-key=dujie.key
[root@k8s-master01 config]# kubectl config set-context --current --user=dujie

6、生成config文件

获取集群的ca证书

[root@k8s-master01 config]# kubectl config view --minify -o jsonpath='{.clusters[0].cluster.certificate-authority-data}'
DATA+OMITTED[root@k8s-master01 config]# 
[root@k8s-master01 config]# CA_CERT=$(kubectl config view --minify -o jsonpath='{.clusters[0].cluster.certificate-authority-data}')

使用以下命令创建一个新的 kubeconfig 文件,其中包含 dujie 用户的凭据信息。假设 API 服务器地址是 https://<api-server-address>:6443,并使用上述命令生成的 CA 证书数据:

cat <<EOF > dujie.kubeconfig
apiVersion: v1
kind: Config
clusters:
- cluster:
    certificate-authority-data: ${CA_CERT}
    server: https://<api-server-address>:6443
  name: kubernetes
contexts:
- context:
    cluster: kubernetes
    user: dujie
  name: dujie-context
current-context: dujie-context
users:
- name: dujie
  user:
    client-certificate: dujie.crt
    client-key: dujie.key
EOF

上面的操作仅仅只是生成一个config文件,并没有对该用户授权。所以还无法操作k8s集群,授权操作自行查询,下面主要演示如何使用go对k8s集群生成授权文件、添加用户并授权等操作。

二、golang中如何创建用户授权文件

初衷:开发一个k8s多集群管理平台,且可以根据当前登录的平台用户对k8s集群资源进行授权操作。

大体流程如下:

  1. 获取k8s客户端:获取k8s客户端对象clientset,通过clientset对k8s Api进行交互,执行创建和管理资源的操作
  2. 生成私钥:生成RSA私钥,用于生成证书请求,并在后续的链接中用于客户端认证
  3. 生成证书请求(CSR):根据传入的用户名和私钥,生成一个证书签名请求(CSR),该CSR中包含了请求证书和公钥和相关的身份信息,然后提交给ca请求签发证书
  4. 创建CertificateSigningRequest资源:用于请求管理员和自动系统批准和签发证书
  5. 审批CSR:为 createResp.Status.Conditions 添加批准条件,并更新 CSR 的审批状态
  6. 等待证书颁发:在一个循环中不断检查 CSR 的状态,看是否已颁发证书
  7. 删除已颁发证书的CSR:在证书颁发后,删除相应的 CSR 对象。

第一步先看下我这里的系统表、集群表、还有集群用户表的结构

集群表:

Users 设置为[]Users 表示1个集群可以被多个用户访问和管理

// k8sCluster表 结构体  K8sCluster
type K8sCluster struct {
	ID                 uint      `json:"id" gorm:"not null;unique;primary_key"`
	UUID               uuid.UUID `json:"uuid" gorm:"comment:集群UUID"`
	Name               string    `json:"name" form:"name" gorm:"comment:集群名称"`
	KubeType           uint      `json:"kube_type" form:"kube_type" gorm:"comment:凭据类型1:KubeConfig,2:Token"`
	KubeConfig         string    `gorm:"type:longText" json:"kube_config" form:"kube_config" gorm:"comment:kube_config"`
	KubeCaCrt          string    `gorm:"type:longText; comment:ca.crt" json:"kube_ca_crt" form:"kube_ca_crt"`
	ApiAddress         string    `gorm:"type:longText" json:"api_address" form:"api_address" gorm:"comment:api_address"`
	PrometheusUrl      string    `gorm:"type:longText" json:"prometheus_url" form:"prometheus_url" gorm:"comment:prometheus 地址"`
	PrometheusAuthType uint      `json:"prometheus_auth_type" form:"prometheus_auth_type" gorm:"comment: 认证类型"`
	PrometheusUser     string    `gorm:"type:longText" json:"prometheus_user" form:"prometheus_user" gorm:"comment:用户名"`
	PrometheusPwd      string    `gorm:"type:longText" json:"prometheus_pwd" form:"prometheus_pwd" gorm:"comment:密码"`
	Users              []User    `json:"users" gorm:"foreignKey:ClusterId;"` # foreignKey指定外键,在Use表有个字段为ClusterId,关联到K8sCluster表的主键字段
	CreatedBy          uint      `gorm:"column:created_by;comment:创建者"`
	UpdatedBy          uint      `gorm:"column:updated_by;comment:更新者"`
	DeletedBy          uint      `gorm:"column:deleted_by;comment:删除者"`
	CreatedAt          time.Time     
	UpdatedAt          time.Time      
	DeletedAt          gorm.DeletedAt `gorm:"index" json:"-"`
}

k8s的User表

type User struct {
	ID             uint           `json:"id" gorm:"not null;unique;primary_key"`
	UUID           uuid.UUID      `json:"uuid" gorm:"comment:用户UUID"`
	Username       string         `json:"userName" gorm:"comment:用户登录名"`
	NickName       string         `json:"nickName" gorm:"default:系统用户;comment:用户昵称"`
	KubeConfig     string         `gorm:"type:longText" json:"kube_config" form:"kube_config" gorm:"comment:kube_config"`
	ClusterRoles   string         `gorm:"type:longText" json:"cluster_roles"`
	NamespaceRoles string         `json:"namespace_roles" gorm:"comment:命名空间权限"`
	ClusterId      uint           `json:"cluster_id" gorm:"comment:集群ID"`
	CreatedAt      time.Time      `json:"created_at"`
	UpdatedAt      time.Time      `json:"updated_at"`
	DeletedAt      gorm.DeletedAt `gorm:"index" json:"-"`
}

平台用户表

type SysUser struct {
	ID        uint           `gorm:"primarykey" json:"ID"` 
	CreatedAt time.Time      
	UpdatedAt time.Time      
	DeletedAt gorm.DeletedAt `gorm:"index" json:"-"` 
	UUID        uuid.UUID      `json:"uuid" gorm:"index;comment:用户UUID"`  
	Username    string         `json:"userName" gorm:"index;comment:用户登录名"`    
	Password    string         `json:"-"  gorm:"comment:用户登录密码"`   
	NickName    string         `json:"nickName" gorm:"default:系统用户;comment:用户昵称"`             
	AuthorityId uint           `json:"authorityId" gorm:"default:888;comment:用户角色ID"`   
	Authority   SysAuthority   `json:"authority" gorm:"foreignKey:AuthorityId;references:AuthorityId;comment:用户角色"`
	Authorities []SysAuthority `json:"authorities" gorm:"many2many:sys_user_authority;"`
	Phone       string         `json:"phone"  gorm:"comment:用户手机号"`                    
	Email       string         `json:"email"  gorm:"comment:用户邮箱"`                    
	Enable      int            `json:"enable" gorm:"default:1;comment:用户是否被冻结 1正常 2冻结"` 
}

创建凭据方法:

clusterId:用户上传的集群id,区分对哪个集群进行创建凭据

userId:当前平台登录的用户id

func (K8sClusterService *K8sClusterService) CreateCredential(clusterId int, userId uint) error {
	// 根据当前平台登录的用户id获取用户信息
	var user system.SysUser
	if err := global.DY_DB.Where("id = ?", userId).First(&user).Error; err != nil {
		return err
	}
	// 根据当前平台登录的用户的uuid,和上传的集群id查询集群信息,同时预加载相关的用户信息
	var clusterIns cluster.K8sCluster
	if err := global.DY_DB.Where("id = ?", clusterId).Preload("Users", "uuid = ?", user.UUID).First(&clusterIns).Error; err != nil {
		return err
	}
	if !errors.Is(global.DY_DB.Where("cluster_id = ? and uuid = ?", clusterId, user.UUID).First(&cluster.User{}).Error, gorm.ErrRecordNotFound) {
		return errors.New("该账号集群凭据已存在")
	}
	fmt.Println(clusterIns)
	// CreateClientCertificate
	// 构建kubernetes 实例
	k := kubernetes.NewKubernetes(&clusterIns, &cluster.User{}, true)
	// 生成对应的客户端证书,返回私钥和公钥
	privateKey, publicCert, err := k.CreateClientCertificate(user.Username)
	if err != nil {
		return errors.New("CreateClientCertificate, error:" + err.Error())
	}

	// To JSON
	kubeConfig, err := k.KubeconfigJson(clusterIns, user.Username, privateKey, publicCert)
	if err != nil {
		return errors.New("To YAML, error:" + err.Error())
	}

	// save User
	if err = global.DY_DB.Save(&cluster.User{
		UUID:       user.UUID,
		Username:   user.Username,
		NickName:   user.NickName,
		KubeConfig: kubeConfig,
		ClusterId:  uint(clusterId),
	}).Error; err != nil {
		return err
	}

	return err
}

CreateClientCertificate 方法创建集群证书,返回私钥和公钥

func (k *Kubernetes) CreateClientCertificate(username string) (privateKey, publicCert string, err error) {
	// 获取clientSet客户端
	clientset, err := k.Client()
	if err != nil {
		return privateKey, publicCert, err
	}

	// 生成一个私钥
	RandprivateKey, err := GeneratePrivateKey()
	if err != nil {
		return privateKey, publicCert, err
	}

	// 生成用户证书申请
	cert, err := CreateClientCertificateRequest(username, RandprivateKey)
	if err != nil {
		return privateKey, publicCert, err
	}
	// 创建k8s证书签名请求(CSR)
	csr := certv1.CertificateSigningRequest{
		ObjectMeta: metav1.ObjectMeta{
			Name: username,
		},
		Spec: certv1.CertificateSigningRequestSpec{
			SignerName: "kubernetes.io/kube-apiserver-client", // 指定签名者
			Request:    cert,                                  // 设置CSR 请求的证书
			Groups: []string{
				"system:authenticated", // 指定用户组
			},
			Usages: []certv1.KeyUsage{
				"client auth", // 指定证书用途为客户端认证
			},
		},
	}
	// 在k8s集群中创建CSR
	createResp, err := clientset.CertificatesV1().CertificateSigningRequests().Create(context.TODO(), &csr, metav1.CreateOptions{})
	if err != nil {
		return privateKey, publicCert, err
	}

	// 审批CSR证书
	createResp.Status.Conditions = append(createResp.Status.Conditions, certv1.CertificateSigningRequestCondition{
		Reason:         "Approved by Devops",
		Type:           certv1.CertificateApproved,
		LastUpdateTime: metav1.Now(),
		Status:         "True",
	})
	// 更新CSR的审批状态
	updateResp, err := clientset.CertificatesV1().CertificateSigningRequests().UpdateApproval(context.TODO(), createResp.Name, createResp, metav1.UpdateOptions{})
	if err != nil {
		return privateKey, publicCert, err
	}
	// 循环等待证书颁发
	for {
		max_num := 0
		for {
			// 每次循环等待3秒
			time.Sleep(3 * time.Second)
			if max_num > 150 {
				break
			}
			// 获取CSR的状态
			getResp, err := clientset.CertificatesV1().CertificateSigningRequests().Get(context.TODO(), updateResp.Name, metav1.GetOptions{})
			if err != nil {
				max_num += 1
				global.DY_LOG.Warn("CertificateSigningRequests Get failed: " + err.Error())
				continue
			}
			// 检查CSR是否已经颁发证书
			if getResp.Status.Certificate != nil {
				// 删除已经颁发证书的CSR
				if err = clientset.CertificatesV1().CertificateSigningRequests().Delete(context.TODO(), username, metav1.DeleteOptions{}); err != nil {
					max_num += 1
					global.DY_LOG.Warn("CertificateSigningRequests Get failed: " + err.Error())
					continue
				}
				// 返回私钥和公钥证书(编码为Base64)
				return base64.StdEncoding.EncodeToString(
					pem.EncodeToMemory(&pem.Block{Type: "RSA PRIVATE KEY", Bytes: RandprivateKey}),
				), base64.StdEncoding.EncodeToString(getResp.Status.Certificate), err
			}

			max_num += 1
			continue
		}
	}
}

GeneratePrivateKey:生成私钥文件

// GeneratePrivateKey
//
//	@Description: 生成私钥
//	@return []byte
//	@return error
func GeneratePrivateKey() ([]byte, error) {
	privateKey, err := rsa.GenerateKey(rand.Reader, 2048)
	if err != nil {
		return nil, err
	}

	return x509.MarshalPKCS1PrivateKey(privateKey), nil
}

CreateClientCertificateRequest:根据私钥文件,生成客户端证书CSR

func CreateClientCertificateRequest(userName string, key []byte, org ...string) ([]byte, error) {
	// 解析PEM 编码的RSA私钥
	privateKey, err := x509.ParsePKCS1PrivateKey(key)
	if err != nil {
		return nil, err
	}
	// 构建证书请求的主题信息,包括用户名等
	subj := pkix.Name{
		CommonName: userName,
	}
	for i := range org {
		subj.Organization = append(subj.Organization, org[i])
	}
	// 将主题信息转换为RDN序列
	rawSubj := subj.ToRDNSequence()
	// 使用ASN.1 编码主题
	asn1Subj, err := asn1.Marshal(rawSubj)
	if err != nil {
		return nil, err
	}
	// 创建x509的证书请求对象
	csr := &x509.CertificateRequest{
		RawSubject:         asn1Subj,
		SignatureAlgorithm: x509.SHA256WithRSA,
	}
	// 生成证书CSR
	csrBytes, err := x509.CreateCertificateRequest(rand.Reader, csr, privateKey)
	if err != nil {
		return nil, err
	}
	// 将CSR转为PEM格式
	return pem.EncodeToMemory(&pem.Block{Type: "CERTIFICATE REQUEST", Bytes: csrBytes}), nil
}

调用创建授权方法之后,k8s_users表就会多出一条记录,该记录就是一个集群用户,其中的kube_config字段就是对应的k8sconfig文件,创建的用户权限根据k8s_cluster表的kubeconfig文件权限一致

image

image

image

上面的方法可以给当前登录的平台用户申请授权文件,而想给平台的其他用户授权呢,如下图,给wangwu用户授权k8s集群的操作权限,需要:

  • 配置默认的集群角色
  • 创建集群角色
  • 根据角色创建对应用户(用户授权)

image

配置默认集群角色

// CreateDefaultClusterRoles 创建或更新默认的 Kubernetes ClusterRoles
// 返回值:
// - error: 如果创建或更新过程中出现问题,则返回相应的错误信息
func (k *Kubernetes) CreateDefaultClusterRoles() error {
    // 获取 Kubernetes 客户端
    clientset, err := k.Client()
    if err != nil {
        global.GVA_LOG.Error("clientset init failed: " + err.Error())
        return err
    }

    // 遍历初始化的 ClusterRoles 列表
    for i := range InitClusterRoles {
        // 尝试获取现有的 ClusterRole
        instance, err := clientset.RbacV1().ClusterRoles().Get(context.TODO(), InitClusterRoles[i].Name, metav1.GetOptions{})
        if err != nil {
            // 如果错误不是 "not found",则返回错误
            if !strings.Contains(strings.ToLower(err.Error()), "not found") {
                return err
            }
        }

        // 如果 ClusterRole 不存在,则创建新的 ClusterRole
        if instance == nil || instance.Name == "" {
            _, err = clientset.RbacV1().ClusterRoles().Create(context.TODO(), &InitClusterRoles[i], metav1.CreateOptions{})
            if err != nil {
                return err
            }
        } else {
            // 如果 ClusterRole 存在,则更新现有的 ClusterRole
            _, err = clientset.RbacV1().ClusterRoles().Update(context.TODO(), &InitClusterRoles[i], metav1.UpdateOptions{})
            if err != nil {
                return err
            }
        }
    }

    // 返回 nil 表示操作成功
    return nil
}

创建集群角色:

type NamespaceRoles struct {
	Namespace string   `json:"namespace"`
	Roles     []string `json:"roles"`
}
type CreateClusterRole struct {
	ClusterRoles   []string         `json:"cluster_roles"`
	NamespaceRoles []NamespaceRoles `json:"namespace_roles"`
	UserUuids      []string         `json:"user_uuids"`
	cluster.User
	ClusterId int `json:"cluster_id"`
}
// CreateClusterRole
//
//	@Description: 创建k8s集群角色
//	@receiver k8sClusterService
//	@param role  包含要创建的角色数据的结构体
//	@return err
func (k8sClusterService *K8sClusterService) CreateClusterRole(role cluster.RoleData) (err error) {
	// 根据角色中的 ClusterId 查找对应的 Kubernetes 集群实例
	var clusterIns cluster.K8sCluster
	if err := global.DY_DB.Where("id = ?", role.ClusterId).First(&clusterIns).Error; err != nil {
		return err
	}
	// 遍历角色规则中的 API 组,将 "core" 替换为空字符串
	for i := range role.Rules {
		for j := range role.Rules[i].APIGroups {
			if role.Rules[i].APIGroups[j] == "core" {
				role.Rules[i].APIGroups[j] = ""
			}
		}
	}
	// 创建 Kubernetes 客户端实例
	k := kubernetes.NewKubernetes(&clusterIns, &cluster.User{}, true)
	client, err := k.Client()
	if err != nil {
		return err
	}
	// 设置角色的注解和标签
	role.Annotations["builtin"] = "false"
	role.Annotations["created-at"] = time.Now().Format("2006-01-02 15:04:05")
	role.Labels[kubernetes.LabelManageKey] = "devops"
	role.Labels[kubernetes.LabelClusterId] = clusterIns.UUID.String()
	// 使用 Kubernetes 客户端创建集群角色
	_, err = client.RbacV1().ClusterRoles().Create(context.TODO(), &role.ClusterRole, metav1.CreateOptions{})
	if err != nil {
		return err
	}

	return err
}

创建集群用户并授权

// CreateUser
//
//	@Description: 在k8s中为给定的角色创建用户
//	@receiver k8sClusterService
//	@param role
//	@return err
func (k8sClusterService *K8sClusterService) CreateUser(role clusterReq.CreateClusterRole) (err error) {
	// 遍历 role.UserUuids 列表,处理每个用户的创建操作
	for _, userUuid := range role.UserUuids {
		// 启动一个新的 goroutine 来并行处理每个用户的创建
		go func(u string, r clusterReq.CreateClusterRole) {
			var user system.SysUser
			// 根据用户的 UUID 从数据库中查找对应的用户记录
			if err = global.DY_DB.Where("uuid = ?", u).First(&user).Error; err != nil {
				global.DY_LOG.Warn("User Not Found failed:" + err.Error())
				return
			}
			// 检查该用户是否已经存在于指定的集群中
			if !errors.Is(global.DY_DB.Where("cluster_id = ? and uuid = ?", r.ClusterId, user.UUID).First(&cluster.User{}).Error, gorm.ErrRecordNotFound) {
				global.DY_LOG.Warn(fmt.Sprintf("The User: %s cluster credentials for this account already exist", user.NickName))
				return
			}
			// 调用 CreateClusterUser 方法来为用户创建集群凭证
			if err = k8sClusterService.CreateClusterUser(r, user); err != nil {
				global.DY_LOG.Error("CreateClusterUser failed: " + err.Error())
				return
			}

			return
		}(userUuid, role)
	}

	return err
}

// CreateClusterUser
//
//	@Description: 为给定角色和平台用户在k8s中创建集群用户
//	@receiver k8sClusterService
//	@param role
//	@param user
//	@return err
func (k8sClusterService *K8sClusterService) CreateClusterUser(role clusterReq.CreateClusterRole, user system.SysUser) (err error) {
	// 根据角色中的 ClusterId 查找对应的 Kubernetes 集群实例
	var clusterIns cluster.K8sCluster
	if err := global.DY_DB.Where("id = ?", role.ClusterId).First(&clusterIns).Error; err != nil {
		return err
	}
	// 为用户创建集群凭据
	if err = k8sClusterService.CreateCredential(role.ClusterId, user.ID); err != nil {
		return errors.New("为用户创建集群凭据失败" + err.Error())
	}
	// 创建 Kubernetes 客户端实例
	k := kubernetes.NewKubernetes(&clusterIns, &cluster.User{}, true)
	// 查找用户在集群中的数据
	var userData cluster.User
	if err = global.DY_DB.Where("cluster_id = ? and uuid = ?", role.ClusterId, user.UUID).First(&userData).Error; err != nil {
		return err
	}
	// 如果角色包含 ClusterRoles,则进行相应处理
	if len(role.ClusterRoles) > 0 {
		// 将 ClusterRoles 转换为 JSON 字符串
		clusterRolesString, err := json.Marshal(role.ClusterRoles)
		if err != nil {
			return err
		}
		// 启动一个新的 goroutine 处理 ClusterRoleBinding 的创建和更新
		go func(id uint, clusterRolesString string) {
			// 创建或更新 ClusterRoleBinding
			for r := range role.ClusterRoles {
				if err = k.CreateOrUpdateClusterRoleBinding(role.ClusterRoles[r], user.Username, false); err != nil {
					global.DY_LOG.Error("CreateOrUpdateClusterRoleBinding failed:" + err.Error())
				}
			}

			// 更新集群授权
			if err = global.DY_DB.Model(&cluster.User{}).Where("id = ?", id).Update("cluster_roles", clusterRolesString).Error; err != nil {
				global.DY_LOG.Error("CreateOrUpdateClusterRoleBinding Cluster Role failed:" + err.Error())
			}
		}(userData.ID, string(clusterRolesString))
	}
	// 如果角色包含 NamespaceRoles,则进行相应处理
	if len(role.NamespaceRoles) > 0 {
		// 将 NamespaceRoles 转换为 JSON 字符串
		namespaceRolesString, err := json.Marshal(role.NamespaceRoles)
		if err != nil {
			return err
		}
		// 启动一个新的 goroutine 处理 Rolebinding 的创建和更新
		go func(id uint, namespaceRolesString string) {
			// 创建或更新 Rolebinding
			for r := range role.NamespaceRoles {
				for j := range role.NamespaceRoles[r].Roles {
					if err := k.CreateOrUpdateRolebinding(role.NamespaceRoles[r].Namespace, role.NamespaceRoles[r].Roles[j], user.Username, false); err != nil {
						global.DY_LOG.Error("CreateOrUpdateRolebinding Namespace role failed:" + err.Error())
					}

				}
			}

			// 更新命名空间授权
			if err = global.DY_DB.Model(&cluster.User{}).Where("id = ?", id).Update("cluster_roles", namespaceRolesString).Error; err != nil {
				global.DY_LOG.Error("CreateOrUpdateClusterRoleBinding Cluster Role failed:" + err.Error())
			}
		}(userData.ID, string(namespaceRolesString))
	}

	return err
}

创建或更新k8s clusterRoleBinding

// CreateOrUpdateClusterRoleBinding
//
//	@Description: 创建或更新k8s ClusterRoleBinding
//	@receiver k
//	@param clusterRoleName
//	@param username  用户名
//	@param builtIn 是否内置
//	@return error
func (k *Kubernetes) CreateOrUpdateClusterRoleBinding(clusterRoleName string, username string, builtIn bool) error {
	client, err := k.Client()
	if err != nil {
		return err
	}
	// 生成 ClusterRoleBinding 的名称
	name := fmt.Sprintf("%s:%s:%s", username, clusterRoleName, k.K8sCluster.UUID.String())
	labels := map[string]string{
		LabelManageKey: "devops",
		LabelClusterId: k.K8sCluster.UUID.String(),
		LabelUsername:  username,
	}
	annotations := map[string]string{
		"built-in":   strconv.FormatBool(builtIn),
		"created-at": time.Now().Format("2006-01-02 15:04:05"),
	}
	// 创建 ClusterRoleBinding 对象
	item := rbacV1.ClusterRoleBinding{
		ObjectMeta: metav1.ObjectMeta{
			Name:        name,
			Labels:      labels,
			Annotations: annotations,
		},
		Subjects: []rbacV1.Subject{
			{
				Kind: "User",
				Name: username,
			},
		},
		RoleRef: rbacV1.RoleRef{
			Kind: "ClusterRole",
			Name: clusterRoleName,
		},
	}
	// 获取现有的 ClusterRoleBinding
	baseItem, err := client.RbacV1().ClusterRoleBindings().Get(context.TODO(), name, metav1.GetOptions{})
	if err != nil {
		if !strings.Contains(err.Error(), "not found") {
			return err
		}
	}

	if baseItem != nil && baseItem.Name != "" {
		_, err := client.RbacV1().ClusterRoleBindings().Create(context.TODO(), &item, metav1.CreateOptions{})
		if err != nil {
			return err
		}
	} else {
		_, err := client.RbacV1().ClusterRoleBindings().Update(context.TODO(), &item, metav1.UpdateOptions{})
		if err != nil {
			return err
		}
	}
	return nil
}

创建或更新k8s RoleBinding

// CreateOrUpdateRolebinding
//
//	@Description: 创建或更新k8s RoleBinding
//	@receiver k
//	@param namespace
//	@param clusterRoleName
//	@param username
//	@param builtIn
//	@return error
func (k *Kubernetes) CreateOrUpdateRolebinding(namespace string, clusterRoleName string, username string, builtIn bool) error {
	client, err := k.Client()
	if err != nil {
		return err
	}
	// 设置标签
	labels := map[string]string{
		LabelManageKey: "devops",
		LabelClusterId: k.K8sCluster.UUID.String(),
		LabelUsername:  username,
	}
	// 设置注解
	annotations := map[string]string{
		"built-in":   strconv.FormatBool(builtIn),
		"created-at": time.Now().Format("2006-01-02 15:04:05"),
	}
	// 生成RoleBinding的名称
	name := fmt.Sprintf("%s:%s:%s:%s", namespace, username, clusterRoleName, k.K8sCluster.UUID)
	// 创建RoleBinding对象
	item := rbacV1.RoleBinding{
		ObjectMeta: metav1.ObjectMeta{
			Name:        name,
			Labels:      labels,
			Annotations: annotations,
			Namespace:   namespace,
		},
		Subjects: []rbacV1.Subject{
			{
				Kind: "User",
				Name: username,
			},
		},
		RoleRef: rbacV1.RoleRef{
			Kind: "ClusterRole",
			Name: clusterRoleName,
		},
	}
	// 获取现有的 RoleBinding
	baseItem, err := client.RbacV1().RoleBindings(namespace).Get(context.TODO(), name, metav1.GetOptions{})
	if err != nil {
		if !strings.Contains(err.Error(), "not found") {
			return err
		}
	}
	// 如果 RoleBinding 不存在,则创建新的 RoleBinding
	if baseItem != nil && baseItem.Name != "" {
		_, err := client.RbacV1().RoleBindings(namespace).Create(context.TODO(), &item, metav1.CreateOptions{})
		if err != nil {
			return err
		}
	} else {
		// 如果 RoleBinding 存在,则更新现有的 RoleBinding
		_, err := client.RbacV1().RoleBindings(namespace).Update(context.TODO(), &item, metav1.UpdateOptions{})
		if err != nil {
			return err
		}
	}
	return nil
}

这样就可以根据平台用户名添加集群用户,指定集群用户的集群权限、命名空间权限了

image