From 0c1fc8479f46f098c4d26cc2e27db40e427d83e2 Mon Sep 17 00:00:00 2001
From: rambohe-ch <linbo.hlb@alibaba-inc.com>
Date: Mon, 10 Apr 2023 17:43:16 +0800
Subject: [PATCH] refactor pool-coordinator-cert controller

---
 .../poolcoordinator/cert/certificate.go       |  12 +-
 .../poolcoordinator/cert/certificate_test.go  |   2 +-
 .../cert/poolcoordinatorcert_controller.go    | 355 +++++++++++-------
 .../poolcoordinatorcert_controller_test.go    |   5 +
 pkg/controller/poolcoordinator/cert/secret.go |   2 +-
 pkg/util/kubeconfig/kubeconfig.go             |  12 +
 6 files changed, 240 insertions(+), 148 deletions(-)

diff --git a/pkg/controller/poolcoordinator/cert/certificate.go b/pkg/controller/poolcoordinator/cert/certificate.go
index 5beb1d3aefe..eb3fdad2a40 100644
--- a/pkg/controller/poolcoordinator/cert/certificate.go
+++ b/pkg/controller/poolcoordinator/cert/certificate.go
@@ -151,8 +151,10 @@ func loadCertAndKeyFromSecret(clientSet client.Interface, certConf CertConfig) (
 		if err != nil {
 			return nil, nil, errors.Wrapf(err, "couldn't parse the kubeconfig file in the %s secret", secretName)
 		}
-		authInfo := kubeConfig.AuthInfos[certConf.CommonName]
-
+		authInfo := kubeconfig.GetAuthInfoFromKubeConfig(kubeConfig)
+		if authInfo == nil {
+			return nil, nil, errors.Errorf("auth info is not found in secret(%s)", secretName)
+		}
 		certBytes = authInfo.ClientCertificateData
 		keyBytes = authInfo.ClientKeyData
 	} else {
@@ -293,7 +295,7 @@ func GetPrivateKeyFromTLSCert(cert *tls.Certificate) (keyPEM []byte, err error)
 	return keyutil.MarshalPrivateKeyToPEM(cert.PrivateKey)
 }
 
