Sync the expiration time of kubeconfig cert file of the cluster
This commit is contained in:
@@ -19,7 +19,9 @@ package cluster
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"crypto/x509"
|
||||
"encoding/json"
|
||||
"encoding/pem"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"reflect"
|
||||
@@ -52,6 +54,7 @@ import (
|
||||
clusterclient "kubesphere.io/kubesphere/pkg/client/clientset/versioned/typed/cluster/v1alpha1"
|
||||
clusterinformer "kubesphere.io/kubesphere/pkg/client/informers/externalversions/cluster/v1alpha1"
|
||||
clusterlister "kubesphere.io/kubesphere/pkg/client/listers/cluster/v1alpha1"
|
||||
"kubesphere.io/kubesphere/pkg/utils/k8sutil"
|
||||
"kubesphere.io/kubesphere/pkg/version"
|
||||
)
|
||||
|
||||
@@ -614,6 +617,11 @@ func (c *clusterController) syncCluster(key string) error {
|
||||
}
|
||||
c.updateClusterCondition(cluster, readyConditon)
|
||||
|
||||
if err = c.updateKubeConfigExpirationDateCondition(cluster); err != nil {
|
||||
klog.Errorf("sync KubeConfig expiration date for cluster %s failed: %v", cluster.Name, err)
|
||||
return err
|
||||
}
|
||||
|
||||
if !reflect.DeepEqual(oldCluster, cluster) {
|
||||
_, err = c.clusterClient.Update(context.TODO(), cluster, metav1.UpdateOptions{})
|
||||
if err != nil {
|
||||
@@ -823,3 +831,52 @@ func (c *clusterController) unJoinFederation(clusterConfig *rest.Config, unjoini
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func parseKubeConfigExpirationDate(kubeconfig []byte) (time.Time, error) {
|
||||
config, err := k8sutil.LoadKubeConfigFromBytes(kubeconfig)
|
||||
if err != nil {
|
||||
return time.Time{}, err
|
||||
}
|
||||
if config.CertData == nil {
|
||||
return time.Time{}, fmt.Errorf("empty CertData")
|
||||
}
|
||||
block, _ := pem.Decode(config.CertData)
|
||||
if block == nil {
|
||||
return time.Time{}, fmt.Errorf("pem.Decode failed, got empty block data")
|
||||
}
|
||||
cert, err := x509.ParseCertificate(block.Bytes)
|
||||
if err != nil {
|
||||
return time.Time{}, err
|
||||
}
|
||||
return cert.NotAfter, nil
|
||||
}
|
||||
|
||||
func (c *clusterController) updateKubeConfigExpirationDateCondition(cluster *clusterv1alpha1.Cluster) error {
|
||||
if _, ok := cluster.Labels[clusterv1alpha1.HostCluster]; ok {
|
||||
return nil
|
||||
}
|
||||
// we don't need to check member clusters which using proxy mode, their certs are managed and will be renewed by tower.
|
||||
if cluster.Spec.Connection.Type == clusterv1alpha1.ConnectionTypeProxy {
|
||||
return nil
|
||||
}
|
||||
|
||||
klog.V(5).Infof("sync KubeConfig expiration date for cluster %s", cluster.Name)
|
||||
notAfter, err := parseKubeConfigExpirationDate(cluster.Spec.Connection.KubeConfig)
|
||||
if err != nil {
|
||||
return fmt.Errorf("parseKubeConfigExpirationDate for cluster %s failed: %v", cluster.Name, err)
|
||||
}
|
||||
expiresInSevenDays := v1.ConditionFalse
|
||||
if time.Now().AddDate(0, 0, 7).Sub(notAfter) > 0 {
|
||||
expiresInSevenDays = v1.ConditionTrue
|
||||
}
|
||||
|
||||
c.updateClusterCondition(cluster, clusterv1alpha1.ClusterCondition{
|
||||
Type: clusterv1alpha1.ClusterKubeConfigCertExpiresInSevenDays,
|
||||
Status: expiresInSevenDays,
|
||||
LastUpdateTime: metav1.Now(),
|
||||
LastTransitionTime: metav1.Now(),
|
||||
Reason: string(clusterv1alpha1.ClusterKubeConfigCertExpiresInSevenDays),
|
||||
Message: notAfter.String(),
|
||||
})
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -41,8 +41,6 @@ import (
|
||||
"k8s.io/client-go/kubernetes"
|
||||
v1 "k8s.io/client-go/listers/core/v1"
|
||||
"k8s.io/client-go/rest"
|
||||
"k8s.io/client-go/tools/clientcmd"
|
||||
|
||||
"kubesphere.io/api/cluster/v1alpha1"
|
||||
|
||||
"kubesphere.io/kubesphere/pkg/api"
|
||||
@@ -51,6 +49,7 @@ import (
|
||||
kubesphere "kubesphere.io/kubesphere/pkg/client/clientset/versioned"
|
||||
"kubesphere.io/kubesphere/pkg/client/informers/externalversions"
|
||||
clusterlister "kubesphere.io/kubesphere/pkg/client/listers/cluster/v1alpha1"
|
||||
"kubesphere.io/kubesphere/pkg/utils/k8sutil"
|
||||
"kubesphere.io/kubesphere/pkg/version"
|
||||
)
|
||||
|
||||
@@ -286,7 +285,7 @@ func (h *handler) updateKubeConfig(request *restful.Request, response *restful.R
|
||||
api.HandleBadRequest(response, request, fmt.Errorf("cluster kubeconfig MUST NOT be empty"))
|
||||
return
|
||||
}
|
||||
config, err := loadKubeConfigFromBytes(req.KubeConfig)
|
||||
config, err := k8sutil.LoadKubeConfigFromBytes(req.KubeConfig)
|
||||
if err != nil {
|
||||
api.HandleBadRequest(response, request, err)
|
||||
return
|
||||
@@ -363,7 +362,7 @@ func (h *handler) validateCluster(request *restful.Request, response *restful.Re
|
||||
|
||||
// validateKubeConfig takes base64 encoded kubeconfig and check its validity
|
||||
func (h *handler) validateKubeConfig(kubeconfig []byte) error {
|
||||
config, err := loadKubeConfigFromBytes(kubeconfig)
|
||||
config, err := k8sutil.LoadKubeConfigFromBytes(kubeconfig)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -393,20 +392,6 @@ func (h *handler) validateKubeConfig(kubeconfig []byte) error {
|
||||
return err
|
||||
}
|
||||
|
||||
func loadKubeConfigFromBytes(kubeconfig []byte) (*rest.Config, error) {
|
||||
clientConfig, err := clientcmd.NewClientConfigFromBytes(kubeconfig)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
config, err := clientConfig.ClientConfig()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return config, nil
|
||||
}
|
||||
|
||||
// validateKubeSphereAPIServer uses version api to check the accessibility
|
||||
// If kubesphere apiserver endpoint is not provided, use kube-apiserver proxy instead
|
||||
func validateKubeSphereAPIServer(ksEndpoint string, kubeconfig []byte) (*version.Info, error) {
|
||||
@@ -426,7 +411,7 @@ func validateKubeSphereAPIServer(ksEndpoint string, kubeconfig []byte) (*version
|
||||
return nil, err
|
||||
}
|
||||
} else {
|
||||
config, err := loadKubeConfigFromBytes(kubeconfig)
|
||||
config, err := k8sutil.LoadKubeConfigFromBytes(kubeconfig)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -485,7 +470,7 @@ func (h *handler) validateMemberClusterConfiguration(memberKubeconfig []byte) er
|
||||
|
||||
// getMemberClusterConfig returns KubeSphere running config by the given member cluster kubeconfig
|
||||
func (h *handler) getMemberClusterConfig(kubeconfig []byte) (*config.Config, error) {
|
||||
config, err := loadKubeConfigFromBytes(kubeconfig)
|
||||
config, err := k8sutil.LoadKubeConfigFromBytes(kubeconfig)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@@ -41,6 +41,7 @@ import (
|
||||
|
||||
"kubesphere.io/kubesphere/pkg/client/clientset/versioned/fake"
|
||||
"kubesphere.io/kubesphere/pkg/informers"
|
||||
"kubesphere.io/kubesphere/pkg/utils/k8sutil"
|
||||
"kubesphere.io/kubesphere/pkg/version"
|
||||
)
|
||||
|
||||
@@ -339,7 +340,7 @@ func TestValidateKubeConfig(t *testing.T) {
|
||||
"",
|
||||
agentImage)
|
||||
|
||||
config, err := loadKubeConfigFromBytes([]byte(base64EncodedKubeConfig))
|
||||
config, err := k8sutil.LoadKubeConfigFromBytes([]byte(base64EncodedKubeConfig))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@@ -415,7 +416,7 @@ func TestValidateMemberClusterConfiguration(t *testing.T) {
|
||||
"",
|
||||
agentImage)
|
||||
|
||||
config, err := loadKubeConfigFromBytes([]byte(base64EncodedKubeConfig))
|
||||
config, err := k8sutil.LoadKubeConfigFromBytes([]byte(base64EncodedKubeConfig))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
@@ -18,6 +18,8 @@ package k8sutil
|
||||
|
||||
import (
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/client-go/rest"
|
||||
"k8s.io/client-go/tools/clientcmd"
|
||||
|
||||
tenantv1alpha1 "kubesphere.io/api/tenant/v1alpha1"
|
||||
tenantv1alpha2 "kubesphere.io/api/tenant/v1alpha2"
|
||||
@@ -55,3 +57,18 @@ func GetWorkspaceOwnerName(ownerReferences []metav1.OwnerReference) string {
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
// LoadKubeConfigFromBytes parses the kubeconfig yaml data to the rest.Config struct.
|
||||
func LoadKubeConfigFromBytes(kubeconfig []byte) (*rest.Config, error) {
|
||||
clientConfig, err := clientcmd.NewClientConfigFromBytes(kubeconfig)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
config, err := clientConfig.ClientConfig()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return config, nil
|
||||
}
|
||||
|
||||
@@ -121,6 +121,9 @@ const (
|
||||
|
||||
// Openpitrix runtime is created
|
||||
ClusterOpenPitrixRuntimeReady ClusterConditionType = "OpenPitrixRuntimeReady"
|
||||
|
||||
// ClusterKubeConfigCertExpiresInSevenDays indicates that the cluster certificate is about to expire.
|
||||
ClusterKubeConfigCertExpiresInSevenDays ClusterConditionType = "KubeConfigCertExpiresInSevenDays"
|
||||
)
|
||||
|
||||
type ClusterCondition struct {
|
||||
|
||||
Reference in New Issue
Block a user