@@ -26,6 +26,7 @@ import (
26
26
"path/filepath"
27
27
28
28
"github.com/pkg/errors"
29
+
29
30
"k8s.io/client-go/tools/clientcmd"
30
31
clientcmdapi "k8s.io/client-go/tools/clientcmd/api"
31
32
certutil "k8s.io/client-go/util/cert"
@@ -34,9 +35,13 @@ import (
34
35
kubeadmapi "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm"
35
36
kubeadmconstants "k8s.io/kubernetes/cmd/kubeadm/app/constants"
36
37
kubeadmutil "k8s.io/kubernetes/cmd/kubeadm/app/util"
38
+ kubeconfigutil "k8s.io/kubernetes/cmd/kubeadm/app/util/kubeconfig"
37
39
pkiutil "k8s.io/kubernetes/cmd/kubeadm/app/util/pkiutil"
40
+ )
38
41
39
- kubeconfigutil "k8s.io/kubernetes/cmd/kubeadm/app/util/kubeconfig"
42
+ const (
43
+ errInvalid = "invalid argument"
44
+ errExist = "file already exists"
40
45
)
41
46
42
47
// clientCertAuth struct holds info required to build a client certificate to provide authentication info in a kubeconfig object
@@ -103,7 +108,7 @@ func createKubeConfigFiles(outDir string, cfg *kubeadmapi.InitConfiguration, kub
103
108
return err
104
109
}
105
110
106
- // writes the kubeconfig to disk if it not exists
111
+ // writes the kubeconfig to disk if it does not exist
107
112
if err = createKubeConfigFileIfNotExists (outDir , kubeConfigFileName , config ); err != nil {
108
113
return err
109
114
}
@@ -113,57 +118,21 @@ func createKubeConfigFiles(outDir string, cfg *kubeadmapi.InitConfiguration, kub
113
118
}
114
119
115
120
// getKubeConfigSpecs returns all KubeConfigSpecs actualized to the context of the current InitConfiguration
116
- // NB. this methods holds the information about how kubeadm creates kubeconfig files.
121
+ // NB. this method holds the information about how kubeadm creates kubeconfig files.
117
122
func getKubeConfigSpecs (cfg * kubeadmapi.InitConfiguration ) (map [string ]* kubeConfigSpec , error ) {
118
-
119
123
caCert , caKey , err := pkiutil .TryLoadCertAndKeyFromDisk (cfg .CertificatesDir , kubeadmconstants .CACertAndKeyBaseName )
120
124
if err != nil {
121
125
return nil , errors .Wrap (err , "couldn't create a kubeconfig; the CA files couldn't be loaded" )
122
126
}
123
-
124
- controlPlaneEndpoint , err := kubeadmutil .GetControlPlaneEndpoint (cfg .ControlPlaneEndpoint , & cfg .LocalAPIEndpoint )
127
+ configs , err := getKubeConfigSpecsBase (cfg )
125
128
if err != nil {
126
129
return nil , err
127
130
}
128
-
129
- var kubeConfigSpec = map [string ]* kubeConfigSpec {
130
- kubeadmconstants .AdminKubeConfigFileName : {
131
- CACert : caCert ,
132
- APIServer : controlPlaneEndpoint ,
133
- ClientName : "kubernetes-admin" ,
134
- ClientCertAuth : & clientCertAuth {
135
- CAKey : caKey ,
136
- Organizations : []string {kubeadmconstants .SystemPrivilegedGroup },
137
- },
138
- },
139
- kubeadmconstants .KubeletKubeConfigFileName : {
140
- CACert : caCert ,
141
- APIServer : controlPlaneEndpoint ,
142
- ClientName : fmt .Sprintf ("%s%s" , kubeadmconstants .NodesUserPrefix , cfg .NodeRegistration .Name ),
143
- ClientCertAuth : & clientCertAuth {
144
- CAKey : caKey ,
145
- Organizations : []string {kubeadmconstants .NodesGroup },
146
- },
147
- },
148
- kubeadmconstants .ControllerManagerKubeConfigFileName : {
149
- CACert : caCert ,
150
- APIServer : controlPlaneEndpoint ,
151
- ClientName : kubeadmconstants .ControllerManagerUser ,
152
- ClientCertAuth : & clientCertAuth {
153
- CAKey : caKey ,
154
- },
155
- },
156
- kubeadmconstants .SchedulerKubeConfigFileName : {
157
- CACert : caCert ,
158
- APIServer : controlPlaneEndpoint ,
159
- ClientName : kubeadmconstants .SchedulerUser ,
160
- ClientCertAuth : & clientCertAuth {
161
- CAKey : caKey ,
162
- },
163
- },
131
+ for _ , spec := range configs {
132
+ spec .CACert = caCert
133
+ spec .ClientCertAuth .CAKey = caKey
164
134
}
165
-
166
- return kubeConfigSpec , nil
135
+ return configs , nil
167
136
}
168
137
169
138
// buildKubeConfigFromSpec creates a kubeconfig object for the given kubeConfigSpec
@@ -182,13 +151,8 @@ func buildKubeConfigFromSpec(spec *kubeConfigSpec, clustername string) (*clientc
182
151
}
183
152
184
153
// otherwise, create a client certs
185
- clientCertConfig := pkiutil.CertConfig {
186
- Config : certutil.Config {
187
- CommonName : spec .ClientName ,
188
- Organization : spec .ClientCertAuth .Organizations ,
189
- Usages : []x509.ExtKeyUsage {x509 .ExtKeyUsageClientAuth },
190
- },
191
- }
154
+ clientCertConfig := newClientCertConfigFromKubeConfigSpec (spec )
155
+
192
156
clientCert , clientKey , err := pkiutil .NewCertAndKey (spec .CACert , spec .ClientCertAuth .CAKey , & clientCertConfig )
193
157
if err != nil {
194
158
return nil , errors .Wrapf (err , "failure while creating %s client certificate" , spec .ClientName )
@@ -209,6 +173,16 @@ func buildKubeConfigFromSpec(spec *kubeConfigSpec, clustername string) (*clientc
209
173
), nil
210
174
}
211
175
176
+ func newClientCertConfigFromKubeConfigSpec (spec * kubeConfigSpec ) pkiutil.CertConfig {
177
+ return pkiutil.CertConfig {
178
+ Config : certutil.Config {
179
+ CommonName : spec .ClientName ,
180
+ Organization : spec .ClientCertAuth .Organizations ,
181
+ Usages : []x509.ExtKeyUsage {x509 .ExtKeyUsageClientAuth },
182
+ },
183
+ }
184
+ }
185
+
212
186
// validateKubeConfig check if the kubeconfig file exist and has the expected CA and server URL
213
187
func validateKubeConfig (outDir , filename string , config * clientcmdapi.Config ) error {
214
188
kubeConfigFilePath := filepath .Join (outDir , filename )
@@ -386,3 +360,115 @@ func ValidateKubeconfigsForExternalCA(outDir string, cfg *kubeadmapi.InitConfigu
386
360
}
387
361
return nil
388
362
}
363
+
364
+ func getKubeConfigSpecsBase (cfg * kubeadmapi.InitConfiguration ) (map [string ]* kubeConfigSpec , error ) {
365
+ apiServer , err := kubeadmutil .GetControlPlaneEndpoint (cfg .ControlPlaneEndpoint , & cfg .LocalAPIEndpoint )
366
+ if err != nil {
367
+ return nil , err
368
+ }
369
+ return map [string ]* kubeConfigSpec {
370
+ kubeadmconstants .AdminKubeConfigFileName : {
371
+ APIServer : apiServer ,
372
+ ClientName : "kubernetes-admin" ,
373
+ ClientCertAuth : & clientCertAuth {
374
+ Organizations : []string {kubeadmconstants .SystemPrivilegedGroup },
375
+ },
376
+ },
377
+ kubeadmconstants .KubeletKubeConfigFileName : {
378
+ APIServer : apiServer ,
379
+ ClientName : fmt .Sprintf ("%s%s" , kubeadmconstants .NodesUserPrefix , cfg .NodeRegistration .Name ),
380
+ ClientCertAuth : & clientCertAuth {
381
+ Organizations : []string {kubeadmconstants .NodesGroup },
382
+ },
383
+ },
384
+ kubeadmconstants .ControllerManagerKubeConfigFileName : {
385
+ APIServer : apiServer ,
386
+ ClientName : kubeadmconstants .ControllerManagerUser ,
387
+ ClientCertAuth : & clientCertAuth {},
388
+ },
389
+ kubeadmconstants .SchedulerKubeConfigFileName : {
390
+ APIServer : apiServer ,
391
+ ClientName : kubeadmconstants .SchedulerUser ,
392
+ ClientCertAuth : & clientCertAuth {},
393
+ },
394
+ }, nil
395
+ }
396
+
397
+ func createKubeConfigAndCSR (kubeConfigDir string , kubeadmConfig * kubeadmapi.InitConfiguration , name string , spec * kubeConfigSpec ) error {
398
+ if kubeConfigDir == "" {
399
+ return errors .Errorf ("%s: kubeConfigDir was empty" , errInvalid )
400
+ }
401
+ if kubeadmConfig == nil {
402
+ return errors .Errorf ("%s: kubeadmConfig was nil" , errInvalid )
403
+ }
404
+ if name == "" {
405
+ return errors .Errorf ("%s: name was empty" , errInvalid )
406
+ }
407
+ if spec == nil {
408
+ return errors .Errorf ("%s: spec was nil" , errInvalid )
409
+ }
410
+ kubeConfigPath := filepath .Join (kubeConfigDir , name )
411
+ if _ , err := os .Stat (kubeConfigPath ); err == nil {
412
+ return errors .Errorf ("%s: kube config: %s" , errExist , kubeConfigPath )
413
+ } else if ! os .IsNotExist (err ) {
414
+ return errors .Wrapf (err , "unexpected error while checking if file exists: %s" , kubeConfigPath )
415
+ }
416
+ if pkiutil .CSROrKeyExist (kubeConfigDir , name ) {
417
+ return errors .Errorf ("%s: csr: %s" , errExist , kubeConfigPath )
418
+ }
419
+
420
+ clientCertConfig := newClientCertConfigFromKubeConfigSpec (spec )
421
+
422
+ clientKey , err := pkiutil .NewPrivateKey (clientCertConfig .PublicKeyAlgorithm )
423
+ if err != nil {
424
+ return err
425
+ }
426
+ clientCSR , err := pkiutil .NewCSR (clientCertConfig , clientKey )
427
+ if err != nil {
428
+ return err
429
+ }
430
+
431
+ encodedClientKey , err := keyutil .MarshalPrivateKeyToPEM (clientKey )
432
+ if err != nil {
433
+ return err
434
+ }
435
+
436
+ var (
437
+ emptyCACert []byte
438
+ emptyClientCert []byte
439
+ )
440
+
441
+ // create a kubeconfig with the client certs
442
+ config := kubeconfigutil .CreateWithCerts (
443
+ spec .APIServer ,
444
+ kubeadmConfig .ClusterName ,
445
+ spec .ClientName ,
446
+ emptyCACert ,
447
+ encodedClientKey ,
448
+ emptyClientCert ,
449
+ )
450
+
451
+ if err := kubeconfigutil .WriteToDisk (kubeConfigPath , config ); err != nil {
452
+ return err
453
+ }
454
+ // Write CSR to disk
455
+ if err := pkiutil .WriteCSR (kubeConfigDir , name , clientCSR ); err != nil {
456
+ return err
457
+ }
458
+ return nil
459
+ }
460
+
461
+ // CreateDefaultKubeConfigsAndCSRFiles is used in ExternalCA mode to create
462
+ // kubeconfig files and adjacent CSR files.
463
+ func CreateDefaultKubeConfigsAndCSRFiles (kubeConfigDir string , kubeadmConfig * kubeadmapi.InitConfiguration ) error {
464
+ kubeConfigs , err := getKubeConfigSpecsBase (kubeadmConfig )
465
+ if err != nil {
466
+ return err
467
+ }
468
+ for name , spec := range kubeConfigs {
469
+ if err := createKubeConfigAndCSR (kubeConfigDir , kubeadmConfig , name , spec ); err != nil {
470
+ return err
471
+ }
472
+ }
473
+ return nil
474
+ }
0 commit comments