@@ -19,14 +19,16 @@ package alpha
19
19
import (
20
20
"fmt"
21
21
22
+ "github.com/pkg/errors"
22
23
"github.com/spf13/cobra"
24
+
25
+ kubeadmapi "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm"
23
26
kubeadmscheme "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm/scheme"
24
27
kubeadmapiv1beta2 "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm/v1beta2"
25
28
"k8s.io/kubernetes/cmd/kubeadm/app/cmd/options"
26
29
cmdutil "k8s.io/kubernetes/cmd/kubeadm/app/cmd/util"
27
30
"k8s.io/kubernetes/cmd/kubeadm/app/constants"
28
31
kubeadmconstants "k8s.io/kubernetes/cmd/kubeadm/app/constants"
29
- certsphase "k8s.io/kubernetes/cmd/kubeadm/app/phases/certs"
30
32
"k8s.io/kubernetes/cmd/kubeadm/app/phases/certs/renewal"
31
33
kubeadmutil "k8s.io/kubernetes/cmd/kubeadm/app/util"
32
34
configutil "k8s.io/kubernetes/cmd/kubeadm/app/util/config"
@@ -36,14 +38,16 @@ import (
36
38
37
39
var (
38
40
genericCertRenewLongDesc = normalizer .LongDesc (`
39
- Renew the %[1]s, and save them into %[2]s.cert and %[2]s.key files .
41
+ Renew the %s .
40
42
41
- Extra attributes such as SANs will be based on the existing certificates, there is no need to resupply them.
42
- ` )
43
- genericCertRenewEmbeddedLongDesc = normalizer .LongDesc (`
44
- Renew the certificate embedded in the kubeconfig file %s.
43
+ Renewals run unconditionally, regardless of certificate expiration date; extra attributes such as SANs will
44
+ be based on the existing file/certificates, there is no need to resupply them.
45
45
46
- Kubeconfig attributes and certificate extra attributes such as SANs will be based on the existing kubeconfig/certificates, there is no need to resupply them.
46
+ Renewal by default tries to use the certificate authority in the local PKI managed by kubeadm; as alternative
47
+ it is possible to use K8s certificate API for certificate renewal, or as a last option, to generate a CSR request.
48
+
49
+ After renewal, in order to make changes effective, is is required to restart control-plane components and
50
+ eventually re-distribute the renewed certificate in case the file is used elsewhere.
47
51
` )
48
52
49
53
allLongDesc = normalizer .LongDesc (`
@@ -78,17 +82,17 @@ func newCmdCertsRenewal() *cobra.Command {
78
82
return cmd
79
83
}
80
84
81
- type renewConfig struct {
85
+ type renewFlags struct {
82
86
cfgPath string
83
87
kubeconfigPath string
84
88
cfg kubeadmapiv1beta2.InitConfiguration
85
89
useAPI bool
86
- useCSR bool
90
+ csrOnly bool
87
91
csrPath string
88
92
}
89
93
90
94
func getRenewSubCommands (kdir string ) []* cobra.Command {
91
- cfg := & renewConfig {
95
+ flags := & renewFlags {
92
96
cfg : kubeadmapiv1beta2.InitConfiguration {
93
97
ClusterConfiguration : kubeadmapiv1beta2.ClusterConfiguration {
94
98
// Setting kubernetes version to a default value in order to allow a not necessary internet lookup
@@ -97,45 +101,28 @@ func getRenewSubCommands(kdir string) []*cobra.Command {
97
101
},
98
102
}
99
103
// Default values for the cobra help text
100
- kubeadmscheme .Scheme .Default (& cfg .cfg )
104
+ kubeadmscheme .Scheme .Default (& flags .cfg )
101
105
102
- certTree , err := certsphase .GetDefaultCertList ().AsMap ().CertTree ()
106
+ // Get a renewal manager for a generic Cluster configuration, that is used only for getting
107
+ // the list of certificates for building subcommands
108
+ rm , err := renewal .NewManager (& kubeadmapi.ClusterConfiguration {}, "" )
103
109
kubeadmutil .CheckErr (err )
104
110
105
111
cmdList := []* cobra.Command {}
106
112
funcList := []func (){}
107
113
108
- for caCert , certs := range certTree {
109
- // Don't offer to renew CAs; would cause serious consequences
110
- for _ , cert := range certs {
111
- // get the cobra.Command skeleton for this command
112
- cmd := generateCertRenewalCommand (cert , cfg )
113
- // get the implementation of renewing this certificate
114
- renewalFunc := func (cert * certsphase.KubeadmCert , caCert * certsphase.KubeadmCert ) func () {
115
- return func () { renewCert (cert , caCert , cfg ) }
116
- }(cert , caCert )
117
- // install the implementation into the command
118
- cmd .Run = func (* cobra.Command , []string ) { renewalFunc () }
119
- cmdList = append (cmdList , cmd )
120
- // Collect renewal functions for `renew all`
121
- funcList = append (funcList , renewalFunc )
122
- }
123
- }
124
-
125
- kubeconfigs := []string {
126
- kubeadmconstants .AdminKubeConfigFileName ,
127
- kubeadmconstants .ControllerManagerKubeConfigFileName ,
128
- kubeadmconstants .SchedulerKubeConfigFileName ,
129
- //NB. we are escluding KubeletKubeConfig from renewal because management of this certificate is delegated to kubelet
130
- }
131
-
132
- for _ , k := range kubeconfigs {
114
+ for _ , handler := range rm .Certificates () {
133
115
// get the cobra.Command skeleton for this command
134
- cmd := generateEmbeddedCertRenewalCommand (k , cfg )
116
+ cmd := & cobra.Command {
117
+ Use : handler .Name ,
118
+ Short : fmt .Sprintf ("Renew the %s" , handler .LongName ),
119
+ Long : fmt .Sprintf (genericCertRenewLongDesc , handler .LongName ),
120
+ }
121
+ addFlags (cmd , flags )
135
122
// get the implementation of renewing this certificate
136
- renewalFunc := func (kdir , k string ) func () {
137
- return func () { renewEmbeddedCert ( kdir , k , cfg ) }
138
- }(kdir , k )
123
+ renewalFunc := func (handler * renewal. CertificateRenewHandler ) func () {
124
+ return func () { renewCert ( flags , kdir , handler ) }
125
+ }(handler )
139
126
// install the implementation into the command
140
127
cmd .Run = func (* cobra.Command , []string ) { renewalFunc () }
141
128
cmdList = append (cmdList , cmd )
@@ -153,134 +140,60 @@ func getRenewSubCommands(kdir string) []*cobra.Command {
153
140
}
154
141
},
155
142
}
156
- addFlags (allCmd , cfg )
143
+ addFlags (allCmd , flags )
157
144
158
145
cmdList = append (cmdList , allCmd )
159
146
return cmdList
160
147
}
161
148
162
- func addFlags (cmd * cobra.Command , cfg * renewConfig ) {
163
- options .AddConfigFlag (cmd .Flags (), & cfg .cfgPath )
164
- options .AddCertificateDirFlag (cmd .Flags (), & cfg .cfg .CertificatesDir )
165
- options .AddKubeConfigFlag (cmd .Flags (), & cfg .kubeconfigPath )
166
- options .AddCSRFlag (cmd .Flags (), & cfg . useCSR )
167
- options .AddCSRDirFlag (cmd .Flags (), & cfg .csrPath )
168
- cmd .Flags ().BoolVar (& cfg .useAPI , "use-api" , cfg .useAPI , "Use the Kubernetes certificate API to renew certificates" )
149
+ func addFlags (cmd * cobra.Command , flags * renewFlags ) {
150
+ options .AddConfigFlag (cmd .Flags (), & flags .cfgPath )
151
+ options .AddCertificateDirFlag (cmd .Flags (), & flags .cfg .CertificatesDir )
152
+ options .AddKubeConfigFlag (cmd .Flags (), & flags .kubeconfigPath )
153
+ options .AddCSRFlag (cmd .Flags (), & flags . csrOnly )
154
+ options .AddCSRDirFlag (cmd .Flags (), & flags .csrPath )
155
+ cmd .Flags ().BoolVar (& flags .useAPI , "use-api" , flags .useAPI , "Use the Kubernetes certificate API to renew certificates" )
169
156
}
170
157
171
- func renewCert (cert * certsphase. KubeadmCert , caCert * certsphase. KubeadmCert , cfg * renewConfig ) {
172
- internalcfg , err := configutil .LoadOrDefaultInitConfiguration (cfg .cfgPath , & cfg .cfg )
158
+ func renewCert (flags * renewFlags , kdir string , handler * renewal. CertificateRenewHandler ) {
159
+ internalcfg , err := configutil .LoadOrDefaultInitConfiguration (flags .cfgPath , & flags .cfg )
173
160
kubeadmutil .CheckErr (err )
174
161
175
- // if the renewal operation is set to generate only CSR request
176
- if cfg .useCSR {
177
- // trigger CSR generation in the csrPath, or if this one is missing, in the CertificateDir
178
- path := cfg .csrPath
179
- if path == "" {
180
- path = cfg .cfg .CertificatesDir
181
- }
182
- err := certsphase .CreateCSR (cert , internalcfg , path )
183
- kubeadmutil .CheckErr (err )
184
- return
185
- }
186
-
187
- // otherwise, the renewal operation has to actually renew a certificate
188
-
189
- var externalCA bool
190
- switch caCert .BaseName {
191
- case kubeadmconstants .CACertAndKeyBaseName :
192
- // Check if an external CA is provided by the user (when the CA Cert is present but the CA Key is not)
193
- externalCA , _ = certsphase .UsingExternalCA (& internalcfg .ClusterConfiguration )
194
- case kubeadmconstants .FrontProxyCACertAndKeyBaseName :
195
- // Check if an external Front-Proxy CA is provided by the user (when the Front-Proxy CA Cert is present but the Front-Proxy CA Key is not)
196
- externalCA , _ = certsphase .UsingExternalFrontProxyCA (& internalcfg .ClusterConfiguration )
197
- default :
198
- externalCA = false
199
- }
200
-
201
- if ! externalCA {
202
- renewer , err := getRenewer (cfg , caCert .BaseName )
203
- kubeadmutil .CheckErr (err )
204
-
205
- err = renewal .RenewExistingCert (internalcfg .CertificatesDir , cert .BaseName , renewer )
206
- kubeadmutil .CheckErr (err )
207
-
208
- fmt .Printf ("Certificate %s renewed\n " , cert .Name )
209
- return
210
- }
211
-
212
- fmt .Printf ("Detected external %s, certificate %s can't be renewed\n " , cert .CAName , cert .Name )
213
- }
214
-
215
- func renewEmbeddedCert (kdir , k string , cfg * renewConfig ) {
216
- internalcfg , err := configutil .LoadOrDefaultInitConfiguration (cfg .cfgPath , & cfg .cfg )
162
+ // Get a renewal manager for the given cluster configuration
163
+ rm , err := renewal .NewManager (& internalcfg .ClusterConfiguration , kdir )
217
164
kubeadmutil .CheckErr (err )
218
165
219
- // if the renewal operation is set to generate only CSR request
220
- if cfg .useCSR {
221
- // trigger CSR generation in the csrPath, or if this one is missing, in the CertificateDir
222
- path := cfg .csrPath
223
- if path == "" {
224
- path = cfg .cfg .CertificatesDir
166
+ // if the renewal operation is set to generate CSR request only
167
+ if flags .csrOnly {
168
+ // checks a path for storing CSR request is given
169
+ if flags .csrPath == "" {
170
+ kubeadmutil .CheckErr (errors .New ("please provide a path where CSR request should be stored" ))
225
171
}
226
- err := certsphase . CreateCSR ( nil , internalcfg , path )
172
+ err := rm . CreateRenewCSR ( handler . Name , flags . csrPath )
227
173
kubeadmutil .CheckErr (err )
228
174
return
229
175
}
230
176
231
177
// otherwise, the renewal operation has to actually renew a certificate
232
178
233
- // Check if an external CA is provided by the user (when the CA Cert is present but the CA Key is not)
234
- externalCA , _ := certsphase . UsingExternalCA ( & internalcfg . ClusterConfiguration )
235
-
236
- if ! externalCA {
237
- renewer , err := getRenewer ( cfg , certsphase . KubeadmCertRootCA . BaseName )
179
+ // renew the certificate using the requested renew method
180
+ if flags . useAPI {
181
+ // renew using K8s certificate API
182
+ kubeConfigPath := cmdutil . GetKubeConfigPath ( flags . kubeconfigPath )
183
+ client , err := kubeconfigutil . ClientSetFromFile ( kubeConfigPath )
238
184
kubeadmutil .CheckErr (err )
239
185
240
- err = renewal . RenewEmbeddedClientCert ( kdir , k , renewer )
186
+ err = rm . RenewUsingCSRAPI ( handler . Name , client )
241
187
kubeadmutil .CheckErr (err )
242
-
243
- fmt .Printf ("Certificate embedded in %s renewed\n " , k )
244
- return
245
- }
246
-
247
- fmt .Printf ("Detected external CA, certificate embedded in %s can't be renewed\n " , k )
248
- }
249
-
250
- func generateCertRenewalCommand (cert * certsphase.KubeadmCert , cfg * renewConfig ) * cobra.Command {
251
- cmd := & cobra.Command {
252
- Use : cert .Name ,
253
- Short : fmt .Sprintf ("Renew the %s" , cert .LongName ),
254
- Long : fmt .Sprintf (genericCertRenewLongDesc , cert .LongName , cert .BaseName ),
255
- }
256
- addFlags (cmd , cfg )
257
- return cmd
258
- }
259
-
260
- func generateEmbeddedCertRenewalCommand (k string , cfg * renewConfig ) * cobra.Command {
261
- cmd := & cobra.Command {
262
- Use : k ,
263
- Short : fmt .Sprintf ("Renew the certificate embedded in %s" , k ),
264
- Long : fmt .Sprintf (genericCertRenewEmbeddedLongDesc , k ),
265
- }
266
- addFlags (cmd , cfg )
267
- return cmd
268
- }
269
-
270
- func getRenewer (cfg * renewConfig , caCertBaseName string ) (renewal.Interface , error ) {
271
- if cfg .useAPI {
272
- kubeConfigPath := cmdutil .GetKubeConfigPath (cfg .kubeconfigPath )
273
- client , err := kubeconfigutil .ClientSetFromFile (kubeConfigPath )
274
- if err != nil {
275
- return nil , err
188
+ } else {
189
+ // renew using local certificate authorities.
190
+ // this operation can't complete in case the certificate key is not provided (external CA)
191
+ renewed , err := rm .RenewUsingLocalCA (handler .Name )
192
+ kubeadmutil .CheckErr (err )
193
+ if ! renewed {
194
+ fmt .Printf ("Detected external %s, %s can't be renewed\n " , handler .CABaseName , handler .LongName )
195
+ return
276
196
}
277
- return renewal .NewCertsAPIRenawal (client ), nil
278
197
}
279
-
280
- caCert , caKey , err := certsphase .LoadCertificateAuthority (cfg .cfg .CertificatesDir , caCertBaseName )
281
- if err != nil {
282
- return nil , err
283
- }
284
-
285
- return renewal .NewFileRenewal (caCert , caKey ), nil
198
+ fmt .Printf ("%s renewed\n " , handler .LongName )
286
199
}
0 commit comments