-// get certificate & private key (in PEM format) from certmanager
+// GetCertAndKeyFromCertMgr will get certificate & private key (in PEM format) from certmanager
 func GetCertAndKeyFromCertMgr(certManager certificate.Manager, stopCh <-chan struct{}) (key []byte, cert []byte, err error) {
 	// waiting for the certificate is generated
 	certManager.Start()
@@ -327,7 +329,7 @@ func GetCertAndKeyFromCertMgr(certManager certificate.Manager, stopCh <-chan str
 	return
 }
 
-// write cert&key pair generated from certManager into a secret
+// WriteCertIntoSecret will write cert&key pair generated from certManager into a secret
 func WriteCertIntoSecret(clientSet client.Interface, certName, secretName string, certManager certificate.Manager, stopCh <-chan struct{}) error {
 
 	keyPEM, certPEM, err := GetCertAndKeyFromCertMgr(certManager, stopCh)
@@ -354,7 +356,7 @@ func WriteCertIntoSecret(clientSet client.Interface, certName, secretName string
 	return nil
 }
 
-// write cert&key into secret
+// WriteCertAndKeyIntoSecret is used for writing cert&key into secret
 // Notice: if cert OR key is nil, it will be ignored
 func WriteCertAndKeyIntoSecret(clientSet client.Interface, certName, secretName string, cert *x509.Certificate, key crypto.Signer) error {
 	// write certificate data into secret
diff --git a/pkg/controller/poolcoordinator/cert/certificate_test.go b/pkg/controller/poolcoordinator/cert/certificate_test.go
index 1f61f2f3073..546111d45b6 100644
--- a/pkg/controller/poolcoordinator/cert/certificate_test.go
+++ b/pkg/controller/poolcoordinator/cert/certificate_test.go
@@ -229,7 +229,7 @@ contexts:
 - context:
     cluster: cluster
     user: openyurt:pool-coordinator:monitoring
-    name: openyurt:pool-coordinator:monitoring@cluster
+  name: openyurt:pool-coordinator:monitoring@cluster
 current-context: openyurt:pool-coordinator:monitoring@cluster
 kind: Config
 users:
diff --git a/pkg/controller/poolcoordinator/cert/poolcoordinatorcert_controller.go b/pkg/controller/poolcoordinator/cert/poolcoordinatorcert_controller.go
index 9a92f020f2a..32eac30315c 100644
--- a/pkg/controller/poolcoordinator/cert/poolcoordinatorcert_controller.go
+++ b/pkg/controller/poolcoordinator/cert/poolcoordinatorcert_controller.go
@@ -26,12 +26,17 @@ import (
 
 	"github.com/pkg/errors"
 	certificatesv1 "k8s.io/api/certificates/v1"
+	corev1 "k8s.io/api/core/v1"
 	client "k8s.io/client-go/kubernetes"
 	"k8s.io/client-go/rest"
 	"k8s.io/klog/v2"
 	"sigs.k8s.io/controller-runtime/pkg/controller"
+	"sigs.k8s.io/controller-runtime/pkg/event"
+	"sigs.k8s.io/controller-runtime/pkg/handler"
 	"sigs.k8s.io/controller-runtime/pkg/manager"
+	"sigs.k8s.io/controller-runtime/pkg/predicate"
 	"sigs.k8s.io/controller-runtime/pkg/reconcile"
+	"sigs.k8s.io/controller-runtime/pkg/source"
 
 	appconfig "github.com/openyurtio/openyurt/cmd/yurt-manager/app/config"
 	certfactory "github.com/openyurtio/openyurt/pkg/util/certmanager/factory"
@@ -39,16 +44,16 @@ import (
 )
 
 func init() {
-	flag.IntVar(&concurrentReconciles, "poolcoordinatorcert-workers", concurrentReconciles, "Max concurrent workers for Poolcoordinatorcert controller.")
+	flag.IntVar(&concurrentReconciles, "poolcoordinatorcert-workers", concurrentReconciles, "Max concurrent workers for PoolCoordinatorCert controller.")
 }
 
 var (
-	concurrentReconciles = 3
+	concurrentReconciles = 1
 	PoolcoordinatorNS    = "kube-system"
 )
 
 const (
-	controllerName = "Poolcoordinatorcert-controller"
+	controllerName = "PoolCoordinatorCert-controller"
 
 	// tmp file directory for certmanager to write cert files
 	certDir = "/tmp"
@@ -68,22 +73,22 @@ const (
 	// - apiserver-kubelet-client.crt  (not self signed)
 	// - apiserver-kubelet-client.key (not self signed)
 	// - admin.conf (kube-config)
-	PoolcoordinatorStaticSecertName = "pool-coordinator-static-certs"
+	PoolcoordinatorStaticSecretName = "pool-coordinator-static-certs"
 	// Dynamic certs will not be shared among clients or servers, contains:
 	// - apiserver.crt
 	// - apiserver.key
 	// - etcd-server.crt
 	// - etcd-server.key
-	// todo: currently we only create one copy, this will be refined in the future to assign customized certs for differnet nodepools
-	PoolcoordinatorDynamicSecertName = "pool-coordinator-dynamic-certs"
+	// todo: currently we only create one copy, this will be refined in the future to assign customized certs for different nodepools
+	PoolcoordinatorDynamicSecretName = "pool-coordinator-dynamic-certs"
 	// Yurthub certs shared by all yurthub, contains:
 	// - ca.crt
 	// - pool-coordinator-yurthub-client.crt
 	// - pool-coordinator-yurthub-client.key
-	PoolcoordinatorYurthubClientSecertName = "pool-coordinator-yurthub-certs"
+	PoolcoordinatorYurthubClientSecretName = "pool-coordinator-yurthub-certs"
 	// Monitoring kubeconfig contains: monitoring kubeconfig for poolcoordinator
 	// - kubeconfig
-	PoolcoordinatorMonitoringKubeconfigSecertName = "pool-coordinator-monitoring-kubeconfig"
+	PoolcoordinatorMonitoringKubeconfigSecretName = "pool-coordinator-monitoring-kubeconfig"
 
 	PoolcoordinatorOrg      = "openyurt:pool-coordinator"
 	PoolcoordinatorAdminOrg = "system:masters"
@@ -91,7 +96,6 @@ const (
 	PoolcoordinatorAPIServerCN            = "openyurt:pool-coordinator:apiserver"
 	PoolcoordinatorNodeLeaseProxyClientCN = "openyurt:pool-coordinator:node-lease-proxy-client"
 	PoolcoordinatorETCDCN                 = "openyurt:pool-coordinator:etcd"
-	PoolcoordinatorYurthubClientCN        = "openyurt:pool-coordinator:yurthub"
 	KubeConfigMonitoringClientCN          = "openyurt:pool-coordinator:monitoring"
 	KubeConfigAdminClientCN               = "cluster-admin"
 )
@@ -112,78 +116,86 @@ type CertConfig struct {
 	DNSNames     []string
 	IPs          []net.IP
 
-	// certInit is used for initilize those attrs which has to be determined dynamically
+	// certInit is used for initialize those attrs which has to be determined dynamically
 	// e.g. TLS server cert's IP & DNSNames
 	certInit certInitFunc
 }
 
-var allSelfSignedCerts []CertConfig = []CertConfig{
-	{
-		CertName:     "apiserver-etcd-client",
-		SecretName:   PoolcoordinatorStaticSecertName,
-		IsKubeConfig: false,
-		ExtKeyUsage:  []x509.ExtKeyUsage{x509.ExtKeyUsageClientAuth},
-		CommonName:   PoolcoordinatorETCDCN,
-		Organization: []string{PoolcoordinatorOrg},
-	},
-	{
-		CertName:     "pool-coordinator-yurthub-client",
-		SecretName:   PoolcoordinatorYurthubClientSecertName,
-		IsKubeConfig: false,
-		ExtKeyUsage:  []x509.ExtKeyUsage{x509.ExtKeyUsageClientAuth},
-		CommonName:   KubeConfigAdminClientCN,
-		Organization: []string{PoolcoordinatorAdminOrg},
-	},
-	{
-		CertName:     "apiserver",
-		SecretName:   PoolcoordinatorDynamicSecertName,
-		IsKubeConfig: false,
-		ExtKeyUsage:  []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth},
-		CommonName:   PoolcoordinatorAPIServerCN,
-		Organization: []string{PoolcoordinatorOrg},
-		certInit: func(i client.Interface, c <-chan struct{}) ([]net.IP, []string, error) {
-			return waitUntilSVCReady(i, PoolcoordinatorAPIServerSVC, c)
+var (
+	allIndependentCerts = []CertConfig{
+		{
+			CertName:     "apiserver-etcd-client",
+			SecretName:   PoolcoordinatorStaticSecretName,
+			IsKubeConfig: false,
+			ExtKeyUsage:  []x509.ExtKeyUsage{x509.ExtKeyUsageClientAuth},
+			CommonName:   PoolcoordinatorETCDCN,
+			Organization: []string{PoolcoordinatorOrg},
 		},
-	},
-	{
-		CertName:     "etcd-server",
-		SecretName:   PoolcoordinatorDynamicSecertName,
-		IsKubeConfig: false,
-		ExtKeyUsage:  []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth},
-		IPs: []net.IP{
-			net.ParseIP("127.0.0.1"),
+		{
+			CertName:     "pool-coordinator-yurthub-client",
+			SecretName:   PoolcoordinatorYurthubClientSecretName,
+			IsKubeConfig: false,
+			ExtKeyUsage:  []x509.ExtKeyUsage{x509.ExtKeyUsageClientAuth},
+			CommonName:   KubeConfigAdminClientCN,
+			Organization: []string{PoolcoordinatorAdminOrg},
 		},
-		CommonName:   PoolcoordinatorETCDCN,
-		Organization: []string{PoolcoordinatorOrg},
-		certInit: func(i client.Interface, c <-chan struct{}) ([]net.IP, []string, error) {
-			return waitUntilSVCReady(i, PoolcoordinatorETCDSVC, c)
+	}
+
+	certsDependOnETCDSvc = []CertConfig{
+		{
+			CertName:     "etcd-server",
+			SecretName:   PoolcoordinatorDynamicSecretName,
+			IsKubeConfig: false,
+			ExtKeyUsage:  []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth},
+			IPs: []net.IP{
+				net.ParseIP("127.0.0.1"),
+			},
+			CommonName:   PoolcoordinatorETCDCN,
+			Organization: []string{PoolcoordinatorOrg},
+			certInit: func(i client.Interface, c <-chan struct{}) ([]net.IP, []string, error) {
+				return waitUntilSVCReady(i, PoolcoordinatorETCDSVC, c)
+			},
+		},
+	}
+
+	certsDependOnAPIServerSvc = []CertConfig{
+		{
+			CertName:     "apiserver",
+			SecretName:   PoolcoordinatorDynamicSecretName,
+			IsKubeConfig: false,
+			ExtKeyUsage:  []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth},
+			CommonName:   PoolcoordinatorAPIServerCN,
+			Organization: []string{PoolcoordinatorOrg},
+			certInit: func(i client.Interface, c <-chan struct{}) ([]net.IP, []string, error) {
+				return waitUntilSVCReady(i, PoolcoordinatorAPIServerSVC, c)
+			},
 		},
-	},
-	{
-		CertName:     "kubeconfig",
-		SecretName:   PoolcoordinatorMonitoringKubeconfigSecertName,
-		IsKubeConfig: true,
-		ExtKeyUsage:  []x509.ExtKeyUsage{x509.ExtKeyUsageClientAuth},
-		CommonName:   KubeConfigMonitoringClientCN,
-		Organization: []string{PoolcoordinatorOrg},
-		// As a clientAuth cert, kubeconfig cert don't need IP&DNS to work,
-		// but kubeconfig need this extra information to verify if it's out of date
-		certInit: func(i client.Interface, c <-chan struct{}) ([]net.IP, []string, error) {
-			return waitUntilSVCReady(i, PoolcoordinatorAPIServerSVC, c)
+		{
+			CertName:     "kubeconfig",
+			SecretName:   PoolcoordinatorMonitoringKubeconfigSecretName,
+			IsKubeConfig: true,
+			ExtKeyUsage:  []x509.ExtKeyUsage{x509.ExtKeyUsageClientAuth},
+			CommonName:   KubeConfigMonitoringClientCN,
+			Organization: []string{PoolcoordinatorOrg},
+			// As a clientAuth cert, kubeconfig cert don't need IP&DNS to work,
+			// but kubeconfig need this extra information to verify if it's out of date
+			certInit: func(i client.Interface, c <-chan struct{}) ([]net.IP, []string, error) {
+				return waitUntilSVCReady(i, PoolcoordinatorAPIServerSVC, c)
+			},
 		},
-	},
-	{
-		CertName:     "admin.conf",
-		SecretName:   PoolcoordinatorStaticSecertName,
-		IsKubeConfig: true,
-		ExtKeyUsage:  []x509.ExtKeyUsage{x509.ExtKeyUsageClientAuth},
-		CommonName:   KubeConfigAdminClientCN,
-		Organization: []string{PoolcoordinatorAdminOrg},
-		certInit: func(i client.Interface, c <-chan struct{}) ([]net.IP, []string, error) {
-			return waitUntilSVCReady(i, PoolcoordinatorAPIServerSVC, c)
+		{
+			CertName:     "admin.conf",
+			SecretName:   PoolcoordinatorStaticSecretName,
+			IsKubeConfig: true,
+			ExtKeyUsage:  []x509.ExtKeyUsage{x509.ExtKeyUsageClientAuth},
+			CommonName:   KubeConfigAdminClientCN,
+			Organization: []string{PoolcoordinatorAdminOrg},
+			certInit: func(i client.Interface, c <-chan struct{}) ([]net.IP, []string, error) {
+				return waitUntilSVCReady(i, PoolcoordinatorAPIServerSVC, c)
+			},
 		},
-	},
-}
+	}
+)
 
 func Format(format string, args ...interface{}) string {
 	s := fmt.Sprintf(format, args...)
@@ -192,11 +204,11 @@ func Format(format string, args ...interface{}) string {
 
 // Add creates a new Poolcoordinatorcert Controller and adds it to the Manager with default RBAC. The Manager will set fields on the Controller
 // and Start it when the Manager is Started.
-func Add(c *appconfig.CompletedConfig, mgr manager.Manager) error {
-	r := &ReconcilePoolcoordinatorcert{}
+func Add(cfg *appconfig.CompletedConfig, mgr manager.Manager) error {
+	r := &ReconcilePoolCoordinatorCert{}
 
 	// Create a new controller
-	_, err := controller.New(controllerName, mgr, controller.Options{
+	c, err := controller.New(controllerName, mgr, controller.Options{
 		Reconciler: r, MaxConcurrentReconciles: concurrentReconciles,
 	})
 	if err != nil {
@@ -204,34 +216,88 @@ func Add(c *appconfig.CompletedConfig, mgr manager.Manager) error {
 	}
 
 	// init global variables
-	cfg := c.ComponentConfig.Generic
-	PoolcoordinatorNS = cfg.WorkingNamespace
+	PoolcoordinatorNS = cfg.ComponentConfig.Generic.WorkingNamespace
 
-	// init PoolCoordinator
-	// prepare some necessary assets (CA, certs, kubeconfigs) for pool-coordinator
-	err = initPoolCoordinator(r.Client, nil)
+	// prepare ca certs for pool coordinator
+	caCert, caKey, reuseCA, err := initCA(r.kubeClient)
 	if err != nil {
+		return errors.Wrap(err, "init poolcoordinator failed")
+	}
+	r.caCert = caCert
+	r.caKey = caKey
+	r.reuseCA = reuseCA
+
+	// prepare all independent certs
+	if err := r.initPoolCoordinator(allIndependentCerts, nil); err != nil {
 		return err
 	}
 
-	return nil
+	// prepare ca cert in static secret
+	if err := WriteCertAndKeyIntoSecret(r.kubeClient, "ca", PoolcoordinatorStaticSecretName, r.caCert, nil); err != nil {
+		return err
+	}
+
+	// prepare ca cert in yurthub secret
+	if err := WriteCertAndKeyIntoSecret(r.kubeClient, "ca", PoolcoordinatorYurthubClientSecretName, r.caCert, nil); err != nil {
+		return err
+	}
+
+	// prepare sa key pairs
+	if err := initSAKeyPair(r.kubeClient, "sa", PoolcoordinatorStaticSecretName); err != nil {
+		return err
+	}
+
+	// watch pool coordinator service
+	svcReadyPredicates := predicate.Funcs{
+		CreateFunc: func(evt event.CreateEvent) bool {
+			if svc, ok := evt.Object.(*corev1.Service); ok {
+				return isPoolCoordinatorSvc(svc)
+			}
+			return false
+		},
+		UpdateFunc: func(evt event.UpdateEvent) bool {
+			if svc, ok := evt.ObjectNew.(*corev1.Service); ok {
+				return isPoolCoordinatorSvc(svc)
+			}
+			return false
+		},
+		DeleteFunc: func(evt event.DeleteEvent) bool {
+			return false
+		},
+	}
+	return c.Watch(&source.Kind{Type: &corev1.Service{}}, &handler.EnqueueRequestForObject{}, svcReadyPredicates)
 }
 
-var _ reconcile.Reconciler = &ReconcilePoolcoordinatorcert{}
+func isPoolCoordinatorSvc(svc *corev1.Service) bool {
+	if svc == nil {
+		return false
+	}
+
+	if svc.Namespace == PoolcoordinatorNS && (svc.Name == PoolcoordinatorAPIServerSVC || svc.Name == PoolcoordinatorETCDSVC) {
+		return true
+	}
 
-// ReconcilePoolcoordinatorcert reconciles a Poolcoordinatorcert object
-type ReconcilePoolcoordinatorcert struct {
-	Client client.Interface
+	return false
 }
 
-// InjectConfig
-func (r *ReconcilePoolcoordinatorcert) InjectConfig(cfg *rest.Config) error {
-	client, err := client.NewForConfig(cfg)
+var _ reconcile.Reconciler = &ReconcilePoolCoordinatorCert{}
+
+// ReconcilePoolCoordinatorCert reconciles a Poolcoordinatorcert object
+type ReconcilePoolCoordinatorCert struct {
+	kubeClient client.Interface
+	caCert     *x509.Certificate
+	caKey      crypto.Signer
+	reuseCA    bool
+}
+
+// InjectConfig will prepare kube client for PoolCoordinatorCert
+func (r *ReconcilePoolCoordinatorCert) InjectConfig(cfg *rest.Config) error {
+	kubeClient, err := client.NewForConfig(cfg)
 	if err != nil {
 		klog.Errorf("failed to create kube client, %v", err)
 		return err
 	}
-	r.Client = client
+	r.kubeClient = kubeClient
 	return nil
 }
 
@@ -240,46 +306,56 @@ func (r *ReconcilePoolcoordinatorcert) InjectConfig(cfg *rest.Config) error {
 // +kubebuilder:rbac:groups="",resources=configmaps,verbs=get;watch;list
 
 // todo: make customized certificate for each poolcoordinator pod
-func (r *ReconcilePoolcoordinatorcert) Reconcile(_ context.Context, request reconcile.Request) (reconcile.Result, error) {
+func (r *ReconcilePoolCoordinatorCert) Reconcile(ctx context.Context, request reconcile.Request) (reconcile.Result, error) {
 
 	// Note !!!!!!!!!!
 	// We strongly recommend use Format() to  encapsulation because Format() can print logs by module
 	// @kadisi
-	klog.Infof(Format("Reconcile Poolcoordinatorcert %s/%s", request.Namespace, request.Name))
+	klog.Infof(Format("Reconcile PoolCoordinatorCert %s/%s", request.Namespace, request.Name))
+	// 1. prepare apiserver-kubelet-client cert
+	if err := initAPIServerClientCert(r.kubeClient, ctx.Done()); err != nil {
+		return reconcile.Result{}, err
+	}
+
+	// 2. prepare node-lease-proxy-client cert
+	if err := initNodeLeaseProxyClient(r.kubeClient, ctx.Done()); err != nil {
+		return reconcile.Result{}, err
+	}
 
+	// 3. prepare certs based on service
+	if request.NamespacedName.Namespace == PoolcoordinatorNS {
+		if request.NamespacedName.Name == PoolcoordinatorAPIServerSVC {
+			return reconcile.Result{}, r.initPoolCoordinator(certsDependOnAPIServerSvc, ctx.Done())
+		} else if request.NamespacedName.Name == PoolcoordinatorETCDSVC {
+			return reconcile.Result{}, r.initPoolCoordinator(certsDependOnETCDSvc, ctx.Done())
+		}
+	}
 	return reconcile.Result{}, nil
 }
 
-func initPoolCoordinator(clientSet client.Interface, stopCh <-chan struct{}) error {
+func (r *ReconcilePoolCoordinatorCert) initPoolCoordinator(allSelfSignedCerts []CertConfig, stopCh <-chan struct{}) error {
 
 	klog.Infof(Format("init poolcoordinator started"))
-
-	// Prepare CA certs
-	caCert, caKey, reuseCA, err := initCA(clientSet)
-	if err != nil {
-		return errors.Wrap(err, "init poolcoordinator failed")
-	}
-
 	// Prepare certs used by poolcoordinators
 
-	// 1. prepare selfsigned certs
+	// prepare selfsigned certs
 	var selfSignedCerts []CertConfig
 
-	if reuseCA {
+	if r.reuseCA {
 		// if CA is reused
 		// then we can check if there are selfsigned certs can be reused too
 		for _, certConf := range allSelfSignedCerts {
 
 			// 1.1 check if cert exist
-			cert, _, err := loadCertAndKeyFromSecret(clientSet, certConf)
+			cert, _, err := loadCertAndKeyFromSecret(r.kubeClient, certConf)
 			if err != nil {
 				klog.Infof(Format("can not load cert %s from %s secret", certConf.CertName, certConf.SecretName))
 				selfSignedCerts = append(selfSignedCerts, certConf)
 				continue
 			}
 
-			// 1.2 check if cert is autorized by current CA
-			if !IsCertFromCA(cert, caCert) {
+			// 1.2 check if cert is authorized by current CA
+			if !IsCertFromCA(cert, r.caCert) {
 				klog.Infof(Format("existing cert %s is not authorized by current CA", certConf.CertName))
 				selfSignedCerts = append(selfSignedCerts, certConf)
 				continue
@@ -288,7 +364,7 @@ func initPoolCoordinator(clientSet client.Interface, stopCh <-chan struct{}) err
 			// 1.3 check has dynamic attrs changed
 			if certConf.certInit != nil {
 				// receive dynamic IP addresses
-				ips, _, err := certConf.certInit(clientSet, stopCh)
+				ips, _, err := certConf.certInit(r.kubeClient, stopCh)
 				if err != nil {
 					// if cert init failed, skip this cert
 					klog.Errorf(Format("fail to init cert %s when checking dynamic attrs: %v", certConf.CertName, err))
@@ -311,44 +387,19 @@ func initPoolCoordinator(clientSet client.Interface, stopCh <-chan struct{}) err
 		selfSignedCerts = allSelfSignedCerts
 	}
 
-	// create self signed certs
+	// create selfsigned certs
 	for _, certConf := range selfSignedCerts {
-		if err := initPoolCoordinatorCert(clientSet, certConf, caCert, caKey, stopCh); err != nil {
+		if err := initPoolCoordinatorCert(r.kubeClient, certConf, r.caCert, r.caKey, stopCh); err != nil {
 			klog.Errorf(Format("create cert %s fail: %v", certConf.CertName, err))
 			return err
 		}
 	}
 
-	// 2. prepare apiserver-kubelet-client cert
-	if err := initAPIServerClientCert(clientSet, stopCh); err != nil {
-		return err
-	}
-
-	// 3. prepare node-lease-proxy-client cert
-	if err := initNodeLeaseProxyClient(clientSet, stopCh); err != nil {
-		return err
-	}
-
-	// 4. prepare ca cert in static secret
-	if err := WriteCertAndKeyIntoSecret(clientSet, "ca", PoolcoordinatorStaticSecertName, caCert, nil); err != nil {
-		return err
-	}
-
-	// 5. prepare ca cert in yurthub secret
-	if err := WriteCertAndKeyIntoSecret(clientSet, "ca", PoolcoordinatorYurthubClientSecertName, caCert, nil); err != nil {
-		return err
-	}
-
-	// 6. prepare sa key pairs
-	if err := initSAKeyPair(clientSet, "sa", PoolcoordinatorStaticSecertName); err != nil {
-		return err
-	}
-
 	return nil
 }
 
-// Prepare CA certs,
-// check if pool-coordinator CA already exist, if not creat one
+// initCA is used for preparing CA certs,
+// check if pool-coordinator CA already exist, if not create one
 func initCA(clientSet client.Interface) (caCert *x509.Certificate, caKey crypto.Signer, reuse bool, err error) {
 	// try load CA cert&key from secret
 	caCert, caKey, err = loadCertAndKeyFromSecret(clientSet, CertConfig{
@@ -362,13 +413,12 @@ func initCA(clientSet client.Interface) (caCert *x509.Certificate, caKey crypto.
 		klog.Info(Format("CA already exist in secret, reuse it"))
 		return caCert, caKey, true, nil
 	} else {
-		// if not exist
-		// create new CA certs
-		klog.Infof(Format("fail to get CA from secret: %v, create new CA", err))
+		// if ca secret does not exist, create new CA certs
+		klog.Infof(Format("secret(%s/%s) is not found, create new CA", PoolcoordinatorNS, PoolCoordinatorCASecretName))
 		// write it into the secret
 		caCert, caKey, err = NewSelfSignedCA()
 		if err != nil {
-			return nil, nil, false, errors.Wrap(err, "fail to write CA assets into secret when initializing poolcoordinator")
+			return nil, nil, false, errors.Wrap(err, "fail to new self CA assets when initializing poolcoordinator")
 		}
 
 		err = WriteCertAndKeyIntoSecret(clientSet, "ca", PoolCoordinatorCASecretName, caCert, caKey)
@@ -376,10 +426,22 @@ func initCA(clientSet client.Interface) (caCert *x509.Certificate, caKey crypto.
 			return nil, nil, false, errors.Wrap(err, "fail to write CA assets into secret when initializing poolcoordinator")
 		}
 	}
+
 	return caCert, caKey, false, nil
 }
 
-func initAPIServerClientCert(clientSet client.Interface, stopCh <-chan struct{}) (err error) {
+func initAPIServerClientCert(clientSet client.Interface, stopCh <-chan struct{}) error {
+	if cert, _, err := loadCertAndKeyFromSecret(clientSet, CertConfig{
+		SecretName:   PoolcoordinatorStaticSecretName,
+		CertName:     "apiserver-kubelet-client",
+		IsKubeConfig: false,
+	}); cert != nil {
+		klog.Infof("apiserver-kubelet-client cert has already existed in secret %s", PoolcoordinatorStaticSecretName)
+		return nil
+	} else if err != nil {
+		klog.Errorf("fail to get apiserver-kubelet-client cert in secret(%s), %v, and new cert will be created", PoolcoordinatorStaticSecretName, err)
+	}
+
 	certMgr, err := certfactory.NewCertManagerFactory(clientSet).New(&certfactory.CertManagerConfig{
 		CertDir:        certDir,
 		ComponentName:  fmt.Sprintf("%s-%s", ComponentName, "apiserver-client"),
@@ -392,10 +454,21 @@ func initAPIServerClientCert(clientSet client.Interface, stopCh <-chan struct{})
 		return err
 	}
 
-	return WriteCertIntoSecret(clientSet, "apiserver-kubelet-client", PoolcoordinatorStaticSecertName, certMgr, stopCh)
+	return WriteCertIntoSecret(clientSet, "apiserver-kubelet-client", PoolcoordinatorStaticSecretName, certMgr, stopCh)
 }
 
 func initNodeLeaseProxyClient(clientSet client.Interface, stopCh <-chan struct{}) error {
+	if cert, _, err := loadCertAndKeyFromSecret(clientSet, CertConfig{
+		SecretName:   PoolcoordinatorYurthubClientSecretName,
+		CertName:     "node-lease-proxy-client",
+		IsKubeConfig: false,
+	}); cert != nil {
+		klog.Infof("node-lease-proxy-client cert has already existed in secret %s", PoolcoordinatorYurthubClientSecretName)
+		return nil
+	} else if err != nil {
+		klog.Errorf("fail to get node-lease-proxy-client cert in secret(%s), %v, and new cert will be created", PoolcoordinatorYurthubClientSecretName, err)
+	}
+
 	certMgr, err := certfactory.NewCertManagerFactory(clientSet).New(&certfactory.CertManagerConfig{
 		CertDir:       certDir,
 		ComponentName: "yurthub",
@@ -407,7 +480,7 @@ func initNodeLeaseProxyClient(clientSet client.Interface, stopCh <-chan struct{}
 		return err
 	}
 
-	return WriteCertIntoSecret(clientSet, "node-lease-proxy-client", PoolcoordinatorYurthubClientSecertName, certMgr, stopCh)
+	return WriteCertIntoSecret(clientSet, "node-lease-proxy-client", PoolcoordinatorYurthubClientSecretName, certMgr, stopCh)
 }
 
 // create new public/private key pair for signing service account users
diff --git a/pkg/controller/poolcoordinator/cert/poolcoordinatorcert_controller_test.go b/pkg/controller/poolcoordinator/cert/poolcoordinatorcert_controller_test.go
index 7bbcb9a0c9d..5f995fe2b57 100644
--- a/pkg/controller/poolcoordinator/cert/poolcoordinatorcert_controller_test.go
+++ b/pkg/controller/poolcoordinator/cert/poolcoordinatorcert_controller_test.go
@@ -62,6 +62,11 @@ func TestInitCA(t *testing.T) {
 			}),
 			false,
 		},
+		{
+			"secret does not exist",
+			fake.NewSimpleClientset(),
+			false,
+		},
 	}
 
 	for _, tt := range tests {
diff --git a/pkg/controller/poolcoordinator/cert/secret.go b/pkg/controller/poolcoordinator/cert/secret.go
index 2bb49e66542..025e04bfbf9 100644
--- a/pkg/controller/poolcoordinator/cert/secret.go
+++ b/pkg/controller/poolcoordinator/cert/secret.go
@@ -54,7 +54,7 @@ func NewSecretClient(clientSet client.Interface, ns, name string) (*SecretClient
 		// if this secret already exist, reuse it
 		if kerrors.IsAlreadyExists(err) {
 			secret, _ = clientSet.CoreV1().Secrets(ns).Get(context.TODO(), name, metav1.GetOptions{})
-			klog.V(4).Infof(Format("secret %s already exisit", secret.Name))
+			klog.V(4).Infof(Format("secret %s already exists", secret.Name))
 		} else {
 			return nil, fmt.Errorf("create secret client %s fail: %v", name, err)
 		}
diff --git a/pkg/util/kubeconfig/kubeconfig.go b/pkg/util/kubeconfig/kubeconfig.go
index 221ded8d3ba..9625d2d3351 100644
--- a/pkg/util/kubeconfig/kubeconfig.go
+++ b/pkg/util/kubeconfig/kubeconfig.go
@@ -113,3 +113,15 @@ func GetClusterFromKubeConfig(config *clientcmdapi.Config) *clientcmdapi.Cluster
 	}
 	return nil
 }
+
+// GetAuthInfoFromKubeConfig returns the default AuthInfo of the specified KubeConfig
+func GetAuthInfoFromKubeConfig(config *clientcmdapi.Config) *clientcmdapi.AuthInfo {
+	// If there is an unnamed cluster object, use it
+	if config.AuthInfos[""] != nil {
+		return config.AuthInfos[""]
+	}
+	if config.Contexts[config.CurrentContext] != nil {
+		return config.AuthInfos[config.Contexts[config.CurrentContext].AuthInfo]
+	}
+	return nil
+}