@@ -3,7 +3,6 @@ package certificate
3
3
import (
4
4
"time"
5
5
6
- "github.com/pkg/errors"
7
6
"github.com/rs/zerolog/log"
8
7
9
8
"github.com/openservicemesh/osm/pkg/announcements"
@@ -20,14 +19,17 @@ func NewManager(mrcClient MRCClient, serviceCertValidityDuration time.Duration,
20
19
return nil , err
21
20
}
22
21
23
- client , err := mrcClient .GetCertIssuerForMRC (mrcs [0 ])
22
+ client , clientID , err := mrcClient .GetCertIssuerForMRC (mrcs [0 ])
24
23
if err != nil {
25
24
return nil , err
26
25
}
27
26
27
+ c := & issuer {Issuer : client , ID : clientID }
28
+
28
29
m := & Manager {
29
30
// The root certificate signing all newly issued certificates
30
- clients : []Issuer {client },
31
+ keyIssuer : c ,
32
+ pubIssuer : c ,
31
33
serviceCertValidityDuration : serviceCertValidityDuration ,
32
34
msgBroker : msgBroker ,
33
35
}
@@ -36,19 +38,13 @@ func NewManager(mrcClient MRCClient, serviceCertValidityDuration time.Duration,
36
38
37
39
// Start takes an interval to check if the certificate
38
40
// needs to be rotated
39
- func (m * Manager ) Start (checkInterval time.Duration , certRotation <- chan struct {}) {
40
- // iterate over the list of certificates
41
- // when a cert needs to be rotated - call RotateCertificate()
42
- if certRotation == nil {
43
- log .Error ().Msgf ("Cannot start certificate rotation, certRotation is nil" )
44
- return
45
- }
41
+ func (m * Manager ) Start (checkInterval time.Duration , stop <- chan struct {}) {
46
42
ticker := time .NewTicker (checkInterval )
47
43
go func () {
48
44
m .checkAndRotate ()
49
45
for {
50
46
select {
51
- case <- certRotation :
47
+ case <- stop :
52
48
ticker .Stop ()
53
49
return
54
50
case <- ticker .C :
@@ -59,6 +55,9 @@ func (m *Manager) Start(checkInterval time.Duration, certRotation <-chan struct{
59
55
}
60
56
61
57
func (m * Manager ) checkAndRotate () {
58
+ // NOTE: checkAndRotate can reintroduce a certificate that has been released, thereby creating an unbounded cache.
59
+ // A certificate can also have been rotated already, leaving the list of issued certs stale, and we re-rotate.
60
+ // the latter is not a bug, but a source of inefficiency.
62
61
for _ , cert := range m .ListIssuedCertificates () {
63
62
shouldRotate := cert .ShouldRotate ()
64
63
@@ -70,15 +69,21 @@ func (m *Manager) checkAndRotate() {
70
69
RenewBeforeCertExpires )
71
70
72
71
if shouldRotate {
73
- // Remove the certificate from the cache of the certificate manager
74
- newCert , err := m .RotateCertificate (cert .GetCommonName ())
72
+ newCert , err := m .IssueCertificate (cert .GetCommonName (), m .serviceCertValidityDuration )
75
73
if err != nil {
76
74
// TODO(#3962): metric might not be scraped before process restart resulting from this error
77
75
log .Error ().Err (err ).Str (errcode .Kind , errcode .GetErrCodeWithMetric (errcode .ErrRotatingCert )).
78
76
Msgf ("Error rotating cert SerialNumber=%s" , cert .GetSerialNumber ())
79
77
continue
80
78
}
81
- log .Trace ().Msgf ("Rotated cert SerialNumber=%s" , newCert .GetSerialNumber ())
79
+
80
+ m .msgBroker .GetCertPubSub ().Pub (events.PubSubMessage {
81
+ Kind : announcements .CertificateRotated ,
82
+ NewObj : newCert ,
83
+ OldObj : cert ,
84
+ }, announcements .CertificateRotated .String ())
85
+
86
+ log .Debug ().Msgf ("Rotated certificate (old SerialNumber=%s) with new SerialNumber=%s" , cert .SerialNumber , newCert .SerialNumber )
82
87
}
83
88
}
84
89
}
@@ -99,16 +104,31 @@ func (m *Manager) getFromCache(cn CommonName) *Certificate {
99
104
100
105
// IssueCertificate implements Manager and returns a newly issued certificate from the given client.
101
106
func (m * Manager ) IssueCertificate (cn CommonName , validityPeriod time.Duration ) (* Certificate , error ) {
107
+ var err error
108
+ cert := m .getFromCache (cn ) // Don't call this while holding the lock
109
+
110
+ m .mu .RLock ()
111
+ pubIssuer := m .pubIssuer
112
+ keyIssuer := m .keyIssuer
113
+ m .mu .RUnlock ()
114
+
102
115
start := time .Now ()
116
+ if cert == nil || cert .keyIssuerID != keyIssuer .ID || cert .pubIssuerID != pubIssuer .ID {
117
+ cert , err = keyIssuer .IssueCertificate (cn , validityPeriod )
118
+ if err != nil {
119
+ return nil , err
120
+ }
121
+ if pubIssuer .ID != keyIssuer .ID {
122
+ pubCert , err := pubIssuer .IssueCertificate (cn , validityPeriod )
123
+ if err != nil {
124
+ return nil , err
125
+ }
103
126
104
- if cert := m .getFromCache (cn ); cert != nil {
105
- return cert , nil
106
- }
127
+ cert = cert .newMergedWithRoot (pubCert .GetIssuingCA ())
128
+ }
107
129
108
- // TODO(#4502): determine client(s) to use based on the rotation stage(s) of the client(s)
109
- cert , err := m .clients [0 ].IssueCertificate (cn , validityPeriod )
110
- if err != nil {
111
- return cert , err
130
+ cert .keyIssuerID = keyIssuer .ID
131
+ cert .pubIssuerID = pubIssuer .ID
112
132
}
113
133
114
134
m .cache .Store (cn , cert )
@@ -124,38 +144,6 @@ func (m *Manager) ReleaseCertificate(cn CommonName) {
124
144
m .cache .Delete (cn )
125
145
}
126
146
127
- // RotateCertificate implements Manager and rotates an existing
128
- func (m * Manager ) RotateCertificate (cn CommonName ) (* Certificate , error ) {
129
- start := time .Now ()
130
-
131
- oldObj , ok := m .cache .Load (cn )
132
- if ! ok {
133
- return nil , errors .Errorf ("Old certificate does not exist for CN=%s" , cn )
134
- }
135
-
136
- oldCert , ok := oldObj .(* Certificate )
137
- if ! ok {
138
- return nil , errors .Errorf ("unexpected type %T for old certificate does not exist for CN=%s" , oldCert , cn )
139
- }
140
-
141
- newCert , err := m .IssueCertificate (cn , m .serviceCertValidityDuration )
142
- if err != nil {
143
- return nil , err
144
- }
145
-
146
- m .cache .Store (cn , newCert )
147
-
148
- m .msgBroker .GetCertPubSub ().Pub (events.PubSubMessage {
149
- Kind : announcements .CertificateRotated ,
150
- NewObj : newCert ,
151
- OldObj : oldCert ,
152
- }, announcements .CertificateRotated .String ())
153
-
154
- log .Debug ().Msgf ("Rotated certificate (old SerialNumber=%s) with new SerialNumber=%s took %+v" , oldCert .SerialNumber , newCert .SerialNumber , time .Since (start ))
155
-
156
- return newCert , nil
157
- }
158
-
159
147
// ListIssuedCertificates implements CertificateDebugger interface and returns the list of issued certificates.
160
148
func (m * Manager ) ListIssuedCertificates () []* Certificate {
161
149
var certs []* Certificate
0 commit comments