k8s.io/kubernetes@v1.29.3/pkg/kubelet/certificate/kubelet.go (about)

     1  /*
     2  Copyright 2017 The Kubernetes Authors.
     3  
     4  Licensed under the Apache License, Version 2.0 (the "License");
     5  you may not use this file except in compliance with the License.
     6  You may obtain a copy of the License at
     7  
     8      http://www.apache.org/licenses/LICENSE-2.0
     9  
    10  Unless required by applicable law or agreed to in writing, software
    11  distributed under the License is distributed on an "AS IS" BASIS,
    12  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13  See the License for the specific language governing permissions and
    14  limitations under the License.
    15  */
    16  
    17  package certificate
    18  
    19  import (
    20  	"crypto/tls"
    21  	"crypto/x509"
    22  	"crypto/x509/pkix"
    23  	"fmt"
    24  	"math"
    25  	"net"
    26  	"sort"
    27  	"time"
    28  
    29  	certificates "k8s.io/api/certificates/v1"
    30  	v1 "k8s.io/api/core/v1"
    31  	"k8s.io/apimachinery/pkg/types"
    32  	clientset "k8s.io/client-go/kubernetes"
    33  	"k8s.io/client-go/util/certificate"
    34  	compbasemetrics "k8s.io/component-base/metrics"
    35  	"k8s.io/component-base/metrics/legacyregistry"
    36  	kubeletconfig "k8s.io/kubernetes/pkg/kubelet/apis/config"
    37  	"k8s.io/kubernetes/pkg/kubelet/metrics"
    38  	netutils "k8s.io/utils/net"
    39  )
    40  
    41  // NewKubeletServerCertificateManager creates a certificate manager for the kubelet when retrieving a server certificate
    42  // or returns an error.
    43  func NewKubeletServerCertificateManager(kubeClient clientset.Interface, kubeCfg *kubeletconfig.KubeletConfiguration, nodeName types.NodeName, getAddresses func() []v1.NodeAddress, certDirectory string) (certificate.Manager, error) {
    44  	var clientsetFn certificate.ClientsetFunc
    45  	if kubeClient != nil {
    46  		clientsetFn = func(current *tls.Certificate) (clientset.Interface, error) {
    47  			return kubeClient, nil
    48  		}
    49  	}
    50  	certificateStore, err := certificate.NewFileStore(
    51  		"kubelet-server",
    52  		certDirectory,
    53  		certDirectory,
    54  		kubeCfg.TLSCertFile,
    55  		kubeCfg.TLSPrivateKeyFile)
    56  	if err != nil {
    57  		return nil, fmt.Errorf("failed to initialize server certificate store: %v", err)
    58  	}
    59  	var certificateRenewFailure = compbasemetrics.NewCounter(
    60  		&compbasemetrics.CounterOpts{
    61  			Subsystem:      metrics.KubeletSubsystem,
    62  			Name:           "server_expiration_renew_errors",
    63  			Help:           "Counter of certificate renewal errors.",
    64  			StabilityLevel: compbasemetrics.ALPHA,
    65  		},
    66  	)
    67  	legacyregistry.MustRegister(certificateRenewFailure)
    68  
    69  	certificateRotationAge := compbasemetrics.NewHistogram(
    70  		&compbasemetrics.HistogramOpts{
    71  			Subsystem: metrics.KubeletSubsystem,
    72  			Name:      "certificate_manager_server_rotation_seconds",
    73  			Help:      "Histogram of the number of seconds the previous certificate lived before being rotated.",
    74  			Buckets: []float64{
    75  				60,        // 1  minute
    76  				3600,      // 1  hour
    77  				14400,     // 4  hours
    78  				86400,     // 1  day
    79  				604800,    // 1  week
    80  				2592000,   // 1  month
    81  				7776000,   // 3  months
    82  				15552000,  // 6  months
    83  				31104000,  // 1  year
    84  				124416000, // 4  years
    85  			},
    86  			StabilityLevel: compbasemetrics.ALPHA,
    87  		},
    88  	)
    89  	legacyregistry.MustRegister(certificateRotationAge)
    90  
    91  	getTemplate := func() *x509.CertificateRequest {
    92  		hostnames, ips := addressesToHostnamesAndIPs(getAddresses())
    93  		// don't return a template if we have no addresses to request for
    94  		if len(hostnames) == 0 && len(ips) == 0 {
    95  			return nil
    96  		}
    97  		return &x509.CertificateRequest{
    98  			Subject: pkix.Name{
    99  				CommonName:   fmt.Sprintf("system:node:%s", nodeName),
   100  				Organization: []string{"system:nodes"},
   101  			},
   102  			DNSNames:    hostnames,
   103  			IPAddresses: ips,
   104  		}
   105  	}
   106  
   107  	m, err := certificate.NewManager(&certificate.Config{
   108  		ClientsetFn:             clientsetFn,
   109  		GetTemplate:             getTemplate,
   110  		SignerName:              certificates.KubeletServingSignerName,
   111  		GetUsages:               certificate.DefaultKubeletServingGetUsages,
   112  		CertificateStore:        certificateStore,
   113  		CertificateRotation:     certificateRotationAge,
   114  		CertificateRenewFailure: certificateRenewFailure,
   115  	})
   116  	if err != nil {
   117  		return nil, fmt.Errorf("failed to initialize server certificate manager: %v", err)
   118  	}
   119  	legacyregistry.RawMustRegister(compbasemetrics.NewGaugeFunc(
   120  		&compbasemetrics.GaugeOpts{
   121  			Subsystem: metrics.KubeletSubsystem,
   122  			Name:      "certificate_manager_server_ttl_seconds",
   123  			Help: "Gauge of the shortest TTL (time-to-live) of " +
   124  				"the Kubelet's serving certificate. The value is in seconds " +
   125  				"until certificate expiry (negative if already expired). If " +
   126  				"serving certificate is invalid or unused, the value will " +
   127  				"be +INF.",
   128  			StabilityLevel: compbasemetrics.ALPHA,
   129  		},
   130  		func() float64 {
   131  			if c := m.Current(); c != nil && c.Leaf != nil {
   132  				return math.Trunc(time.Until(c.Leaf.NotAfter).Seconds())
   133  			}
   134  			return math.Inf(1)
   135  		},
   136  	))
   137  	return m, nil
   138  }
   139  
   140  func addressesToHostnamesAndIPs(addresses []v1.NodeAddress) (dnsNames []string, ips []net.IP) {
   141  	seenDNSNames := map[string]bool{}
   142  	seenIPs := map[string]bool{}
   143  	for _, address := range addresses {
   144  		if len(address.Address) == 0 {
   145  			continue
   146  		}
   147  
   148  		switch address.Type {
   149  		case v1.NodeHostName:
   150  			if ip := netutils.ParseIPSloppy(address.Address); ip != nil {
   151  				seenIPs[address.Address] = true
   152  			} else {
   153  				seenDNSNames[address.Address] = true
   154  			}
   155  		case v1.NodeExternalIP, v1.NodeInternalIP:
   156  			if ip := netutils.ParseIPSloppy(address.Address); ip != nil {
   157  				seenIPs[address.Address] = true
   158  			}
   159  		case v1.NodeExternalDNS, v1.NodeInternalDNS:
   160  			seenDNSNames[address.Address] = true
   161  		}
   162  	}
   163  
   164  	for dnsName := range seenDNSNames {
   165  		dnsNames = append(dnsNames, dnsName)
   166  	}
   167  	for ip := range seenIPs {
   168  		ips = append(ips, netutils.ParseIPSloppy(ip))
   169  	}
   170  
   171  	// return in stable order
   172  	sort.Strings(dnsNames)
   173  	sort.Slice(ips, func(i, j int) bool { return ips[i].String() < ips[j].String() })
   174  
   175  	return dnsNames, ips
   176  }
   177  
   178  // NewKubeletClientCertificateManager sets up a certificate manager without a
   179  // client that can be used to sign new certificates (or rotate). If a CSR
   180  // client is set later, it may begin rotating/renewing the client cert.
   181  func NewKubeletClientCertificateManager(
   182  	certDirectory string,
   183  	nodeName types.NodeName,
   184  	bootstrapCertData []byte,
   185  	bootstrapKeyData []byte,
   186  	certFile string,
   187  	keyFile string,
   188  	clientsetFn certificate.ClientsetFunc,
   189  ) (certificate.Manager, error) {
   190  
   191  	certificateStore, err := certificate.NewFileStore(
   192  		"kubelet-client",
   193  		certDirectory,
   194  		certDirectory,
   195  		certFile,
   196  		keyFile)
   197  	if err != nil {
   198  		return nil, fmt.Errorf("failed to initialize client certificate store: %v", err)
   199  	}
   200  	var certificateRenewFailure = compbasemetrics.NewCounter(
   201  		&compbasemetrics.CounterOpts{
   202  			Namespace:      metrics.KubeletSubsystem,
   203  			Subsystem:      "certificate_manager",
   204  			Name:           "client_expiration_renew_errors",
   205  			Help:           "Counter of certificate renewal errors.",
   206  			StabilityLevel: compbasemetrics.ALPHA,
   207  		},
   208  	)
   209  	legacyregistry.Register(certificateRenewFailure)
   210  
   211  	m, err := certificate.NewManager(&certificate.Config{
   212  		ClientsetFn: clientsetFn,
   213  		Template: &x509.CertificateRequest{
   214  			Subject: pkix.Name{
   215  				CommonName:   fmt.Sprintf("system:node:%s", nodeName),
   216  				Organization: []string{"system:nodes"},
   217  			},
   218  		},
   219  		SignerName: certificates.KubeAPIServerClientKubeletSignerName,
   220  		GetUsages:  certificate.DefaultKubeletClientGetUsages,
   221  		// For backwards compatibility, the kubelet supports the ability to
   222  		// provide a higher privileged certificate as initial data that will
   223  		// then be rotated immediately. This code path is used by kubeadm on
   224  		// the masters.
   225  		BootstrapCertificatePEM: bootstrapCertData,
   226  		BootstrapKeyPEM:         bootstrapKeyData,
   227  
   228  		CertificateStore:        certificateStore,
   229  		CertificateRenewFailure: certificateRenewFailure,
   230  	})
   231  	if err != nil {
   232  		return nil, fmt.Errorf("failed to initialize client certificate manager: %v", err)
   233  	}
   234  
   235  	return m, nil
   236  }