1
16
17 package certificate
18
19 import (
20 "context"
21 "crypto/ecdsa"
22 "crypto/elliptic"
23 cryptorand "crypto/rand"
24 "crypto/rsa"
25 "crypto/tls"
26 "crypto/x509"
27 "encoding/pem"
28 "errors"
29 "fmt"
30 "reflect"
31 "sync"
32 "time"
33
34 "k8s.io/klog/v2"
35
36 certificates "k8s.io/api/certificates/v1"
37 apierrors "k8s.io/apimachinery/pkg/api/errors"
38 utilruntime "k8s.io/apimachinery/pkg/util/runtime"
39 "k8s.io/apimachinery/pkg/util/sets"
40 "k8s.io/apimachinery/pkg/util/wait"
41 clientset "k8s.io/client-go/kubernetes"
42 "k8s.io/client-go/util/cert"
43 "k8s.io/client-go/util/certificate/csr"
44 "k8s.io/client-go/util/keyutil"
45 )
46
47 var (
48
49
50 certificateWaitTimeout = 15 * time.Minute
51
52 kubeletServingUsagesWithEncipherment = []certificates.KeyUsage{
53
54
55
56
57 certificates.UsageDigitalSignature,
58
59
60
61 certificates.UsageKeyEncipherment,
62
63
64 certificates.UsageServerAuth,
65 }
66 kubeletServingUsagesNoEncipherment = []certificates.KeyUsage{
67
68
69
70
71 certificates.UsageDigitalSignature,
72
73
74 certificates.UsageServerAuth,
75 }
76 DefaultKubeletServingGetUsages = func(privateKey interface{}) []certificates.KeyUsage {
77 switch privateKey.(type) {
78 case *rsa.PrivateKey:
79 return kubeletServingUsagesWithEncipherment
80 default:
81 return kubeletServingUsagesNoEncipherment
82 }
83 }
84 kubeletClientUsagesWithEncipherment = []certificates.KeyUsage{
85
86
87
88
89 certificates.UsageDigitalSignature,
90
91
92
93 certificates.UsageKeyEncipherment,
94
95
96 certificates.UsageClientAuth,
97 }
98 kubeletClientUsagesNoEncipherment = []certificates.KeyUsage{
99
100
101
102
103 certificates.UsageDigitalSignature,
104
105
106 certificates.UsageClientAuth,
107 }
108 DefaultKubeletClientGetUsages = func(privateKey interface{}) []certificates.KeyUsage {
109 switch privateKey.(type) {
110 case *rsa.PrivateKey:
111 return kubeletClientUsagesWithEncipherment
112 default:
113 return kubeletClientUsagesNoEncipherment
114 }
115 }
116 )
117
118
119
120
121 type Manager interface {
122
123 Start()
124
125 Stop()
126
127
128
129 Current() *tls.Certificate
130
131
132
133
134
135 ServerHealthy() bool
136 }
137
138
139 type Config struct {
140
141
142
143
144 ClientsetFn ClientsetFunc
145
146
147
148
149 Template *x509.CertificateRequest
150
151
152
153
154
155
156 GetTemplate func() *x509.CertificateRequest
157
158
159 SignerName string
160
161
162
163
164 RequestedCertificateLifetime *time.Duration
165
166
167 Usages []certificates.KeyUsage
168
169
170
171 GetUsages func(privateKey interface{}) []certificates.KeyUsage
172
173
174
175 CertificateStore Store
176
177
178
179
180
181
182
183
184
185
186 BootstrapCertificatePEM []byte
187
188
189
190
191
192
193
194
195 BootstrapKeyPEM []byte `datapolicy:"security-key"`
196
197
198
199
200
201 CertificateRotation Histogram
202
203
204 CertificateRenewFailure Counter
205
206
207
208
209 Name string
210
211
212 Logf func(format string, args ...interface{})
213 }
214
215
216
217
218 type Store interface {
219
220
221
222
223
224 Current() (*tls.Certificate, error)
225
226
227
228 Update(cert, key []byte) (*tls.Certificate, error)
229 }
230
231
232
233 type Gauge interface {
234 Set(float64)
235 }
236
237
238
239 type Histogram interface {
240 Observe(float64)
241 }
242
243
244 type Counter interface {
245 Inc()
246 }
247
248
249 type NoCertKeyError string
250
251
252
253 type ClientsetFunc func(current *tls.Certificate) (clientset.Interface, error)
254
255 func (e *NoCertKeyError) Error() string { return string(*e) }
256
257 type manager struct {
258 getTemplate func() *x509.CertificateRequest
259
260
261 lastRequestLock sync.Mutex
262 lastRequestCancel context.CancelFunc
263 lastRequest *x509.CertificateRequest
264
265 dynamicTemplate bool
266 signerName string
267 requestedCertificateLifetime *time.Duration
268 getUsages func(privateKey interface{}) []certificates.KeyUsage
269 forceRotation bool
270
271 certStore Store
272
273 certificateRotation Histogram
274 certificateRenewFailure Counter
275
276
277 certAccessLock sync.RWMutex
278 cert *tls.Certificate
279 serverHealth bool
280
281
282 clientAccessLock sync.Mutex
283 clientsetFn ClientsetFunc
284 stopCh chan struct{}
285 stopped bool
286
287
288 now func() time.Time
289
290 name string
291 logf func(format string, args ...interface{})
292 }
293
294
295
296
297 func NewManager(config *Config) (Manager, error) {
298 cert, forceRotation, err := getCurrentCertificateOrBootstrap(
299 config.CertificateStore,
300 config.BootstrapCertificatePEM,
301 config.BootstrapKeyPEM)
302 if err != nil {
303 return nil, err
304 }
305
306 getTemplate := config.GetTemplate
307 if getTemplate == nil {
308 getTemplate = func() *x509.CertificateRequest { return config.Template }
309 }
310
311 if config.GetUsages != nil && config.Usages != nil {
312 return nil, errors.New("cannot specify both GetUsages and Usages")
313 }
314 if config.GetUsages == nil && config.Usages == nil {
315 return nil, errors.New("either GetUsages or Usages should be specified")
316 }
317 var getUsages func(interface{}) []certificates.KeyUsage
318 if config.GetUsages != nil {
319 getUsages = config.GetUsages
320 } else {
321 getUsages = func(interface{}) []certificates.KeyUsage { return config.Usages }
322 }
323 m := manager{
324 stopCh: make(chan struct{}),
325 clientsetFn: config.ClientsetFn,
326 getTemplate: getTemplate,
327 dynamicTemplate: config.GetTemplate != nil,
328 signerName: config.SignerName,
329 requestedCertificateLifetime: config.RequestedCertificateLifetime,
330 getUsages: getUsages,
331 certStore: config.CertificateStore,
332 cert: cert,
333 forceRotation: forceRotation,
334 certificateRotation: config.CertificateRotation,
335 certificateRenewFailure: config.CertificateRenewFailure,
336 now: time.Now,
337 }
338
339 name := config.Name
340 if len(name) == 0 {
341 name = m.signerName
342 }
343 if len(name) == 0 {
344 usages := getUsages(nil)
345 switch {
346 case hasKeyUsage(usages, certificates.UsageClientAuth):
347 name = string(certificates.UsageClientAuth)
348 default:
349 name = "certificate"
350 }
351 }
352
353 m.name = name
354 m.logf = config.Logf
355 if m.logf == nil {
356 m.logf = func(format string, args ...interface{}) { klog.V(2).Infof(format, args...) }
357 }
358
359 return &m, nil
360 }
361
362
363
364
365
366 func (m *manager) Current() *tls.Certificate {
367 m.certAccessLock.RLock()
368 defer m.certAccessLock.RUnlock()
369 if m.cert != nil && m.cert.Leaf != nil && m.now().After(m.cert.Leaf.NotAfter) {
370 m.logf("%s: Current certificate is expired", m.name)
371 return nil
372 }
373 return m.cert
374 }
375
376
377
378 func (m *manager) ServerHealthy() bool {
379 m.certAccessLock.RLock()
380 defer m.certAccessLock.RUnlock()
381 return m.serverHealth
382 }
383
384
385 func (m *manager) Stop() {
386 m.clientAccessLock.Lock()
387 defer m.clientAccessLock.Unlock()
388 if m.stopped {
389 return
390 }
391 close(m.stopCh)
392 m.stopped = true
393 }
394
395
396 func (m *manager) Start() {
397
398
399
400 if m.clientsetFn == nil {
401 m.logf("%s: Certificate rotation is not enabled, no connection to the apiserver", m.name)
402 return
403 }
404 m.logf("%s: Certificate rotation is enabled", m.name)
405
406 templateChanged := make(chan struct{})
407 go wait.Until(func() {
408 deadline := m.nextRotationDeadline()
409 if sleepInterval := deadline.Sub(m.now()); sleepInterval > 0 {
410 m.logf("%s: Waiting %v for next certificate rotation", m.name, sleepInterval)
411
412 timer := time.NewTimer(sleepInterval)
413 defer timer.Stop()
414
415 select {
416 case <-timer.C:
417
418 case <-templateChanged:
419 _, lastRequestTemplate := m.getLastRequest()
420 if reflect.DeepEqual(lastRequestTemplate, m.getTemplate()) {
421
422 return
423 }
424 m.logf("%s: Certificate template changed, rotating", m.name)
425 }
426 }
427
428
429 if m.getTemplate() == nil {
430 return
431 }
432
433 backoff := wait.Backoff{
434 Duration: 2 * time.Second,
435 Factor: 2,
436 Jitter: 0.1,
437 Steps: 5,
438 }
439 if err := wait.ExponentialBackoff(backoff, m.rotateCerts); err != nil {
440 utilruntime.HandleError(fmt.Errorf("%s: Reached backoff limit, still unable to rotate certs: %v", m.name, err))
441 wait.PollInfinite(32*time.Second, m.rotateCerts)
442 }
443 }, time.Second, m.stopCh)
444
445 if m.dynamicTemplate {
446 go wait.Until(func() {
447
448 lastRequestCancel, lastRequestTemplate := m.getLastRequest()
449
450 if !m.certSatisfiesTemplate() && !reflect.DeepEqual(lastRequestTemplate, m.getTemplate()) {
451
452
453 if lastRequestCancel != nil {
454
455 lastRequestCancel()
456 }
457 select {
458 case templateChanged <- struct{}{}:
459 case <-m.stopCh:
460 }
461 }
462 }, time.Second, m.stopCh)
463 }
464 }
465
466 func getCurrentCertificateOrBootstrap(
467 store Store,
468 bootstrapCertificatePEM []byte,
469 bootstrapKeyPEM []byte) (cert *tls.Certificate, shouldRotate bool, errResult error) {
470
471 currentCert, err := store.Current()
472 if err == nil {
473
474 if currentCert.Leaf != nil && time.Now().Before(currentCert.Leaf.NotAfter) {
475 return currentCert, false, nil
476 }
477 } else {
478 if _, ok := err.(*NoCertKeyError); !ok {
479 return nil, false, err
480 }
481 }
482
483 if bootstrapCertificatePEM == nil || bootstrapKeyPEM == nil {
484 return nil, true, nil
485 }
486
487 bootstrapCert, err := tls.X509KeyPair(bootstrapCertificatePEM, bootstrapKeyPEM)
488 if err != nil {
489 return nil, false, err
490 }
491 if len(bootstrapCert.Certificate) < 1 {
492 return nil, false, fmt.Errorf("no cert/key data found")
493 }
494
495 certs, err := x509.ParseCertificates(bootstrapCert.Certificate[0])
496 if err != nil {
497 return nil, false, fmt.Errorf("unable to parse certificate data: %v", err)
498 }
499 if len(certs) < 1 {
500 return nil, false, fmt.Errorf("no cert data found")
501 }
502 bootstrapCert.Leaf = certs[0]
503
504 if _, err := store.Update(bootstrapCertificatePEM, bootstrapKeyPEM); err != nil {
505 utilruntime.HandleError(fmt.Errorf("unable to set the cert/key pair to the bootstrap certificate: %v", err))
506 }
507
508 return &bootstrapCert, true, nil
509 }
510
511 func (m *manager) getClientset() (clientset.Interface, error) {
512 current := m.Current()
513 m.clientAccessLock.Lock()
514 defer m.clientAccessLock.Unlock()
515 return m.clientsetFn(current)
516 }
517
518
519
520
521 func (m *manager) RotateCerts() (bool, error) {
522 return m.rotateCerts()
523 }
524
525
526
527
528
529
530
531 func (m *manager) rotateCerts() (bool, error) {
532 m.logf("%s: Rotating certificates", m.name)
533
534 template, csrPEM, keyPEM, privateKey, err := m.generateCSR()
535 if err != nil {
536 utilruntime.HandleError(fmt.Errorf("%s: Unable to generate a certificate signing request: %v", m.name, err))
537 if m.certificateRenewFailure != nil {
538 m.certificateRenewFailure.Inc()
539 }
540 return false, nil
541 }
542
543
544 clientSet, err := m.getClientset()
545 if err != nil {
546 utilruntime.HandleError(fmt.Errorf("%s: Unable to load a client to request certificates: %v", m.name, err))
547 if m.certificateRenewFailure != nil {
548 m.certificateRenewFailure.Inc()
549 }
550 return false, nil
551 }
552
553 getUsages := m.getUsages
554 if m.getUsages == nil {
555 getUsages = DefaultKubeletClientGetUsages
556 }
557 usages := getUsages(privateKey)
558
559
560 reqName, reqUID, err := csr.RequestCertificate(clientSet, csrPEM, "", m.signerName, m.requestedCertificateLifetime, usages, privateKey)
561 if err != nil {
562 utilruntime.HandleError(fmt.Errorf("%s: Failed while requesting a signed certificate from the control plane: %v", m.name, err))
563 if m.certificateRenewFailure != nil {
564 m.certificateRenewFailure.Inc()
565 }
566 return false, m.updateServerError(err)
567 }
568
569 ctx, cancel := context.WithTimeout(context.Background(), certificateWaitTimeout)
570 defer cancel()
571
572
573 m.setLastRequest(cancel, template)
574
575
576
577 crtPEM, err := csr.WaitForCertificate(ctx, clientSet, reqName, reqUID)
578 if err != nil {
579 utilruntime.HandleError(fmt.Errorf("%s: certificate request was not signed: %v", m.name, err))
580 if m.certificateRenewFailure != nil {
581 m.certificateRenewFailure.Inc()
582 }
583 return false, nil
584 }
585
586 cert, err := m.certStore.Update(crtPEM, keyPEM)
587 if err != nil {
588 utilruntime.HandleError(fmt.Errorf("%s: Unable to store the new cert/key pair: %v", m.name, err))
589 if m.certificateRenewFailure != nil {
590 m.certificateRenewFailure.Inc()
591 }
592 return false, nil
593 }
594
595 if old := m.updateCached(cert); old != nil && m.certificateRotation != nil {
596 m.certificateRotation.Observe(m.now().Sub(old.Leaf.NotBefore).Seconds())
597 }
598
599 return true, nil
600 }
601
602
603
604
605
606
607
608
609 func (m *manager) certSatisfiesTemplateLocked() bool {
610 if m.cert == nil {
611 return false
612 }
613
614 if template := m.getTemplate(); template != nil {
615 if template.Subject.CommonName != m.cert.Leaf.Subject.CommonName {
616 m.logf("%s: Current certificate CN (%s) does not match requested CN (%s)", m.name, m.cert.Leaf.Subject.CommonName, template.Subject.CommonName)
617 return false
618 }
619
620 currentDNSNames := sets.NewString(m.cert.Leaf.DNSNames...)
621 desiredDNSNames := sets.NewString(template.DNSNames...)
622 missingDNSNames := desiredDNSNames.Difference(currentDNSNames)
623 if len(missingDNSNames) > 0 {
624 m.logf("%s: Current certificate is missing requested DNS names %v", m.name, missingDNSNames.List())
625 return false
626 }
627
628 currentIPs := sets.NewString()
629 for _, ip := range m.cert.Leaf.IPAddresses {
630 currentIPs.Insert(ip.String())
631 }
632 desiredIPs := sets.NewString()
633 for _, ip := range template.IPAddresses {
634 desiredIPs.Insert(ip.String())
635 }
636 missingIPs := desiredIPs.Difference(currentIPs)
637 if len(missingIPs) > 0 {
638 m.logf("%s: Current certificate is missing requested IP addresses %v", m.name, missingIPs.List())
639 return false
640 }
641
642 currentOrgs := sets.NewString(m.cert.Leaf.Subject.Organization...)
643 desiredOrgs := sets.NewString(template.Subject.Organization...)
644 missingOrgs := desiredOrgs.Difference(currentOrgs)
645 if len(missingOrgs) > 0 {
646 m.logf("%s: Current certificate is missing requested orgs %v", m.name, missingOrgs.List())
647 return false
648 }
649 }
650
651 return true
652 }
653
654 func (m *manager) certSatisfiesTemplate() bool {
655 m.certAccessLock.RLock()
656 defer m.certAccessLock.RUnlock()
657 return m.certSatisfiesTemplateLocked()
658 }
659
660
661
662
663 func (m *manager) nextRotationDeadline() time.Time {
664
665 if m.forceRotation {
666 m.forceRotation = false
667 return m.now()
668 }
669
670 m.certAccessLock.RLock()
671 defer m.certAccessLock.RUnlock()
672
673 if !m.certSatisfiesTemplateLocked() {
674 return m.now()
675 }
676
677 notAfter := m.cert.Leaf.NotAfter
678 totalDuration := float64(notAfter.Sub(m.cert.Leaf.NotBefore))
679 deadline := m.cert.Leaf.NotBefore.Add(jitteryDuration(totalDuration))
680
681 m.logf("%s: Certificate expiration is %v, rotation deadline is %v", m.name, notAfter, deadline)
682 return deadline
683 }
684
685
686
687
688
689
690
691
692
693 var jitteryDuration = func(totalDuration float64) time.Duration {
694 return wait.Jitter(time.Duration(totalDuration), 0.2) - time.Duration(totalDuration*0.3)
695 }
696
697
698
699 func (m *manager) updateCached(cert *tls.Certificate) *tls.Certificate {
700 m.certAccessLock.Lock()
701 defer m.certAccessLock.Unlock()
702 m.serverHealth = true
703 old := m.cert
704 m.cert = cert
705 return old
706 }
707
708
709
710
711
712 func (m *manager) updateServerError(err error) error {
713 m.certAccessLock.Lock()
714 defer m.certAccessLock.Unlock()
715 switch {
716 case apierrors.IsUnauthorized(err):
717
718 m.serverHealth = true
719 case apierrors.IsUnexpectedServerError(err):
720
721
722 m.serverHealth = false
723 default:
724
725
726 m.serverHealth = apierrors.IsNotFound(err) || apierrors.IsForbidden(err)
727 }
728 return nil
729 }
730
731 func (m *manager) generateCSR() (template *x509.CertificateRequest, csrPEM []byte, keyPEM []byte, key interface{}, err error) {
732
733 privateKey, err := ecdsa.GenerateKey(elliptic.P256(), cryptorand.Reader)
734 if err != nil {
735 return nil, nil, nil, nil, fmt.Errorf("%s: unable to generate a new private key: %v", m.name, err)
736 }
737 der, err := x509.MarshalECPrivateKey(privateKey)
738 if err != nil {
739 return nil, nil, nil, nil, fmt.Errorf("%s: unable to marshal the new key to DER: %v", m.name, err)
740 }
741
742 keyPEM = pem.EncodeToMemory(&pem.Block{Type: keyutil.ECPrivateKeyBlockType, Bytes: der})
743
744 template = m.getTemplate()
745 if template == nil {
746 return nil, nil, nil, nil, fmt.Errorf("%s: unable to create a csr, no template available", m.name)
747 }
748 csrPEM, err = cert.MakeCSRFromTemplate(privateKey, template)
749 if err != nil {
750 return nil, nil, nil, nil, fmt.Errorf("%s: unable to create a csr from the private key: %v", m.name, err)
751 }
752 return template, csrPEM, keyPEM, privateKey, nil
753 }
754
755 func (m *manager) getLastRequest() (context.CancelFunc, *x509.CertificateRequest) {
756 m.lastRequestLock.Lock()
757 defer m.lastRequestLock.Unlock()
758 return m.lastRequestCancel, m.lastRequest
759 }
760
761 func (m *manager) setLastRequest(cancel context.CancelFunc, r *x509.CertificateRequest) {
762 m.lastRequestLock.Lock()
763 defer m.lastRequestLock.Unlock()
764 m.lastRequestCancel = cancel
765 m.lastRequest = r
766 }
767
768 func hasKeyUsage(usages []certificates.KeyUsage, usage certificates.KeyUsage) bool {
769 for _, u := range usages {
770 if u == usage {
771 return true
772 }
773 }
774 return false
775 }
776
View as plain text