1
16
17 package certs
18
19 import (
20 "crypto"
21 "crypto/x509"
22 "fmt"
23 "io"
24 "path/filepath"
25
26 "github.com/pkg/errors"
27
28 certutil "k8s.io/client-go/util/cert"
29 "k8s.io/klog/v2"
30
31 kubeadmapi "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm"
32 kubeadmconstants "k8s.io/kubernetes/cmd/kubeadm/app/constants"
33 "k8s.io/kubernetes/cmd/kubeadm/app/util/pkiutil"
34 )
35
36 const (
37 errInvalid = "invalid argument"
38 errExist = "file already exists"
39 )
40
41 type configMutatorsFunc func(*kubeadmapi.InitConfiguration, *pkiutil.CertConfig) error
42
43
44 type KubeadmCert struct {
45 Name string
46 LongName string
47 BaseName string
48 CAName string
49
50
51 configMutators []configMutatorsFunc
52 config pkiutil.CertConfig
53 }
54
55
56 func (k *KubeadmCert) GetConfig(ic *kubeadmapi.InitConfiguration) (*pkiutil.CertConfig, error) {
57 for _, f := range k.configMutators {
58 if err := f(ic, &k.config); err != nil {
59 return nil, err
60 }
61 }
62
63 k.config.EncryptionAlgorithm = ic.ClusterConfiguration.EncryptionAlgorithmType()
64 return &k.config, nil
65 }
66
67
68 func (k *KubeadmCert) CreateFromCA(ic *kubeadmapi.InitConfiguration, caCert *x509.Certificate, caKey crypto.Signer) error {
69 cfg, err := k.GetConfig(ic)
70 if err != nil {
71 return errors.Wrapf(err, "couldn't create %q certificate", k.Name)
72 }
73 cert, key, err := pkiutil.NewCertAndKey(caCert, caKey, cfg)
74 if err != nil {
75 return err
76 }
77 err = writeCertificateFilesIfNotExist(
78 ic.CertificatesDir,
79 k.BaseName,
80 caCert,
81 cert,
82 key,
83 cfg,
84 )
85
86 if err != nil {
87 return errors.Wrapf(err, "failed to write or validate certificate %q", k.Name)
88 }
89
90 return nil
91 }
92
93
94 func (k *KubeadmCert) CreateAsCA(ic *kubeadmapi.InitConfiguration) (*x509.Certificate, crypto.Signer, error) {
95 cfg, err := k.GetConfig(ic)
96 if err != nil {
97 return nil, nil, errors.Wrapf(err, "couldn't get configuration for %q CA certificate", k.Name)
98 }
99 caCert, caKey, err := pkiutil.NewCertificateAuthority(cfg)
100 if err != nil {
101 return nil, nil, errors.Wrapf(err, "couldn't generate %q CA certificate", k.Name)
102 }
103
104 err = writeCertificateAuthorityFilesIfNotExist(
105 ic.CertificatesDir,
106 k.BaseName,
107 caCert,
108 caKey,
109 )
110 if err != nil {
111 return nil, nil, errors.Wrapf(err, "couldn't write out %q CA certificate", k.Name)
112 }
113
114 return caCert, caKey, nil
115 }
116
117
118 type CertificateTree map[*KubeadmCert]Certificates
119
120
121 func (t CertificateTree) CreateTree(ic *kubeadmapi.InitConfiguration) error {
122 for ca, leaves := range t {
123 cfg, err := ca.GetConfig(ic)
124 if err != nil {
125 return err
126 }
127
128 var caKey crypto.Signer
129
130 caCert, err := pkiutil.TryLoadCertFromDisk(ic.CertificatesDir, ca.BaseName)
131 if err == nil {
132
133 CheckCertificatePeriodValidity(ca.BaseName, caCert)
134
135
136 if !caCert.IsCA {
137 return errors.Errorf("certificate %q is not a CA", ca.Name)
138 }
139
140 caKey, err = pkiutil.TryLoadKeyFromDisk(ic.CertificatesDir, ca.BaseName)
141 if err != nil {
142
143 for _, leaf := range leaves {
144 cl := certKeyLocation{
145 pkiDir: ic.CertificatesDir,
146 baseName: leaf.BaseName,
147 uxName: leaf.Name,
148 }
149 if err := validateSignedCertWithCA(cl, caCert); err != nil {
150 return errors.Wrapf(err, "could not load expected certificate %q or validate the existence of key %q for it", leaf.Name, ca.Name)
151 }
152 }
153 continue
154 }
155
156 klog.V(1).Infof("[certs] Using the existing CA certificate %q and key %q\n", filepath.Join(ic.CertificatesDir, fmt.Sprintf("%s.crt", ca.BaseName)), filepath.Join(ic.CertificatesDir, fmt.Sprintf("%s.key", ca.BaseName)))
157 } else {
158
159 caCert, caKey, err = pkiutil.NewCertificateAuthority(cfg)
160 if err != nil {
161 return err
162 }
163
164 err = writeCertificateAuthorityFilesIfNotExist(
165 ic.CertificatesDir,
166 ca.BaseName,
167 caCert,
168 caKey,
169 )
170 if err != nil {
171 return err
172 }
173 }
174
175 for _, leaf := range leaves {
176 if err := leaf.CreateFromCA(ic, caCert, caKey); err != nil {
177 return err
178 }
179 }
180 }
181 return nil
182 }
183
184
185 type CertificateMap map[string]*KubeadmCert
186
187
188 func (m CertificateMap) CertTree() (CertificateTree, error) {
189 caMap := make(CertificateTree)
190
191 for _, cert := range m {
192 if cert.CAName == "" {
193 if _, ok := caMap[cert]; !ok {
194 caMap[cert] = []*KubeadmCert{}
195 }
196 } else {
197 ca, ok := m[cert.CAName]
198 if !ok {
199 return nil, errors.Errorf("certificate %q references unknown CA %q", cert.Name, cert.CAName)
200 }
201 caMap[ca] = append(caMap[ca], cert)
202 }
203 }
204
205 return caMap, nil
206 }
207
208
209 type Certificates []*KubeadmCert
210
211
212 func (c Certificates) AsMap() CertificateMap {
213 certMap := make(map[string]*KubeadmCert)
214 for _, cert := range c {
215 certMap[cert.Name] = cert
216 }
217
218 return certMap
219 }
220
221
222 func GetDefaultCertList() Certificates {
223 return Certificates{
224 KubeadmCertRootCA(),
225 KubeadmCertAPIServer(),
226 KubeadmCertKubeletClient(),
227
228 KubeadmCertFrontProxyCA(),
229 KubeadmCertFrontProxyClient(),
230
231 KubeadmCertEtcdCA(),
232 KubeadmCertEtcdServer(),
233 KubeadmCertEtcdPeer(),
234 KubeadmCertEtcdHealthcheck(),
235 KubeadmCertEtcdAPIClient(),
236 }
237 }
238
239
240 func GetCertsWithoutEtcd() Certificates {
241 return Certificates{
242 KubeadmCertRootCA(),
243 KubeadmCertAPIServer(),
244 KubeadmCertKubeletClient(),
245
246 KubeadmCertFrontProxyCA(),
247 KubeadmCertFrontProxyClient(),
248 }
249 }
250
251
252 func KubeadmCertRootCA() *KubeadmCert {
253 return &KubeadmCert{
254 Name: "ca",
255 LongName: "self-signed Kubernetes CA to provision identities for other Kubernetes components",
256 BaseName: kubeadmconstants.CACertAndKeyBaseName,
257 config: pkiutil.CertConfig{
258 Config: certutil.Config{
259 CommonName: "kubernetes",
260 },
261 },
262 }
263 }
264
265
266 func KubeadmCertAPIServer() *KubeadmCert {
267 return &KubeadmCert{
268 Name: "apiserver",
269 LongName: "certificate for serving the Kubernetes API",
270 BaseName: kubeadmconstants.APIServerCertAndKeyBaseName,
271 CAName: "ca",
272 config: pkiutil.CertConfig{
273 Config: certutil.Config{
274 CommonName: kubeadmconstants.APIServerCertCommonName,
275 Usages: []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth},
276 },
277 },
278 configMutators: []configMutatorsFunc{
279 makeAltNamesMutator(pkiutil.GetAPIServerAltNames),
280 },
281 }
282 }
283
284
285 func KubeadmCertKubeletClient() *KubeadmCert {
286 return &KubeadmCert{
287 Name: "apiserver-kubelet-client",
288 LongName: "certificate for the API server to connect to kubelet",
289 BaseName: kubeadmconstants.APIServerKubeletClientCertAndKeyBaseName,
290 CAName: "ca",
291 config: pkiutil.CertConfig{
292 Config: certutil.Config{
293 CommonName: kubeadmconstants.APIServerKubeletClientCertCommonName,
294 Organization: []string{kubeadmconstants.ClusterAdminsGroupAndClusterRoleBinding},
295 Usages: []x509.ExtKeyUsage{x509.ExtKeyUsageClientAuth},
296 },
297 },
298 }
299 }
300
301
302 func KubeadmCertFrontProxyCA() *KubeadmCert {
303 return &KubeadmCert{
304 Name: "front-proxy-ca",
305 LongName: "self-signed CA to provision identities for front proxy",
306 BaseName: kubeadmconstants.FrontProxyCACertAndKeyBaseName,
307 config: pkiutil.CertConfig{
308 Config: certutil.Config{
309 CommonName: "front-proxy-ca",
310 },
311 },
312 }
313 }
314
315
316 func KubeadmCertFrontProxyClient() *KubeadmCert {
317 return &KubeadmCert{
318 Name: "front-proxy-client",
319 BaseName: kubeadmconstants.FrontProxyClientCertAndKeyBaseName,
320 LongName: "certificate for the front proxy client",
321 CAName: "front-proxy-ca",
322 config: pkiutil.CertConfig{
323 Config: certutil.Config{
324 CommonName: kubeadmconstants.FrontProxyClientCertCommonName,
325 Usages: []x509.ExtKeyUsage{x509.ExtKeyUsageClientAuth},
326 },
327 },
328 }
329 }
330
331
332 func KubeadmCertEtcdCA() *KubeadmCert {
333 return &KubeadmCert{
334 Name: "etcd-ca",
335 LongName: "self-signed CA to provision identities for etcd",
336 BaseName: kubeadmconstants.EtcdCACertAndKeyBaseName,
337 config: pkiutil.CertConfig{
338 Config: certutil.Config{
339 CommonName: "etcd-ca",
340 },
341 },
342 }
343 }
344
345
346 func KubeadmCertEtcdServer() *KubeadmCert {
347 return &KubeadmCert{
348 Name: "etcd-server",
349 LongName: "certificate for serving etcd",
350 BaseName: kubeadmconstants.EtcdServerCertAndKeyBaseName,
351 CAName: "etcd-ca",
352 config: pkiutil.CertConfig{
353 Config: certutil.Config{
354
355
356
357
358 Usages: []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth, x509.ExtKeyUsageClientAuth},
359 },
360 },
361 configMutators: []configMutatorsFunc{
362 makeAltNamesMutator(pkiutil.GetEtcdAltNames),
363 setCommonNameToNodeName(),
364 },
365 }
366 }
367
368
369 func KubeadmCertEtcdPeer() *KubeadmCert {
370 return &KubeadmCert{
371 Name: "etcd-peer",
372 LongName: "certificate for etcd nodes to communicate with each other",
373 BaseName: kubeadmconstants.EtcdPeerCertAndKeyBaseName,
374 CAName: "etcd-ca",
375 config: pkiutil.CertConfig{
376 Config: certutil.Config{
377 Usages: []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth, x509.ExtKeyUsageClientAuth},
378 },
379 },
380 configMutators: []configMutatorsFunc{
381 makeAltNamesMutator(pkiutil.GetEtcdPeerAltNames),
382 setCommonNameToNodeName(),
383 },
384 }
385 }
386
387
388 func KubeadmCertEtcdHealthcheck() *KubeadmCert {
389 return &KubeadmCert{
390 Name: "etcd-healthcheck-client",
391 LongName: "certificate for liveness probes to healthcheck etcd",
392 BaseName: kubeadmconstants.EtcdHealthcheckClientCertAndKeyBaseName,
393 CAName: "etcd-ca",
394 config: pkiutil.CertConfig{
395 Config: certutil.Config{
396 CommonName: kubeadmconstants.EtcdHealthcheckClientCertCommonName,
397 Usages: []x509.ExtKeyUsage{x509.ExtKeyUsageClientAuth},
398 },
399 },
400 }
401 }
402
403
404 func KubeadmCertEtcdAPIClient() *KubeadmCert {
405 return &KubeadmCert{
406 Name: "apiserver-etcd-client",
407 LongName: "certificate the apiserver uses to access etcd",
408 BaseName: kubeadmconstants.APIServerEtcdClientCertAndKeyBaseName,
409 CAName: "etcd-ca",
410 config: pkiutil.CertConfig{
411 Config: certutil.Config{
412 CommonName: kubeadmconstants.APIServerEtcdClientCertCommonName,
413 Usages: []x509.ExtKeyUsage{x509.ExtKeyUsageClientAuth},
414 },
415 },
416 }
417 }
418
419 func makeAltNamesMutator(f func(*kubeadmapi.InitConfiguration) (*certutil.AltNames, error)) configMutatorsFunc {
420 return func(mc *kubeadmapi.InitConfiguration, cc *pkiutil.CertConfig) error {
421 altNames, err := f(mc)
422 if err != nil {
423 return err
424 }
425 cc.AltNames = *altNames
426 return nil
427 }
428 }
429
430 func setCommonNameToNodeName() configMutatorsFunc {
431 return func(mc *kubeadmapi.InitConfiguration, cc *pkiutil.CertConfig) error {
432 cc.CommonName = mc.NodeRegistration.Name
433 return nil
434 }
435 }
436
437
438 func leafCertificates(c Certificates) (Certificates, error) {
439 certTree, err := c.AsMap().CertTree()
440 if err != nil {
441 return nil, err
442 }
443
444 var out Certificates
445 for _, leafCertificates := range certTree {
446 out = append(out, leafCertificates...)
447 }
448 return out, nil
449 }
450
451 func createKeyAndCSR(kubeadmConfig *kubeadmapi.InitConfiguration, cert *KubeadmCert) error {
452 if kubeadmConfig == nil {
453 return errors.Errorf("%s: kubeadmConfig was nil", errInvalid)
454 }
455 if cert == nil {
456 return errors.Errorf("%s: cert was nil", errInvalid)
457 }
458 certDir := kubeadmConfig.CertificatesDir
459 name := cert.BaseName
460 if pkiutil.CSROrKeyExist(certDir, name) {
461 return errors.Errorf("%s: key or CSR %s/%s", errExist, certDir, name)
462 }
463 cfg, err := cert.GetConfig(kubeadmConfig)
464 if err != nil {
465 return err
466 }
467 csr, key, err := pkiutil.NewCSRAndKey(cfg)
468 if err != nil {
469 return err
470 }
471 err = pkiutil.WriteKey(certDir, name, key)
472 if err != nil {
473 return err
474 }
475 return pkiutil.WriteCSR(certDir, name, csr)
476 }
477
478
479
480 func CreateDefaultKeysAndCSRFiles(out io.Writer, config *kubeadmapi.InitConfiguration) error {
481 certificates, err := leafCertificates(GetDefaultCertList())
482 if err != nil {
483 return err
484 }
485 if out != nil {
486 fmt.Fprintf(out, "generating keys and CSRs in %s\n", config.CertificatesDir)
487 }
488 for _, cert := range certificates {
489 if err := createKeyAndCSR(config, cert); err != nil {
490 return err
491 }
492 if out != nil {
493 fmt.Fprintf(out, " %s\n", cert.BaseName)
494 }
495 }
496 return nil
497 }
498
View as plain text