func NewAPIServerCrtAndKey(ca *CrtKeyPair, vc *tenancyv1alpha1.VirtualCluster, apiserverDomain string, apiserverIPs ...string) (*CrtKeyPair, error) {
	clusterDomain := defaultClusterDomain
	if vc.Spec.ClusterDomain != "" {
		clusterDomain = vc.Spec.ClusterDomain
	}
	altNames := &cert.AltNames{
		DNSNames: []string{
			"kubernetes",
			"kubernetes.default",
			"kubernetes.default.svc",
			fmt.Sprintf("kubernetes.default.svc.%s", clusterDomain),
			apiserverDomain,
			vc.Name,
		},
	}
	for _, ip := range apiserverIPs {
		if ip != "" {
			altNames.IPs = append(altNames.IPs, net.ParseIP(ip))
		}
	}
	config := &pkiutil.CertConfig{
		Config: cert.Config{
			CommonName: conversion.ToClusterKey(vc),
			AltNames:   *altNames,
			Usages:     []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth, x509.ExtKeyUsageClientAuth},
		},
	}
	apiCert, apiKey, err := pkiutil.NewCertAndKey(ca.Crt, ca.Key, config)
	if err != nil {
		return nil, fmt.Errorf("fail to create apiserver crt and key: %v", err)
	}
	rsaKey, ok := apiKey.(*rsa.PrivateKey)
	if !ok {
		return nil, errors.New("fail to assert rsa private key")
	}
	return &CrtKeyPair{apiCert, rsaKey}, nil
}
NewAPIServerCertAndKey creates crt and key for apiserver using ca.
package pki
import (
	cryptorand "crypto/rand"
	"crypto/rsa"
	"crypto/x509"
	"encoding/pem"
	"errors"
	"fmt"
	"net"
	"k8s.io/client-go/util/cert"
	tenancyv1alpha1 "sigs.k8s.io/cluster-api-provider-nested/virtualcluster/pkg/apis/tenancy/v1alpha1"
	"sigs.k8s.io/cluster-api-provider-nested/virtualcluster/pkg/syncer/conversion"
	pkiutil "sigs.k8s.io/cluster-api-provider-nested/virtualcluster/pkg/util/pki"
)
const (
	defaultClusterDomain = "cluster.local"
)
type CrtKeyPair struct {
	Crt *x509.Certificate
	Key *rsa.PrivateKey
}
type ClusterCAGroup struct {
	RootCA                   *CrtKeyPair
	APIServer                *CrtKeyPair
	ETCD                     *CrtKeyPair
	FrontProxy               *CrtKeyPair
	CtrlMgrKbCfg             string  
	AdminKbCfg               string  
	ServiceAccountPrivateKey *rsa.PrivateKey
}