调用k8s API实现添加用户并授权
调用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 7月 25 09:38 dujie.csr
-rw------- 1 root root 1679 7月 25 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 7月 25 09:40 dujie.crt
-rw-r--r-- 1 root root 920 7月 25 09:38 dujie.csr
-rw------- 1 root root 1679 7月 25 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集群资源进行授权操作。
大体流程如下:
- 获取k8s客户端:获取k8s客户端对象clientset,通过clientset对k8s Api进行交互,执行创建和管理资源的操作
- 生成私钥:生成RSA私钥,用于生成证书请求,并在后续的链接中用于客户端认证
- 生成证书请求(CSR):根据传入的用户名和私钥,生成一个证书签名请求(CSR),该CSR中包含了请求证书和公钥和相关的身份信息,然后提交给ca请求签发证书
- 创建CertificateSigningRequest资源:用于请求管理员和自动系统批准和签发证书
- 审批CSR:为
createResp.Status.Conditions
添加批准条件,并更新 CSR 的审批状态 - 等待证书颁发:在一个循环中不断检查 CSR 的状态,看是否已颁发证书
- 删除已颁发证书的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文件权限一致
上面的方法可以给当前登录的平台用户申请授权文件,而想给平台的其他用户授权呢,如下图,给wangwu用户授权k8s集群的操作权限,需要:
- 配置默认的集群角色
- 创建集群角色
- 根据角色创建对应用户(用户授权)
配置默认集群角色
// 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
}
这样就可以根据平台用户名添加集群用户,指定集群用户的集群权限、命名空间权限了