renewer.go 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166
  1. package ca
  2. import (
  3. "sync"
  4. "time"
  5. "github.com/Sirupsen/logrus"
  6. "github.com/docker/go-events"
  7. "github.com/docker/swarmkit/connectionbroker"
  8. "github.com/docker/swarmkit/log"
  9. "github.com/pkg/errors"
  10. "golang.org/x/net/context"
  11. )
  12. // RenewTLSExponentialBackoff sets the exponential backoff when trying to renew TLS certificates that have expired
  13. var RenewTLSExponentialBackoff = events.ExponentialBackoffConfig{
  14. Base: time.Second * 5,
  15. Factor: time.Second * 5,
  16. Max: 1 * time.Hour,
  17. }
  18. // TLSRenewer handles renewing TLS certificates, either automatically or upon
  19. // request.
  20. type TLSRenewer struct {
  21. mu sync.Mutex
  22. s *SecurityConfig
  23. connBroker *connectionbroker.Broker
  24. renew chan struct{}
  25. expectedRole string
  26. }
  27. // NewTLSRenewer creates a new TLS renewer. It must be started with Start.
  28. func NewTLSRenewer(s *SecurityConfig, connBroker *connectionbroker.Broker) *TLSRenewer {
  29. return &TLSRenewer{
  30. s: s,
  31. connBroker: connBroker,
  32. renew: make(chan struct{}, 1),
  33. }
  34. }
  35. // SetExpectedRole sets the expected role. If a renewal is forced, and the role
  36. // doesn't match this expectation, renewal will be retried with exponential
  37. // backoff until it does match.
  38. func (t *TLSRenewer) SetExpectedRole(role string) {
  39. t.mu.Lock()
  40. t.expectedRole = role
  41. t.mu.Unlock()
  42. }
  43. // Renew causes the TLSRenewer to renew the certificate (nearly) right away,
  44. // instead of waiting for the next automatic renewal.
  45. func (t *TLSRenewer) Renew() {
  46. select {
  47. case t.renew <- struct{}{}:
  48. default:
  49. }
  50. }
  51. // Start will continuously monitor for the necessity of renewing the local certificates, either by
  52. // issuing them locally if key-material is available, or requesting them from a remote CA.
  53. func (t *TLSRenewer) Start(ctx context.Context) <-chan CertificateUpdate {
  54. updates := make(chan CertificateUpdate)
  55. go func() {
  56. var (
  57. retry time.Duration
  58. forceRetry bool
  59. )
  60. expBackoff := events.NewExponentialBackoff(RenewTLSExponentialBackoff)
  61. defer close(updates)
  62. for {
  63. ctx = log.WithModule(ctx, "tls")
  64. log := log.G(ctx).WithFields(logrus.Fields{
  65. "node.id": t.s.ClientTLSCreds.NodeID(),
  66. "node.role": t.s.ClientTLSCreds.Role(),
  67. })
  68. // Our starting default will be 5 minutes
  69. retry = 5 * time.Minute
  70. // Since the expiration of the certificate is managed remotely we should update our
  71. // retry timer on every iteration of this loop.
  72. // Retrieve the current certificate expiration information.
  73. validFrom, validUntil, err := readCertValidity(t.s.KeyReader())
  74. if err != nil {
  75. // We failed to read the expiration, let's stick with the starting default
  76. log.Errorf("failed to read the expiration of the TLS certificate in: %s", t.s.KeyReader().Target())
  77. select {
  78. case updates <- CertificateUpdate{Err: errors.New("failed to read certificate expiration")}:
  79. case <-ctx.Done():
  80. log.Info("shutting down certificate renewal routine")
  81. return
  82. }
  83. } else {
  84. // If we have an expired certificate, try to renew immediately: the hope that this is a temporary clock skew, or
  85. // we can issue our own TLS certs.
  86. if validUntil.Before(time.Now()) {
  87. log.Warn("the current TLS certificate is expired, so an attempt to renew it will be made immediately")
  88. // retry immediately(ish) with exponential backoff
  89. retry = expBackoff.Proceed(nil)
  90. } else if forceRetry {
  91. // A forced renewal was requested, but did not succeed yet.
  92. // retry immediately(ish) with exponential backoff
  93. retry = expBackoff.Proceed(nil)
  94. } else {
  95. // Random retry time between 50% and 80% of the total time to expiration
  96. retry = calculateRandomExpiry(validFrom, validUntil)
  97. }
  98. }
  99. log.WithFields(logrus.Fields{
  100. "time": time.Now().Add(retry),
  101. }).Debugf("next certificate renewal scheduled for %v from now", retry)
  102. select {
  103. case <-time.After(retry):
  104. log.Info("renewing certificate")
  105. case <-t.renew:
  106. forceRetry = true
  107. log.Info("forced certificate renewal")
  108. // Pause briefly before attempting the renewal,
  109. // to give the CA a chance to reconcile the
  110. // desired role.
  111. select {
  112. case <-time.After(500 * time.Millisecond):
  113. case <-ctx.Done():
  114. log.Info("shutting down certificate renewal routine")
  115. return
  116. }
  117. case <-ctx.Done():
  118. log.Info("shutting down certificate renewal routine")
  119. return
  120. }
  121. // ignore errors - it will just try again later
  122. var certUpdate CertificateUpdate
  123. if err := RenewTLSConfigNow(ctx, t.s, t.connBroker); err != nil {
  124. certUpdate.Err = err
  125. expBackoff.Failure(nil, nil)
  126. } else {
  127. newRole := t.s.ClientTLSCreds.Role()
  128. t.mu.Lock()
  129. expectedRole := t.expectedRole
  130. t.mu.Unlock()
  131. if expectedRole != "" && expectedRole != newRole {
  132. expBackoff.Failure(nil, nil)
  133. continue
  134. }
  135. certUpdate.Role = newRole
  136. expBackoff.Success(nil)
  137. forceRetry = false
  138. }
  139. select {
  140. case updates <- certUpdate:
  141. case <-ctx.Done():
  142. log.Info("shutting down certificate renewal routine")
  143. return
  144. }
  145. }
  146. }()
  147. return updates
  148. }