1
16
17 package renewal
18
19 import (
20 "crypto/x509"
21 "sort"
22
23 "github.com/pkg/errors"
24
25 certutil "k8s.io/client-go/util/cert"
26
27 kubeadmapi "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm"
28 kubeadmconstants "k8s.io/kubernetes/cmd/kubeadm/app/constants"
29 certsphase "k8s.io/kubernetes/cmd/kubeadm/app/phases/certs"
30 "k8s.io/kubernetes/cmd/kubeadm/app/util/pkiutil"
31 )
32
33
34
35 type Manager struct {
36
37 cfg *kubeadmapi.ClusterConfiguration
38
39
40 kubernetesDir string
41
42
43 certificates map[string]*CertificateRenewHandler
44
45
46 cas map[string]*CAExpirationHandler
47 }
48
49 type certConfigMutatorFunc func(*certutil.Config) error
50
51
52 type CertificateRenewHandler struct {
53
54
55 Name string
56
57
58 LongName string
59
60
61 FileName string
62
63
64 CAName string
65
66
67 CABaseName string
68
69
70 readwriter certificateReadWriter
71
72
73
74 certConfigMutators []certConfigMutatorFunc
75 }
76
77
78 type CAExpirationHandler struct {
79
80
81 Name string
82
83
84 LongName string
85
86
87 FileName string
88
89
90 readwriter certificateReadWriter
91 }
92
93
94 func NewManager(cfg *kubeadmapi.ClusterConfiguration, kubernetesDir string) (*Manager, error) {
95 rm := &Manager{
96 cfg: cfg,
97 kubernetesDir: kubernetesDir,
98 certificates: map[string]*CertificateRenewHandler{},
99 cas: map[string]*CAExpirationHandler{},
100 }
101
102
103 certListFunc := certsphase.GetDefaultCertList
104 if cfg.Etcd.External != nil {
105 certListFunc = certsphase.GetCertsWithoutEtcd
106 }
107 certTree, err := certListFunc().AsMap().CertTree()
108 if err != nil {
109 return nil, err
110 }
111
112
113
114 for ca, certs := range certTree {
115 for _, cert := range certs {
116
117 pkiReadWriter := newPKICertificateReadWriter(rm.cfg.CertificatesDir, cert.BaseName)
118 certConfigMutators := loadCertConfigMutators(cert.BaseName)
119
120
121
122
123 rm.certificates[cert.Name] = &CertificateRenewHandler{
124 Name: cert.Name,
125 LongName: cert.LongName,
126 FileName: cert.BaseName,
127 CAName: ca.Name,
128 CABaseName: ca.BaseName,
129 readwriter: pkiReadWriter,
130 certConfigMutators: certConfigMutators,
131 }
132 }
133
134 pkiReadWriter := newPKICertificateReadWriter(rm.cfg.CertificatesDir, ca.BaseName)
135 rm.cas[ca.Name] = &CAExpirationHandler{
136 Name: ca.Name,
137 LongName: ca.LongName,
138 FileName: ca.BaseName,
139 readwriter: pkiReadWriter,
140 }
141 }
142
143
144 kubeConfigs := []struct {
145 longName string
146 fileName string
147 }{
148 {
149 longName: "certificate embedded in the kubeconfig file for the admin to use and for kubeadm itself",
150 fileName: kubeadmconstants.AdminKubeConfigFileName,
151 },
152 {
153 longName: "certificate embedded in the kubeconfig file for the super-admin",
154 fileName: kubeadmconstants.SuperAdminKubeConfigFileName,
155 },
156 {
157 longName: "certificate embedded in the kubeconfig file for the controller manager to use",
158 fileName: kubeadmconstants.ControllerManagerKubeConfigFileName,
159 },
160 {
161 longName: "certificate embedded in the kubeconfig file for the scheduler manager to use",
162 fileName: kubeadmconstants.SchedulerKubeConfigFileName,
163 },
164
165 }
166
167
168 for _, kubeConfig := range kubeConfigs {
169
170 kubeConfigReadWriter := newKubeconfigReadWriter(kubernetesDir, kubeConfig.fileName,
171 rm.cfg.CertificatesDir, kubeadmconstants.CACertAndKeyBaseName)
172
173
174
175
176 rm.certificates[kubeConfig.fileName] = &CertificateRenewHandler{
177 Name: kubeConfig.fileName,
178 LongName: kubeConfig.longName,
179 FileName: kubeConfig.fileName,
180 CABaseName: kubeadmconstants.CACertAndKeyBaseName,
181 CAName: kubeadmconstants.CACertAndKeyBaseName,
182 readwriter: kubeConfigReadWriter,
183 }
184 }
185
186 return rm, nil
187 }
188
189
190 func (rm *Manager) Certificates() []*CertificateRenewHandler {
191 certificates := []*CertificateRenewHandler{}
192 for _, h := range rm.certificates {
193 certificates = append(certificates, h)
194 }
195
196 sort.Slice(certificates, func(i, j int) bool { return certificates[i].Name < certificates[j].Name })
197
198 return certificates
199 }
200
201
202 func (rm *Manager) CAs() []*CAExpirationHandler {
203 cas := []*CAExpirationHandler{}
204 for _, h := range rm.cas {
205 cas = append(cas, h)
206 }
207
208 sort.Slice(cas, func(i, j int) bool { return cas[i].Name < cas[j].Name })
209
210 return cas
211 }
212
213
214
215
216
217 func (rm *Manager) RenewUsingLocalCA(name string) (bool, error) {
218 handler, ok := rm.certificates[name]
219 if !ok {
220 return false, errors.Errorf("%s is not a valid certificate for this cluster", name)
221 }
222
223
224 externallyManaged, err := rm.IsExternallyManaged(handler.CABaseName)
225 if err != nil {
226 return false, err
227 }
228
229
230 if externallyManaged {
231 return false, nil
232 }
233
234
235 cert, err := handler.readwriter.Read()
236 if err != nil {
237 return false, err
238 }
239
240
241 certConfig := certToConfig(cert)
242 for _, f := range handler.certConfigMutators {
243 if err := f(&certConfig); err != nil {
244 return false, err
245 }
246 }
247
248 cfg := &pkiutil.CertConfig{
249 Config: certConfig,
250 EncryptionAlgorithm: rm.cfg.EncryptionAlgorithmType(),
251 }
252
253
254 caCert, caKey, err := certsphase.LoadCertificateAuthority(rm.cfg.CertificatesDir, handler.CABaseName)
255 if err != nil {
256 return false, err
257 }
258
259
260 newCert, newKey, err := NewFileRenewer(caCert, caKey).Renew(cfg)
261 if err != nil {
262 return false, errors.Wrapf(err, "failed to renew certificate %s", name)
263 }
264
265
266 err = handler.readwriter.Write(newCert, newKey)
267 if err != nil {
268 return false, err
269 }
270
271 return true, nil
272 }
273
274
275
276
277
278 func (rm *Manager) CreateRenewCSR(name, outdir string) error {
279 handler, ok := rm.certificates[name]
280 if !ok {
281 return errors.Errorf("%s is not a known certificate", name)
282 }
283
284
285 cert, err := handler.readwriter.Read()
286 if err != nil {
287 return err
288 }
289
290
291 certConfig := certToConfig(cert)
292 for _, f := range handler.certConfigMutators {
293 if err := f(&certConfig); err != nil {
294 return err
295 }
296 }
297 cfg := &pkiutil.CertConfig{
298 Config: certConfig,
299 EncryptionAlgorithm: rm.cfg.EncryptionAlgorithmType(),
300 }
301
302
303 csr, key, err := pkiutil.NewCSRAndKey(cfg)
304 if err != nil {
305 return errors.Wrapf(err, "failure while generating %s CSR and key", name)
306 }
307 if err := pkiutil.WriteKey(outdir, name, key); err != nil {
308 return errors.Wrapf(err, "failure while saving %s key", name)
309 }
310
311 if err := pkiutil.WriteCSR(outdir, name, csr); err != nil {
312 return errors.Wrapf(err, "failure while saving %s CSR", name)
313 }
314
315 return nil
316 }
317
318
319 func (rm *Manager) CertificateExists(name string) (bool, error) {
320 handler, ok := rm.certificates[name]
321 if !ok {
322 return false, errors.Errorf("%s is not a known certificate", name)
323 }
324
325 return handler.readwriter.Exists()
326 }
327
328
329
330
331
332 func (rm *Manager) GetCertificateExpirationInfo(name string) (*ExpirationInfo, error) {
333 handler, ok := rm.certificates[name]
334 if !ok {
335 return nil, errors.Errorf("%s is not a known certificate", name)
336 }
337
338
339 externallyManaged, err := rm.IsExternallyManaged(handler.CABaseName)
340 if err != nil {
341 return nil, err
342 }
343
344
345 cert, err := handler.readwriter.Read()
346 if err != nil {
347 return nil, err
348 }
349
350
351 return newExpirationInfo(name, cert, externallyManaged), nil
352 }
353
354
355 func (rm *Manager) CAExists(name string) (bool, error) {
356 handler, ok := rm.cas[name]
357 if !ok {
358 return false, errors.Errorf("%s is not a known certificate", name)
359 }
360
361 return handler.readwriter.Exists()
362 }
363
364
365 func (rm *Manager) GetCAExpirationInfo(name string) (*ExpirationInfo, error) {
366 handler, ok := rm.cas[name]
367 if !ok {
368 return nil, errors.Errorf("%s is not a known CA", name)
369 }
370
371
372 externallyManaged, err := rm.IsExternallyManaged(handler.FileName)
373 if err != nil {
374 return nil, err
375 }
376
377
378 ca, err := handler.readwriter.Read()
379 if err != nil {
380 return nil, err
381 }
382
383
384 return newExpirationInfo(name, ca, externallyManaged), nil
385 }
386
387
388 func (rm *Manager) IsExternallyManaged(caBaseName string) (bool, error) {
389 switch caBaseName {
390 case kubeadmconstants.CACertAndKeyBaseName:
391 externallyManaged, err := certsphase.UsingExternalCA(rm.cfg)
392 if err != nil {
393 return false, errors.Wrapf(err, "Error checking external CA condition for %s certificate authority", caBaseName)
394 }
395 return externallyManaged, nil
396 case kubeadmconstants.FrontProxyCACertAndKeyBaseName:
397 externallyManaged, err := certsphase.UsingExternalFrontProxyCA(rm.cfg)
398 if err != nil {
399 return false, errors.Wrapf(err, "Error checking external CA condition for %s certificate authority", caBaseName)
400 }
401 return externallyManaged, nil
402 case kubeadmconstants.EtcdCACertAndKeyBaseName:
403 externallyManaged, err := certsphase.UsingExternalEtcdCA(rm.cfg)
404 if err != nil {
405 return false, errors.Wrapf(err, "Error checking external CA condition for %s certificate authority", caBaseName)
406 }
407 return externallyManaged, nil
408 default:
409 return false, errors.Errorf("unknown certificate authority %s", caBaseName)
410 }
411 }
412
413 func certToConfig(cert *x509.Certificate) certutil.Config {
414 return certutil.Config{
415 CommonName: cert.Subject.CommonName,
416 Organization: cert.Subject.Organization,
417 AltNames: certutil.AltNames{
418 IPs: cert.IPAddresses,
419 DNSNames: cert.DNSNames,
420 },
421 Usages: cert.ExtKeyUsage,
422 }
423 }
424
425 func loadCertConfigMutators(certBaseName string) []certConfigMutatorFunc {
426 return nil
427 }
428
View as plain text