1
1
package certificate
2
2
3
3
import (
4
+ "context"
5
+ "errors"
6
+ "sync"
4
7
"time"
5
8
6
9
"github.com/rs/zerolog/log"
7
10
8
11
"github.com/openservicemesh/osm/pkg/announcements"
12
+ "github.com/openservicemesh/osm/pkg/constants"
9
13
"github.com/openservicemesh/osm/pkg/errcode"
10
14
"github.com/openservicemesh/osm/pkg/k8s/events"
11
15
"github.com/openservicemesh/osm/pkg/messaging"
12
16
)
13
17
14
- // NewManager creates a new CertManager with the passed CA and CA Private Key
15
- func NewManager (mrcClient MRCClient , serviceCertValidityDuration time.Duration , msgBroker * messaging.Broker ) (* Manager , error ) {
16
- // TODO(#4502): transition this call to a watch function that knows how to handle multiple MRC and can react to changes.
17
- mrcs , err := mrcClient .List ()
18
- if err != nil {
19
- return nil , err
18
+ // NewManager creates a new CertificateManager with the passed MRCClient and options
19
+ func NewManager (ctx context.Context , mrcClient MRCClient , serviceCertValidityDuration time.Duration , msgBroker * messaging.Broker , checkInterval time.Duration ) (* Manager , error ) {
20
+ m := & Manager {
21
+ serviceCertValidityDuration : serviceCertValidityDuration ,
22
+ msgBroker : msgBroker ,
20
23
}
21
24
22
- client , ca , clientID , err := mrcClient . GetCertIssuerForMRC ( mrcs [ 0 ] )
25
+ err := m . start ( ctx , mrcClient )
23
26
if err != nil {
24
27
return nil , err
25
28
}
26
29
27
- c := & issuer {Issuer : client , ID : clientID , CertificateAuthority : ca , TrustDomain : mrcs [0 ].Spec .TrustDomain }
28
-
29
- m := & Manager {
30
- // The signingIssuer is responsible for signing all newly issued certificates
31
- // The validatingIssuer is the issuer that issued existing certificates.
32
- // its underlying cert is still in the validating trust store
33
- signingIssuer : c ,
34
- validatingIssuer : c ,
35
- serviceCertValidityDuration : serviceCertValidityDuration ,
36
- msgBroker : msgBroker ,
37
- }
30
+ m .startRotationTicker (ctx , checkInterval )
38
31
return m , nil
39
32
}
40
33
41
- // Start takes an interval to check if the certificate
42
- // needs to be rotated
43
- func (m * Manager ) Start (checkInterval time.Duration , stop <- chan struct {}) {
34
+ func (m * Manager ) startRotationTicker (ctx context.Context , checkInterval time.Duration ) {
44
35
ticker := time .NewTicker (checkInterval )
45
36
go func () {
46
37
m .checkAndRotate ()
47
38
for {
48
39
select {
49
- case <- stop :
40
+ case <- ctx . Done () :
50
41
ticker .Stop ()
51
42
return
52
43
case <- ticker .C :
@@ -56,6 +47,103 @@ func (m *Manager) Start(checkInterval time.Duration, stop <-chan struct{}) {
56
47
}()
57
48
}
58
49
50
+ func (m * Manager ) start (ctx context.Context , mrcClient MRCClient ) error {
51
+ // start a watch and we wait until the manager is initialized so that
52
+ // the caller gets a manager that's ready to be used
53
+ var once sync.Once
54
+ var wg sync.WaitGroup
55
+ mrcEvents , err := mrcClient .Watch (ctx )
56
+ if err != nil {
57
+ return err
58
+ }
59
+
60
+ wg .Add (1 )
61
+
62
+ go func (wg * sync.WaitGroup , once * sync.Once ) {
63
+ for {
64
+ select {
65
+ case <- ctx .Done ():
66
+ if err := ctx .Err (); err != nil {
67
+ log .Error ().Err (err ).Msg ("context canceled with error. stopping MRC watch..." )
68
+ return
69
+ }
70
+
71
+ log .Info ().Msg ("context canceled. stopping MRC watch..." )
72
+ return
73
+ case event , open := <- mrcEvents :
74
+ if ! open {
75
+ // channel was closed; return
76
+ log .Info ().Msg ("stopping MRC watch..." )
77
+ return
78
+ }
79
+
80
+ err = m .handleMRCEvent (mrcClient , event )
81
+ if err != nil {
82
+ log .Error ().Err (err ).Msgf ("error encountered processing MRCEvent" )
83
+ continue
84
+ }
85
+ }
86
+
87
+ if m .signingIssuer != nil && m .validatingIssuer != nil {
88
+ once .Do (func () {
89
+ wg .Done ()
90
+ })
91
+ }
92
+ }
93
+ }(& wg , & once )
94
+
95
+ done := make (chan struct {})
96
+
97
+ // Wait for WaitGroup to finish and notify select when it does
98
+ go func () {
99
+ wg .Wait ()
100
+ close (done )
101
+ }()
102
+
103
+ select {
104
+ case <- time .After (10 * time .Second ):
105
+ // We timed out
106
+ return errors .New ("manager initialization timed out. Make sure your MeshRootCertificate(s) are valid" )
107
+ case <- done :
108
+ }
109
+
110
+ return nil
111
+ }
112
+
113
+ func (m * Manager ) handleMRCEvent (mrcClient MRCClient , event MRCEvent ) error {
114
+ switch event .Type {
115
+ case MRCEventAdded :
116
+ mrc := event .MRC
117
+ if mrc .Status .State == constants .MRCStateError {
118
+ log .Debug ().Msgf ("skipping MRC with error state %s" , mrc .GetName ())
119
+ return nil
120
+ }
121
+
122
+ client , ca , clientID , err := mrcClient .GetCertIssuerForMRC (mrc )
123
+ if err != nil {
124
+ return err
125
+ }
126
+
127
+ c := & issuer {Issuer : client , ID : clientID , CertificateAuthority : ca }
128
+ switch {
129
+ case mrc .Status .State == constants .MRCStateActive :
130
+ m .signingIssuer = c
131
+ m .validatingIssuer = c
132
+ case mrc .Status .State == constants .MRCStateIssuingRollback || mrc .Status .State == constants .MRCStateIssuingRollout :
133
+ m .signingIssuer = c
134
+ case mrc .Status .State == constants .MRCStateValidatingRollback || mrc .Status .State == constants .MRCStateValidatingRollout :
135
+ m .validatingIssuer = c
136
+ default :
137
+ m .signingIssuer = c
138
+ m .validatingIssuer = c
139
+ }
140
+ case MRCEventUpdated :
141
+ // TODO
142
+ }
143
+
144
+ return nil
145
+ }
146
+
59
147
// GetTrustDomain returns the trust domain from the configured signingkey issuer.
60
148
// Note that the CRD uses a default, so this value will always be set.
61
149
func (m * Manager ) GetTrustDomain () string {
0 commit comments