github.com/sealerio/sealer@v0.11.1-0.20240507115618-f4f89c5853ae/pkg/clustercert/kube_certs.go (about)

     1  // Copyright © 2021 Alibaba Group Holding Ltd.
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  package clustercert
    16  
    17  import (
    18  	"crypto"
    19  	"crypto/x509"
    20  	"fmt"
    21  	"net"
    22  	"os"
    23  	"strings"
    24  
    25  	"github.com/pkg/errors"
    26  	"github.com/sirupsen/logrus"
    27  	utilnet "k8s.io/utils/net"
    28  
    29  	"github.com/sealerio/sealer/pkg/clustercert/cert"
    30  )
    31  
    32  const (
    33  
    34  	// KubernetesConfigDir kubernetes default certificate directory
    35  	KubernetesConfigDir = "/etc/kubernetes"
    36  
    37  	// KubeDefaultCertPath kubernetes components default certificate directory
    38  	KubeDefaultCertPath = "/etc/kubernetes/pki"
    39  
    40  	// KubeDefaultCertEtcdPath etcd default certificate directory
    41  	KubeDefaultCertEtcdPath = "/etc/kubernetes/pki/etcd"
    42  )
    43  
    44  type CertificateConfig struct {
    45  	// file saved path only for this cert
    46  	certPath   string
    47  	certName   string
    48  	descriptor *cert.CertificateDescriptor
    49  }
    50  
    51  type CertificateConfigFamily struct {
    52  	// default file saved path for this cert Family
    53  	certPath     string
    54  	caConfig     CertificateConfig
    55  	commonConfig []CertificateConfig
    56  }
    57  
    58  func (c CertificateConfigFamily) GenerateAll() error {
    59  	var (
    60  		err    error
    61  		caCert *x509.Certificate
    62  		caKey  crypto.Signer
    63  	)
    64  
    65  	_, err = os.Stat(cert.PathForCert(c.certPath, c.caConfig.certName))
    66  	if os.IsNotExist(err) {
    67  		caCert, caKey, err = c.generateAuthorityCertificate()
    68  		if err != nil {
    69  			return err
    70  		}
    71  	} else {
    72  		logrus.Info("authority certificate is already exist")
    73  		caCert, caKey, err = c.loadAuthorityCertificate(c.certPath, c.caConfig.certName)
    74  		if err != nil {
    75  			return fmt.Errorf("failed to load an exist cert(%s):  %v", c.caConfig.certName, err)
    76  		}
    77  	}
    78  
    79  	err = c.generateCommonCertificate(caCert, caKey)
    80  	if err != nil {
    81  		return err
    82  	}
    83  
    84  	return nil
    85  }
    86  
    87  func (c CertificateConfigFamily) generateAuthorityCertificate() (*x509.Certificate, crypto.Signer, error) {
    88  	// New authority certificate generator to gen ca cert.
    89  	caGenerator := cert.NewAuthorityCertificateGenerator(*c.caConfig.descriptor)
    90  	caCert, caKey, err := caGenerator.Generate()
    91  	if err != nil {
    92  		return nil, nil, fmt.Errorf("unable to generate %s cert: %v", c.caConfig.certName, err)
    93  	}
    94  
    95  	// write cert file to disk
    96  	err = cert.NewCertificateFileManger(c.certPath, c.caConfig.certName).Write(caCert, caKey)
    97  	if err != nil {
    98  		return nil, nil, fmt.Errorf("unable to save %s cert: %v", c.caConfig.certName, err)
    99  	}
   100  
   101  	return caCert, caKey, nil
   102  }
   103  
   104  func (c CertificateConfigFamily) loadAuthorityCertificate(certPath, certName string) (*x509.Certificate, crypto.Signer, error) {
   105  	caCert, caKey, err := cert.NewCertificateFileManger(certPath, certName).Read()
   106  	if err != nil {
   107  		return nil, nil, fmt.Errorf("unable to load cert(%s) from disk: %v", certName, err)
   108  	}
   109  	return caCert, caKey, nil
   110  }
   111  
   112  func (c CertificateConfigFamily) generateCommonCertificate(caCert *x509.Certificate, caKey crypto.Signer) error {
   113  	for _, config := range c.commonConfig {
   114  		certPath := c.certPath
   115  		if config.certPath != "" {
   116  			certPath = config.certPath
   117  		}
   118  
   119  		g, err := cert.NewCommonCertificateGenerator(*config.descriptor, caCert, caKey)
   120  		if err != nil {
   121  			return err
   122  		}
   123  
   124  		commonCert, key, err := g.Generate()
   125  		if err != nil {
   126  			return err
   127  		}
   128  
   129  		err = cert.NewCertificateFileManger(certPath, config.certName).Write(commonCert, key)
   130  		if err != nil {
   131  			return fmt.Errorf("unable to save %s key: %v", config.certName, err)
   132  		}
   133  	}
   134  	return nil
   135  }
   136  
   137  type KubernetesCertService struct {
   138  	kubeCert       CertificateConfigFamily
   139  	etcdCert       CertificateConfigFamily
   140  	frontProxyCert CertificateConfigFamily
   141  	serviceAccount cert.KeyPairFileGenerator
   142  }
   143  
   144  func (s KubernetesCertService) GenerateKubeComponentCert() (err error) {
   145  	err = s.kubeCert.GenerateAll()
   146  	if err != nil {
   147  		return err
   148  	}
   149  
   150  	err = s.etcdCert.GenerateAll()
   151  	if err != nil {
   152  		return err
   153  	}
   154  
   155  	err = s.frontProxyCert.GenerateAll()
   156  	if err != nil {
   157  		return err
   158  	}
   159  
   160  	return nil
   161  }
   162  
   163  func (s KubernetesCertService) GenerateServiceAccountKeyPair() (err error) {
   164  	err = s.serviceAccount.GenerateAll()
   165  	if err != nil {
   166  		return err
   167  	}
   168  
   169  	return nil
   170  }
   171  
   172  type Args struct {
   173  	APIServerAltNames cert.AltNames
   174  	NodeName          string
   175  	NodeIP            net.IP
   176  	DNSDomain         string
   177  }
   178  
   179  // GenerateAllKubernetesCerts generate all cert.
   180  func GenerateAllKubernetesCerts(certPath, etcdCertPath, nodeName, serviceCIRD, DNSDomain string, altNames []string, nodeIP net.IP) error {
   181  	if certPath == "" || etcdCertPath == "" {
   182  		return fmt.Errorf("must provide cert path")
   183  	}
   184  
   185  	if nodeName == "" || nodeIP == nil {
   186  		return fmt.Errorf("must provide node name and node IP")
   187  	}
   188  
   189  	if DNSDomain == "" {
   190  		return fmt.Errorf("must provide cluster DNS domain")
   191  	}
   192  
   193  	// parse cluster cert args
   194  	clusterCertArgs := Args{
   195  		DNSDomain: DNSDomain,
   196  		NodeIP:    nodeIP,
   197  		NodeName:  nodeName,
   198  		APIServerAltNames: cert.AltNames{
   199  			DNSNames: map[string]string{},
   200  			IPs:      map[string]net.IP{},
   201  		},
   202  	}
   203  
   204  	clusterCertArgs.APIServerAltNames.IPs[nodeIP.String()] = nodeIP
   205  
   206  	for _, svcCidr := range strings.Split(serviceCIRD, ",") {
   207  		_, svcSubnet, err := net.ParseCIDR(svcCidr)
   208  		if err != nil {
   209  			return errors.Wrapf(err, "unable to parse ServiceSubnet %v", svcCidr)
   210  		}
   211  		svcFirstIP, err := utilnet.GetIndexedIP(svcSubnet, 1)
   212  		if err != nil {
   213  			return err
   214  		}
   215  		clusterCertArgs.APIServerAltNames.IPs[svcFirstIP.String()] = svcFirstIP
   216  	}
   217  
   218  	for _, altName := range altNames {
   219  		ip := net.ParseIP(altName)
   220  		if ip != nil {
   221  			clusterCertArgs.APIServerAltNames.IPs[ip.String()] = ip
   222  			continue
   223  		}
   224  		clusterCertArgs.APIServerAltNames.DNSNames[altName] = altName
   225  	}
   226  
   227  	// generate all cert.
   228  	certService := KubernetesCertService{
   229  		kubeCert:       getKubeCertificateConfig(certPath, clusterCertArgs.APIServerAltNames, clusterCertArgs.NodeName, clusterCertArgs.DNSDomain),
   230  		etcdCert:       getEtcdCertificateConfig(etcdCertPath, certPath, clusterCertArgs.NodeName, clusterCertArgs.NodeIP),
   231  		frontProxyCert: getFrontProxyCertificateConfig(certPath),
   232  		serviceAccount: cert.NewKeyPairFileGenerator(certPath, "sa"),
   233  	}
   234  
   235  	err := certService.GenerateKubeComponentCert()
   236  	if err != nil {
   237  		return err
   238  	}
   239  
   240  	err = certService.GenerateServiceAccountKeyPair()
   241  	if err != nil {
   242  		return err
   243  	}
   244  
   245  	return nil
   246  }
   247  
   248  func getKubeCertificateConfig(certPath string, APIServerAltNames cert.AltNames, nodeName string, DNSDomain string) CertificateConfigFamily {
   249  	kubeCert := CertificateConfigFamily{
   250  		certPath: certPath,
   251  		caConfig: CertificateConfig{
   252  			certName: "ca",
   253  			descriptor: &cert.CertificateDescriptor{
   254  				CommonName:   "kubernetes",
   255  				Organization: nil,
   256  				Year:         100,
   257  				AltNames:     cert.AltNames{},
   258  				Usages:       nil,
   259  			},
   260  		},
   261  		commonConfig: []CertificateConfig{
   262  			{
   263  				certName: "apiserver",
   264  				descriptor: &cert.CertificateDescriptor{
   265  					CommonName:   "kube-apiserver",
   266  					Organization: nil,
   267  					Year:         100,
   268  					AltNames:     cert.AltNames{},
   269  					Usages:       []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth},
   270  				},
   271  			},
   272  			{
   273  				certName: "apiserver-kubelet-client",
   274  				descriptor: &cert.CertificateDescriptor{
   275  					CommonName:   "kube-apiserver-kubelet-client",
   276  					Organization: []string{"system:masters"},
   277  					Year:         100,
   278  					AltNames:     cert.AltNames{},
   279  					Usages:       []x509.ExtKeyUsage{x509.ExtKeyUsageClientAuth},
   280  				},
   281  			},
   282  		},
   283  	}
   284  
   285  	IPs := map[string]net.IP{
   286  		"127.0.0.1": net.IPv4(127, 0, 0, 1),
   287  	}
   288  
   289  	dnsName := map[string]string{
   290  		"localhost":              "localhost",
   291  		"kubernetes":             "kubernetes",
   292  		"kubernetes.default":     "kubernetes.default",
   293  		"kubernetes.default.svc": "kubernetes.default.svc",
   294  		nodeName:                 nodeName,
   295  		fmt.Sprintf("kubernetes.default.svc.%s", DNSDomain): fmt.Sprintf("kubernetes.default.svc.%s", DNSDomain),
   296  	}
   297  
   298  	for _, dns := range APIServerAltNames.DNSNames {
   299  		dnsName[dns] = dns
   300  	}
   301  
   302  	for _, ip := range APIServerAltNames.IPs {
   303  		IPs[ip.String()] = ip
   304  	}
   305  
   306  	for _, config := range kubeCert.commonConfig {
   307  		// add altNames and node name to etcd server cert and peer cert.
   308  		if config.certName == "apiserver" {
   309  			config.descriptor.AltNames.DNSNames = dnsName
   310  			config.descriptor.AltNames.IPs = IPs
   311  			logrus.Info("API server altNames: ", config.descriptor.AltNames)
   312  		}
   313  	}
   314  
   315  	return kubeCert
   316  }
   317  
   318  func getEtcdCertificateConfig(etcdCertPath, certPath, nodeName string, nodeIP net.IP) CertificateConfigFamily {
   319  	etcdCert := CertificateConfigFamily{
   320  		certPath: etcdCertPath,
   321  		caConfig: CertificateConfig{
   322  			certName: "ca",
   323  			descriptor: &cert.CertificateDescriptor{
   324  				CommonName:   "etcd-ca",
   325  				Organization: nil,
   326  				Year:         100,
   327  				AltNames:     cert.AltNames{},
   328  				Usages:       nil,
   329  			},
   330  		},
   331  		commonConfig: []CertificateConfig{
   332  			{
   333  				certPath: certPath,
   334  				certName: "apiserver-etcd-client",
   335  				descriptor: &cert.CertificateDescriptor{
   336  					CommonName:   "kube-apiserver-etcd-client",
   337  					Organization: []string{"system:masters"},
   338  					Year:         100,
   339  					AltNames:     cert.AltNames{},
   340  					Usages:       []x509.ExtKeyUsage{x509.ExtKeyUsageClientAuth},
   341  				},
   342  			},
   343  			{
   344  				certName: "server",
   345  				descriptor: &cert.CertificateDescriptor{
   346  					CommonName:   "etcd",
   347  					Organization: nil,
   348  					Year:         100,
   349  					AltNames:     cert.AltNames{},
   350  					Usages:       []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth, x509.ExtKeyUsageClientAuth},
   351  				},
   352  			},
   353  			{
   354  				certName: "peer",
   355  				descriptor: &cert.CertificateDescriptor{
   356  					CommonName:   "etcd-peer",
   357  					Organization: nil,
   358  					Year:         100,
   359  					AltNames:     cert.AltNames{},
   360  					Usages:       []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth, x509.ExtKeyUsageClientAuth},
   361  				},
   362  			},
   363  			{
   364  				certName: "healthcheck-client",
   365  				descriptor: &cert.CertificateDescriptor{
   366  					CommonName:   "kube-etcd-healthcheck-client",
   367  					Organization: []string{"system:masters"},
   368  					Year:         100,
   369  					AltNames:     cert.AltNames{},
   370  					Usages:       []x509.ExtKeyUsage{x509.ExtKeyUsageClientAuth},
   371  				},
   372  			},
   373  		},
   374  	}
   375  
   376  	altNames := cert.AltNames{
   377  		DNSNames: map[string]string{
   378  			"localhost": "localhost",
   379  			nodeName:    nodeName,
   380  		},
   381  		IPs: map[string]net.IP{
   382  			net.IPv4(127, 0, 0, 1).String(): net.IPv4(127, 0, 0, 1),
   383  			nodeIP.String():                 nodeIP,
   384  			net.IPv6loopback.String():       net.IPv6loopback,
   385  		},
   386  	}
   387  
   388  	for _, config := range etcdCert.commonConfig {
   389  		// add altNames and node name to etcd server cert and peer cert.
   390  		if config.certName == "server" || config.certName == "peer" {
   391  			config.descriptor.AltNames = altNames
   392  			config.descriptor.CommonName = nodeName
   393  		}
   394  	}
   395  
   396  	return etcdCert
   397  }
   398  
   399  func getFrontProxyCertificateConfig(certPath string) CertificateConfigFamily {
   400  	return CertificateConfigFamily{
   401  		certPath: certPath,
   402  		caConfig: CertificateConfig{
   403  			certName: "front-proxy-ca",
   404  			descriptor: &cert.CertificateDescriptor{
   405  				CommonName:   "front-proxy-ca",
   406  				Organization: nil,
   407  				Year:         100,
   408  				AltNames:     cert.AltNames{},
   409  				Usages:       nil,
   410  			},
   411  		},
   412  		commonConfig: []CertificateConfig{
   413  			{
   414  				certName: "front-proxy-client",
   415  				descriptor: &cert.CertificateDescriptor{
   416  					CommonName:   "front-proxy-client",
   417  					Organization: nil,
   418  					Year:         100,
   419  					AltNames:     cert.AltNames{},
   420  					Usages:       []x509.ExtKeyUsage{x509.ExtKeyUsageClientAuth},
   421  				},
   422  			},
   423  		},
   424  	}
   425  }
   426  
   427  // UpdateAPIServerCertSans :renew apiserver cert sans with given ca under pkiPath.
   428  func UpdateAPIServerCertSans(pkiPath string, certSans []string) error {
   429  	baseName := "apiserver"
   430  
   431  	APIServerCertSans := cert.AltNames{
   432  		DNSNames: map[string]string{},
   433  		IPs:      map[string]net.IP{},
   434  	}
   435  
   436  	for _, altName := range certSans {
   437  		ip := net.ParseIP(altName)
   438  		if ip != nil {
   439  			APIServerCertSans.IPs[ip.String()] = ip
   440  			continue
   441  		}
   442  		APIServerCertSans.DNSNames[altName] = altName
   443  	}
   444  
   445  	apiCert, _, err := cert.NewCertificateFileManger(pkiPath, baseName).Read()
   446  	if err != nil {
   447  		return fmt.Errorf("unable to load %s cert: %v", baseName, err)
   448  	}
   449  
   450  	for _, dns := range apiCert.DNSNames {
   451  		APIServerCertSans.DNSNames[dns] = dns
   452  	}
   453  
   454  	for _, ip := range apiCert.IPAddresses {
   455  		APIServerCertSans.IPs[ip.String()] = ip
   456  	}
   457  
   458  	apiCertConfig := cert.CertificateDescriptor{
   459  		Year:         100,
   460  		CommonName:   apiCert.Subject.CommonName,
   461  		Organization: apiCert.Subject.Organization,
   462  		AltNames:     APIServerCertSans,
   463  		Usages:       apiCert.ExtKeyUsage,
   464  	}
   465  
   466  	// load ca cert form pkiPath
   467  	caCert, caKey, err := cert.NewCertificateFileManger(pkiPath, "ca").Read()
   468  	if err != nil {
   469  		return fmt.Errorf("unable to load %s cert: %v", baseName, err)
   470  	}
   471  
   472  	if err != nil {
   473  		return err
   474  	}
   475  
   476  	// new api server cert
   477  	generator, err := cert.NewCommonCertificateGenerator(apiCertConfig, caCert, caKey)
   478  	if err != nil {
   479  		return fmt.Errorf("unable to generate %s cert: %v", baseName, err)
   480  	}
   481  
   482  	newCert, newKey, err := generator.Generate()
   483  	if err != nil {
   484  		return fmt.Errorf("unable to generate %s cert: %v", baseName, err)
   485  	}
   486  
   487  	// write cert file to disk
   488  	err = cert.NewCertificateFileManger(pkiPath, baseName).Write(newCert, newKey)
   489  	if err != nil {
   490  		return fmt.Errorf("unable to save %s cert: %v", baseName, err)
   491  	}
   492  
   493  	return nil
   494  }