karmada/pkg/controllers/unifiedauth/ensure_impersonation_secret.go

104 lines
3.8 KiB
Go

package unifiedauth
import (
"context"
"fmt"
corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
kubeclient "k8s.io/client-go/kubernetes"
"k8s.io/klog/v2"
clusterv1alpha1 "github.com/karmada-io/karmada/pkg/apis/cluster/v1alpha1"
"github.com/karmada-io/karmada/pkg/util"
"github.com/karmada-io/karmada/pkg/util/names"
)
// ensureImpersonationSecret make sure create impersonation secret for all Cluster.
// This logic is used only in the upgrade scenario of the current version
// and can be deleted in the next version.
func (c *Controller) ensureImpersonationSecret() {
controlPlaneKubeClient := kubeclient.NewForConfigOrDie(c.ControllerPlaneConfig)
clusterList := &clusterv1alpha1.ClusterList{}
if err := c.Client.List(context.TODO(), clusterList); err != nil {
klog.Errorf("Failed to list clusterList, error: %v", err)
return
}
for index, cluster := range clusterList.Items {
err := c.ensureImpersonationSecretForCluster(controlPlaneKubeClient, &clusterList.Items[index])
if err != nil {
klog.Errorf("Failed to ensure impersonation secret exist for cluster %s", cluster.Name)
return
}
}
}
func (c *Controller) ensureImpersonationSecretForCluster(karmadaKubeClient kubeclient.Interface, cluster *clusterv1alpha1.Cluster) error {
klog.V(4).Infof("Create impersonation secret for cluster %s", cluster.Name)
// create a ClusterClient for the given member cluster
clusterClient, err := c.ClusterClientSetFunc(cluster.Name, c.Client, nil)
if err != nil {
klog.Errorf("Failed to create a ClusterClient for the given member cluster: %v, err is : %v", cluster.Name, err)
return err
}
// clusterNamespace store namespace where serviceaccount and secret exist.
clusterNamespace := cluster.Spec.SecretRef.Namespace
// create a ServiceAccount for impersonation in cluster.
impersonationSA := &corev1.ServiceAccount{}
impersonationSA.Namespace = clusterNamespace
impersonationSA.Name = names.GenerateServiceAccountName("impersonator")
if impersonationSA, err = c.ensureServiceAccountExist(clusterClient.KubeClient, impersonationSA); err != nil {
return err
}
clusterImpersonatorSecret, err := util.WaitForServiceAccountSecretCreation(clusterClient.KubeClient, impersonationSA)
if err != nil {
return fmt.Errorf("failed to get serviceAccount secret for impersonation from cluster(%s), error: %v", cluster.Name, err)
}
// create secret to store impersonation info in control plane
impersonationSecret := &corev1.Secret{
ObjectMeta: metav1.ObjectMeta{
Namespace: clusterNamespace,
Name: names.GenerateImpersonationSecretName(cluster.Name),
OwnerReferences: []metav1.OwnerReference{
*metav1.NewControllerRef(cluster, clusterv1alpha1.SchemeGroupVersion.WithKind("Cluster")),
},
},
Data: map[string][]byte{
clusterv1alpha1.SecretCADataKey: clusterImpersonatorSecret.Data["ca.crt"],
clusterv1alpha1.SecretTokenKey: clusterImpersonatorSecret.Data[clusterv1alpha1.SecretTokenKey],
},
}
_, err = util.CreateSecret(karmadaKubeClient, impersonationSecret)
if err != nil {
return fmt.Errorf("failed to create impersonator secret in control plane. error: %v", err)
}
return nil
}
// ensureServiceAccountExist makes sure that the specific service account exist in cluster.
// If service account not exit, just create it.
func (c *Controller) ensureServiceAccountExist(client kubeclient.Interface, saObj *corev1.ServiceAccount) (*corev1.ServiceAccount, error) {
exist, err := util.IsServiceAccountExist(client, saObj.Namespace, saObj.Name)
if err != nil {
return nil, fmt.Errorf("failed to check if impersonation service account exist. error: %v", err)
}
if exist {
return saObj, nil
}
createdObj, err := util.CreateServiceAccount(client, saObj)
if err != nil {
return nil, fmt.Errorf("ensure impersonation service account failed due to create failed, error: %v", err)
}
return createdObj, nil
}