由 SuKai January 5, 2022
在Kubernetes里User只是一个用户身份辨识的ID,没有真正用户管理,k8s一般通过第三方提供用户管理和存储,k8s通过User进行身份验证与权限认证。
Kubernetes用户验证支持X509证书认证,token认证和密码验证几种方式。
RBAC是Kubernetes进行权限控制的方式。用户与角色绑定,赋予角色权限。
今天我们来一起看一下Kubesphere如何通过Operator实现kubernetes用户管理。我们在Kubernetes里创建User自定义资源,使用LDAP存储用户帐号信息。通过Kubernets CertificateSigningRequest请求X509证书,生成Kubeconfig。通过各种自定义Role资源来创建Kubernetes Role与用户绑定,分配用户权限。最终用户通过客户端使用kubeconfig来访问Kubernetes资源。
这个场景不像Dex这种Kubernetes OpenID服务,他不需要在Kubernetes APIServer上进行配置,改变Kubernetes集群的部署配置。
代码主要流程
1, User控制器调谐,创建LDAP用户,创建用户KubeConfig的Configmap
2, 在CreateKubeConfig生成kubeconfig用户信息,创建CertificateSigningRequest
3, 在Informer中监听CertificateSigningRequest事件,Approve请求,更新Configmap中用户kubeconfig的证书
代码实现
主入口,创建Kubernetes集群Client,创建Informer,创建controller,在controller的mgr中添加user, kubeconfig自定义资源控制器。
func run(s *options.AIScopeControllerManagerOptions, ctx context.Context) error {
kubernetesClient, err := k8s.NewKubernetesClient(s.KubernetesOptions)
if err != nil {
klog.Errorf("Failed to create kubernetes clientset %v", err)
return err
}
informerFactory := informers.NewInformerFactories(
kubernetesClient.Kubernetes())
mgrOptions := manager.Options{
Port: 8443,
}
if s.LeaderElect {
mgrOptions = manager.Options{
Port: 8443,
LeaderElection: s.LeaderElect,
LeaderElectionNamespace: "aiscope-system",
LeaderElectionID: "aiscope-controller-manager-leader-election",
LeaseDuration: &s.LeaderElection.LeaseDuration,
RetryPeriod: &s.LeaderElection.RetryPeriod,
RenewDeadline: &s.LeaderElection.RenewDeadline,
}
}
klog.V(0).Info("setting up manager")
ctrl.SetLogger(klogr.New())
mgr, err := manager.New(kubernetesClient.Config(), mgrOptions)
if err != nil {
klog.Fatalf("unable to set up overall controller manager: %v", err)
}
if err = apis.AddToScheme(mgr.GetScheme()); err != nil {
klog.Fatalf("unable add APIs to scheme: %v", err)
}
// register common meta types into schemas.
metav1.AddToGroupVersion(mgr.GetScheme(), metav1.SchemeGroupVersion)
kubeconfigClient := kubeconfig.NewOperator(kubernetesClient.Kubernetes(),
informerFactory.KubernetesSharedInformerFactory().Core().V1().ConfigMaps().Lister(),
kubernetesClient.Config())
userController := user.Reconciler{
MaxConcurrentReconciles: 4,
KubeconfigClient: kubeconfigClient,
}
if err = userController.SetupWithManager(mgr); err != nil {
klog.Fatalf("Unable to create user controller: %v", err)
}
if err = addControllers(mgr,
kubernetesClient,
informerFactory,
ctx.Done()); err != nil {
klog.Fatalf("unable to register controllers to the manager: %v", err)
}
// Start cache data after all informer is registered
klog.V(0).Info("Starting cache resource from apiserver...")
informerFactory.Start(ctx.Done())
klog.V(0).Info("Starting the controllers.")
if err = mgr.Start(ctx); err != nil {
klog.Fatalf("unable to run the manager: %v", err)
}
return nil
}
添加Certificatessigningrequest控制器
func addControllers(mgr manager.Manager, client k8s.Client, informerFactory informers.InformerFactory, stopCh <-chan struct{}) error {
kubernetesInformer := informerFactory.KubernetesSharedInformerFactory()
csrController := certificatesigningrequest.NewController(client.Kubernetes(),
kubernetesInformer.Certificates().V1().CertificateSigningRequests(),
kubernetesInformer.Core().V1().ConfigMaps(), client.Config())
controllers := map[string]manager.Runnable{
"csr-controller": csrController,
}
for name, ctrl := range controllers {
if ctrl == nil {
klog.V(4).Infof("%s is not going to run due to dependent component disabled.", name)
continue
}
if err := mgr.Add(ctrl); err != nil {
klog.Error(err, "add controller to manager failed", "name", name)
return err
}
}
return nil
}
User控制器,调用LDAP用户创建,创建用户kubeconfig configmap
func (r *Reconciler) Reconcile(ctx context.Context, req reconcile.Request) (reconcile.Result, error) {
// we do not need to sync ldap info when ldapClient is nil
if r.LdapClient != nil {
// ignore errors if timeout
if err = r.waitForSyncToLDAP(user); err != nil {
// ignore timeout error
r.Recorder.Event(user, corev1.EventTypeWarning, failedSynced, fmt.Sprintf(syncFailMessage, err))
}
}
if r.KubeconfigClient != nil {
// ensure user KubeconfigClient configmap is created
if err = r.KubeconfigClient.CreateKubeConfig(user); err != nil {
klog.Error(err)
r.Recorder.Event(user, corev1.EventTypeWarning, failedSynced, fmt.Sprintf(syncFailMessage, err))
return ctrl.Result{}, err
}
}
return ctrl.Result{}, nil
}
Kubeconfig,createCSR创建certificatesigningrequest,创建ConfigMap
// CreateKubeConfig Create kubeconfig configmap in KubeSphereControlNamespace for the specified user
func (o *operator) CreateKubeConfig(user *iamv1alpha2.User) error {
if err = o.createCSR(user.Name); err != nil {
klog.Errorln(err)
return err
}
currentContext := fmt.Sprintf("%s@%s", user.Name, defaultClusterName)
config := clientcmdapi.Config{
Kind: configMapKind,
APIVersion: configMapAPIVersion,
Preferences: clientcmdapi.Preferences{},
Clusters: map[string]*clientcmdapi.Cluster{defaultClusterName: {
Server: o.config.Host,
InsecureSkipTLSVerify: false,
CertificateAuthorityData: ca,
}},
Contexts: map[string]*clientcmdapi.Context{currentContext: {
Cluster: defaultClusterName,
AuthInfo: user.Name,
Namespace: defaultNamespace,
}},
CurrentContext: currentContext,
}
kubeconfig, err := clientcmd.Write(config)
if err != nil {
klog.Error(err)
return err
}
// create a new config
cm = &corev1.ConfigMap{
TypeMeta: metav1.TypeMeta{
Kind: configMapKind,
APIVersion: configMapAPIVersion,
},
ObjectMeta: metav1.ObjectMeta{
Name: configName,
Labels: map[string]string{constants.UsernameLabelKey: user.Name},
},
Data: map[string]string{kubeconfigFileName: string(kubeconfig)},
}
if err = controllerutil.SetControllerReference(user, cm, scheme.Scheme); err != nil {
klog.Errorln(err)
return err
}
if _, err = o.k8sClient.CoreV1().ConfigMaps(constants.KubeSphereControlNamespace).Create(context.Background(), cm, metav1.CreateOptions{}); err != nil {
klog.Errorln(err)
return err
}
return nil
}
在CertificateSigningRequest控制器中Approve批准CertificateSigningRequest请求,UpdateKubeconfig最终调用applyCert更新证书
func (c *Controller) reconcile(key string) error {
// csr create by kubesphere auto approve
if username := csr.Labels[constants.UsernameLabelKey]; username != "" {
err = c.Approve(csr)
if err != nil {
klog.Error(err)
return err
}
// certificate data is not empty
if len(csr.Status.Certificate) > 0 {
err = c.UpdateKubeconfig(csr)
if err != nil {
// kubeconfig not generated
klog.Error(err)
return err
}
// release
err := c.k8sclient.CertificatesV1().CertificateSigningRequests().Delete(context.Background(), csr.Name, *metav1.NewDeleteOptions(0))
if err != nil {
klog.Error(err)
return err
}
}
}
c.recorder.Event(csr, corev1.EventTypeNormal, successSynced, messageResourceSynced)
return nil
}
更新kubeconfig证书ClientKeyData,ClientCertificateData
func applyCert(cm *corev1.ConfigMap, csr *certificatesv1.CertificateSigningRequest) *corev1.ConfigMap {
data := []byte(cm.Data[kubeconfigFileName])
kubeconfig, err := clientcmd.Load(data)
if err != nil {
klog.Error(err)
return cm
}
username := getControlledUsername(cm)
privateKey := csr.Annotations[privateKeyAnnotation]
clientCert := csr.Status.Certificate
kubeconfig.AuthInfos = map[string]*clientcmdapi.AuthInfo{
username: {
ClientKeyData: []byte(privateKey),
ClientCertificateData: clientCert,
},
}
data, err = clientcmd.Write(*kubeconfig)
if err != nil {
klog.Error(err)
return cm
}
cm.Data[kubeconfigFileName] = string(data)
return cm
}
通过API创建GlobalRole, GlobalRoleBinding,对用户和角色进行绑定
amOperator := am.NewOperator(s.KubernetesClient.KubeSphere(),
s.KubernetesClient.Kubernetes(),
s.InformerFactory,
s.DevopsClient)
func (am *amOperator) CreateGlobalRoleBinding(username string, role string) error {
_, err := am.GetGlobalRole(role)
if err != nil {
klog.Error(err)
return err
}
roleBindings, err := am.ListGlobalRoleBindings(username)
if err != nil {
klog.Error(err)
return err
}
for _, roleBinding := range roleBindings {
if role == roleBinding.RoleRef.Name {
return nil
}
err := am.ksclient.IamV1alpha2().GlobalRoleBindings().Delete(context.Background(), roleBinding.Name, *metav1.NewDeleteOptions(0))
if err != nil {
if errors.IsNotFound(err) {
continue
}
klog.Error(err)
return err
}
}
globalRoleBinding := iamv1alpha2.GlobalRoleBinding{
ObjectMeta: metav1.ObjectMeta{
Name: fmt.Sprintf("%s-%s", username, role),
Labels: map[string]string{iamv1alpha2.UserReferenceLabel: username},
},
Subjects: []rbacv1.Subject{
{
Kind: rbacv1.UserKind,
APIGroup: rbacv1.SchemeGroupVersion.Group,
Name: username,
},
},
RoleRef: rbacv1.RoleRef{
APIGroup: iamv1alpha2.SchemeGroupVersion.Group,
Kind: iamv1alpha2.ResourceKindGlobalRole,
Name: role,
},
}
if _, err := am.ksclient.IamV1alpha2().GlobalRoleBindings().Create(context.Background(), &globalRoleBinding, metav1.CreateOptions{}); err != nil {
return err
}
return nil
}
最后,用户可以获取kubeconfig,通过客户端来访问kubernetes资源。
示例:
创建user cr资源
apiVersion: iam.aiscope/v1alpha2
kind: User
metadata:
name: user-sukai
spec:
email: ycsk02@hotmail.com
password: sukai
User CR调谐后
sukai@sukai:~$ kubectl describe user user-sukai
Name: user-sukai
Namespace:
Labels: <none>
Annotations: iam.aiscope.io/last-password-change-time: 2022-01-06T07:18:14Z
API Version: iam.aiscope/v1alpha2
Kind: User
Metadata:
Creation Timestamp: 2022-01-06T07:18:13Z
Finalizers:
finalizers.aiscope.io/users
Generation: 2
Managed Fields:
API Version: iam.aiscope/v1alpha2
Fields Type: FieldsV1
fieldsV1:
f:metadata:
f:annotations:
f:iam.aiscope.io/last-password-change-time:
f:finalizers:
.:
v:"finalizers.aiscope.io/users":
f:spec:
f:password:
Manager: controller-manager.exe
Operation: Update
Time: 2022-01-06T07:18:13Z
API Version: iam.aiscope/v1alpha2
Fields Type: FieldsV1
fieldsV1:
f:metadata:
f:annotations:
f:spec:
.:
f:email:
Manager: kubectl-client-side-apply
Operation: Update
Time: 2022-01-06T07:18:13Z
Resource Version: 7892023
UID: 59818b17-db3c-428f-9094-addc18a12e07
Spec:
Email: ycsk02@hotmail.com
Password: $2a$10$pMFmLPNfyjJK71RRL2wQ7uL7mj6NNGm8Yk6bNp/xW7wiZhuw9oQs.
Events: <none>
创建的csr请求
sukai@sukai:~$ kubectl get csr
NAME AGE SIGNERNAME REQUESTOR REQUESTEDDURATION CONDITION
user-sukai-csr-1641432770 40m kubernetes.io/kube-apiserver-client kubernetes-admin <none> Approved,Issued
user-sukai-csr-1641432771 40m kubernetes.io/kube-apiserver-client kubernetes-admin <none> Approved,Issued
user-sukai-csr-1641432772 40m kubernetes.io/kube-apiserver-client kubernetes-admin <none> Approved,Issued
user-sukai-csr-1641432774 40m kubernetes.io/kube-apiserver-client kubernetes-admin <none> Approved,Issued
user-sukai-csr-1641432776 40m kubernetes.io/kube-apiserver-client kubernetes-admin <none> Approved,Issued
user-sukai-csr-1641432782 40m kubernetes.io/kube-apiserver-client kubernetes-admin <none> Approved,Issued
user-sukai-csr-1641432792 39m kubernetes.io/kube-apiserver-client kubernetes-admin <none> Approved,Issued
user-sukai-csr-1641432813 39m kubernetes.io/kube-apiserver-client kubernetes-admin <none> Approved,Issued
最终生成的kubeconfig configmap
sukai@sukai:~$ kubectl -n aiscope-controls-system get cm kubeconfig-user-sukai -o yaml
apiVersion: v1
data:
config: |
apiVersion: v1
clusters:
- cluster:
certificate-authority-data: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUMvakNDQWVhZ0F3SUJBZ0lCQURBTkJna3Foa2lHOXcwQkFRc0ZBREFWTVJNd0VRWURWUVFERXdwcmRXSmwKY201bGRHVnpNQjRYRFRJeE1USXdNVEEyTWpVeE9Gb1hEVE14TVRFeU9UQTJNalV4T0Zvd0ZURVRNQkVHQTFVRQpBeE1LYTNWaVpYSnVaWFJsY3pDQ0FTSXdEUVlKS29aSWh2Y05BUUVCQlFBRGdnRVBBRENDQVFvQ2dnRUJBTlhiCldpRXlVcm1Ld01RTUxGS25QWXpkaTY5NmJWc0ZiUUhCWFpjN0V4YWFtWXphWE83dEttVDIyWGt5WEZvMElkYmoKOWtnOTQ2YTkwSlRIVmdWUzJWUGFaQ1ZQR3pVblhPVm1TREVrK1NWeXBmYXhyV20yWm1JckNKOUIyNTh0bk1GKwovZkhCRmw2M3JnLzJod3VzUkcrWXdJN1V1VHpoZlp0NmoyRzhaeHdTNUhMR2o5dDB3T1ZjMmgxL1dpMVJHRHpECllON0pKV0c1cURoZXdVaHJIc1JidnhRcmNEb3o0SE9VdjVRSnJSckZDS0UxQjI4SE1PV0FrK0NTZ0FSSFAxM2IKc0IrUU9KUXFaRnRyZUMzYXRoWXJVZGRYUExCcjRYMGNFVnZRbXozVFVFTGNDM205OTRvQkxua0dMak92Sk9vWAp2T0QvMEhBQVhzYXExeUJoV204Q0F3RUFBYU5aTUZjd0RnWURWUjBQQVFIL0JBUURBZ0trTUE4R0ExVWRFd0VCCi93UUZNQU1CQWY4d0hRWURWUjBPQkJZRUZGMm13Skw3VHdycnJVTVVjOHpnMU81TEdzQ0NNQlVHQTFVZEVRUU8KTUF5Q0NtdDFZbVZ5Ym1WMFpYTXdEUVlKS29aSWh2Y05BUUVMQlFBRGdnRUJBSEp1TlJneVlLbWNaSmFPQkNJKwpXS1NNeTlUZWUwNFp0eEVNYmdLZWV4eEhsd2IrZTVUWVZKM1JMOUI0cVJ4YnVPaW9wai9vN09hL3BRMUxGWC9yCnJCUWw0WCtUUktUaGRKU2ZoaS9ZM3pyd1VEVkxOVEF4YklFLyswdS9Ib1FFQ1FWRUIyNGllS3JIeFZUYktNWE8KbVFQZWY4VjduSkFQa1BqTFUvSjBZV2Z2YTBFQ0ZjTi9pVEZYVkJOMndGdWp6OHJFeGNqK2VhYXUwcUNTUzNmVwpqQ1NPZGlBYXF6ZTdiSzEzNENlMGF0a3ArZkFXZSsvZkI4M2xVVjY3ZDIxVk5ERHN6Z081RGJFZitNQ2M2VzRNCkdmS1RXcXpMRVFkU21ndEV0a01RbVNCWWV5ZkpGbUF4KzZ0aHB0djNVOHpRbVRnRlMzTmFwWjZielR3dWZ0REYKak1rPQotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tCg==
server: https://192.168.10.7:6443
name: local
contexts:
- context:
cluster: local
namespace: default
user: user-sukai
name: user-sukai@local
current-context: user-sukai@local
kind: Config
preferences: {}
users:
- name: user-sukai
user:
client-certificate-data: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSURDakNDQWZLZ0F3SUJBZ0lRTGxHc1BWMVJvUG1uWFVteHdUS1UxakFOQmdrcWhraUc5dzBCQVFzRkFEQVYKTVJNd0VRWURWUVFERXdwcmRXSmxjbTVsZEdWek1CNFhEVEl5TURFd05qQTNNVEkxTjFvWERUSXpNREV3TmpBMwpNVEkxTjFvd0ZURVRNQkVHQTFVRUF4TUtkWE5sY2kxemRXdGhhVENDQVNJd0RRWUpLb1pJaHZjTkFRRUJCUUFECmdnRVBBRENDQVFvQ2dnRUJBS0RFSUFwSENwLzVJYzJZQjg5Rmlsb0tSaVpWWlE3c3lPRE44MktsTXlwYWVCNysKbnA2REJVdTZYTzJId0w5WC8yejgrYmduT0hxZVIyc1h5aXdQYzFGcWkrRG92czhyN3g4RHNEc3l4UlJHODhoaQoxV3h0NEwrSkRucCt0NzJzTUN4cjNWcTlMWklUZFhWMDJGclZIcUw2MnBFRzRWRGd2ZGswTFArSnFhMzU3T3lFCm9hZExTRzNReHpxNGxRVTgzb3VBVCtPamRmM3NyeVJsQ2ZYS2o3N0hWdkhaRHBYSjAySS95aTAxQUN2Z20zWUEKWGJiQUNVQ3Q4eVpBb25aRXQ3Y3RWQUpic0JrZFNQaGFvNDNDZ0duVDZFZ0VuWlBObnoyUVc4VEhsSUdvRkF4VwpUL2lmTW5KdUtnOWs3WE1hSzIvc3VyRVI2VUQ2Zm51QkJWdkJSUnNDQXdFQUFhTldNRlF3RGdZRFZSMFBBUUgvCkJBUURBZ1dnTUJNR0ExVWRKUVFNTUFvR0NDc0dBUVVGQndNQ01Bd0dBMVVkRXdFQi93UUNNQUF3SHdZRFZSMGoKQkJnd0ZvQVVYYWJBa3Z0UEN1dXRReFJ6ek9EVTdrc2F3SUl3RFFZSktvWklodmNOQVFFTEJRQURnZ0VCQUxOKwpRUmY5TDNxMXlEWnAvblpmWnF2dXZDQlV1SGFEWDNCczdKbUlySGU2ZURSdGhMMjVqZVY2VEdId0tFQmdYOHE2Cnd5RzZnVC9uYXViZi9kR2ovYXB6YW9QaWFLa0xlQkd0TEhBK2lzQlVNNzBsRzZLMXdaZzZveVVkT0JLcFM0cGUKMWhROTZjelJRbVViMnVpVE0rK3FBRVBmVlI3bHdGQXNlRVg2WE1XQnZVYzBsNFd1T3VPRXdIcW0xeWpuY0V6WQpPWkVnVGZqQ1lWTWFnSEtzOUk3RmdpaTlvZHZwWkZIWnFLV0gxSVB3R3BmRXVXeG44eURldnhxMnY2Zi9vUlhTCjkyVTBUMkVQSGNZS3NpT0JDTk90R1p2czNpNHBiTFZDa2l1VFlvZzdhczBoWnlrRlpOMXV5WVp0bFhQSkRLZVEKU3Nla1pkbHhQYy8xcHpydG1HMD0KLS0tLS1FTkQgQ0VSVElGSUNBVEUtLS0tLQo=
client-key-data: LS0tLS1CRUdJTiBQUklWQVRFIEtFWS0tLS0tCk1JSUVvd0lCQUFLQ0FRRUFvTVFnQ2tjS24va2h6WmdIejBXS1dncEdKbFZsRHV6STRNM3pZcVV6S2xwNEh2NmUKbm9NRlM3cGM3WWZBdjFmL2JQejV1Q2M0ZXA1SGF4ZktMQTl6VVdxTDRPaSt6eXZ2SHdPd096TEZGRWJ6eUdMVgpiRzNndjRrT2VuNjN2YXd3TEd2ZFdyMHRraE4xZFhUWVd0VWVvdnJha1FiaFVPQzkyVFFzLzRtcHJmbnM3SVNoCnAwdEliZERIT3JpVkJUemVpNEJQNDZOMS9leXZKR1VKOWNxUHZzZFc4ZGtPbGNuVFlqL0tMVFVBSytDYmRnQmQKdHNBSlFLM3pKa0NpZGtTM3R5MVVBbHV3R1IxSStGcWpqY0tBYWRQb1NBU2RrODJmUFpCYnhNZVVnYWdVREZaUAorSjh5Y200cUQyVHRjeG9yYit5NnNSSHBRUHArZTRFRlc4RkZHd0lEQVFBQkFvSUJBQkgzK2RETVFlN0JiTHJLCi9FeDViRTVHQ2JNdEpqOTF6Ym42cXZKaW5vWmtXRHEyb01uOHdQSEc0YTRXMXo5THVadlg1cDFqbk5kdnEzSFgKMWR2NDJoM0dkOTNxaGJFb0t2RGZlNm9TTVo3amswblphaHRWYUtKZjBrTjB1RnExelNpWjRjTExsRFZZZ1c5ZwpZUEkrRWMrTGxEUlRmWW1KcFE2SzIyQ3daVXV4anlCNkE2YTBZOW1wUVI5QkVVUWZtczMzcXl0YW9YOFZXZ2xFClVjWmRkSUxXV0NrdVpvMTdNcUk5SGdZNnd3WWN3WlJuMmU2VGkxd3h1MHVBR3ozNjhQeTJTaHJ3d3VWM1VRTmcKbkRuTEwwMjZvWWhUZXRnSjZoUVlBN1B6SmdXbXhpekZoOVc0OVJKWlhFL1F3cHJ6TkdWSDEzSUNtUHlXa2lmdAptL3lEWC9FQ2dZRUF4VDE4WjJrL2g4eHFocS85dTYrYWxVazk3TnhSWU1YS2dlOUk5RW91OG9vT0I0MFBzdFJ5CnpXczhhc1hRWWRXK3NVUkZVT0pPMWFEaThicGxGM1RVczU1L3NJVW8rMVFWRjlXOFVNdkVqdzNnV0tFU2hBbnQKeXJTRGNqVENjWmg1RHhHakowT05ndzZMcFQxV3M2M29SN2NkdEVvZ1I2YUVkNVdQWjNQQmNKa0NnWUVBMEtqeQpOSTQzanhJKzFtSjJWTVJiTSt1STZLTVlMWTI2ZXJQSlpQSDhtZklMN2Q0L3ZVUTdYL0ZjTkE0a0tmOE1PTzJpCnBPQ05neTFETmx4VGgvODZ1Ri9iL0xTUHg4OE9DK3pxVU5zKzM5Rmh0ZXd0eVZBY3h0NjkzWUdwU3JsOFZSQVoKU3cyYUJ4RG11WHR6TFpWU1dFdE9TSDdZN0MxNG4wSHY4VGhNajlNQ2dZRUFtSytoVnpnOWF2V09YVmR0MTFYNApGNnJNR2tqdllqZWJMWHk4QUFoUlVZWVhtRGJWdVQwRzVnZ21qQTAzNUJTZit2LzduTUtqL25IK1hOeExGNTVrCmJldTdzejFSM1VWWTBzdXRiT3BnN2REekpBa0VtVnhLVFVueUczM0dMRU81S3pZZkUrMFNaaXJqWlhZWFlSNjIKR3BZaGs0aHlkcVRzRk5xZFdadGRXcmtDZ1lBd3BKSUNLbjFOUHlXaStNVTVNYVZKVDBsVlltQUtqcFhBY1JVcwpFVFdmOWN0T0lwZWRXY0MxdHlDVmlnNW9NK3IzZ241K0RWTXdGMmNwenhBeURnLzBWM1NEVHR5TjZma09VcWExClBzZERpaDVMT01uYnVtOWE5U1l4OHo0eUMxZXV4TmdBcFNVWkxKbDgrQWg3d2VtMlo2ZlNRcS96THc2Rm9ldDcKd25JbXZRS0JnQjFKY2VVZXM5QURjd2NwTldna21teFZXNkN5UVVJTFRxUHVEbFY2RE95TDJNaTNXeXNGamphawpvU05maWxoVGxaOTJ1M0NsTDlQQnBWVDF2eE1kOFA5K0FzdFlPVlpCcHRNU1IvRDJUdms4WnZGYjV4b3ZWUkQwCjVqVk1GN094WXlCRktMVVlTL2Z1cStaNVhpSmdqUFhzRUpyZ3V0STRsZURtWkF4bnBQWFEKLS0tLS1FTkQgUFJJVkFURSBLRVktLS0tLQo=
kind: ConfigMap
metadata:
creationTimestamp: "2022-01-06T07:18:13Z"
labels:
aiscope.io/username: user-sukai
managedFields:
- apiVersion: v1
fieldsType: FieldsV1
fieldsV1:
f:data:
.: {}
f:config: {}
f:metadata:
f:labels:
.: {}
f:aiscope.io/username: {}
f:ownerReferences:
.: {}
k:{"uid":"59818b17-db3c-428f-9094-addc18a12e07"}: {}
manager: controller-manager.exe
operation: Update
time: "2022-01-06T07:18:13Z"
name: kubeconfig-user-sukai
namespace: aiscope-controls-system
ownerReferences:
- apiVersion: iam.aiscope/v1alpha2
blockOwnerDeletion: true
controller: true
kind: User
name: user-sukai
uid: 59818b17-db3c-428f-9094-addc18a12e07
resourceVersion: "7892042"
uid: b08afeb8-2a00-4b04-9ea2-b9111d8c80c6
使用kubeconfig来请求Kubernetes资源,已经能够通过kubeconfig访问到Kubernetes API,这里因为没有进行Role绑定,所以被权限禁止。
sukai@sukai:~/.kube$ kubectl --kubeconfig config.test-sukai get all
Error from server (Forbidden): pods is forbidden: User "user-sukai" cannot list resource "pods" in API group "" in the namespace "default"
Error from server (Forbidden): replicationcontrollers is forbidden: User "user-sukai" cannot list resource "replicationcontrollers" in API group "" in the namespace "default"
Error from server (Forbidden): services is forbidden: User "user-sukai" cannot list resource "services" in API group "" in the namespace "default"
Error from server (Forbidden): daemonsets.apps is forbidden: User "user-sukai" cannot list resource "daemonsets" in API group "apps" in the namespace "default"
Error from server (Forbidden): deployments.apps is forbidden: User "user-sukai" cannot list resource "deployments" in API group "apps" in the namespace "default"
Error from server (Forbidden): replicasets.apps is forbidden: User "user-sukai" cannot list resource "replicasets" in API group "apps" in the namespace "default"
Error from server (Forbidden): statefulsets.apps is forbidden: User "user-sukai" cannot list resource "statefulsets" in API group "apps" in the namespace "default"
Error from server (Forbidden): horizontalpodautoscalers.autoscaling is forbidden: User "user-sukai" cannot list resource "horizontalpodautoscalers" in API group "autoscaling" in the namespace "default"
Error from server (Forbidden): cronjobs.batch is forbidden: User "user-sukai" cannot list resource "cronjobs" in API group "batch" in the namespace "default"
Error from server (Forbidden): jobs.batch is forbidden: User "user-sukai" cannot list resource "jobs" in API group "batch" in the namespace "default"
sukai@sukai:~/.kube$
sukai@sukai:~/.kube$