forked from kubernetes/kubernetes
-
Notifications
You must be signed in to change notification settings - Fork 0
/
bootstraptoken.go
358 lines (296 loc) · 14.2 KB
/
bootstraptoken.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
/*
Copyright 2017 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package phases
import (
"fmt"
"strings"
"github.com/spf13/cobra"
"github.com/spf13/pflag"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/util/sets"
clientset "k8s.io/client-go/kubernetes"
kubeadmapiext "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm/v1alpha1"
"k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm/validation"
cmdutil "k8s.io/kubernetes/cmd/kubeadm/app/cmd/util"
kubeadmconstants "k8s.io/kubernetes/cmd/kubeadm/app/constants"
"k8s.io/kubernetes/cmd/kubeadm/app/phases/bootstraptoken/clusterinfo"
"k8s.io/kubernetes/cmd/kubeadm/app/phases/bootstraptoken/node"
"k8s.io/kubernetes/cmd/kubeadm/app/phases/certs/pkiutil"
kubeadmutil "k8s.io/kubernetes/cmd/kubeadm/app/util"
configutil "k8s.io/kubernetes/cmd/kubeadm/app/util/config"
kubeconfigutil "k8s.io/kubernetes/cmd/kubeadm/app/util/kubeconfig"
"k8s.io/kubernetes/cmd/kubeadm/app/util/pubkeypin"
"k8s.io/kubernetes/pkg/api/legacyscheme"
bootstrapapi "k8s.io/kubernetes/pkg/bootstrap/api"
"k8s.io/kubernetes/pkg/util/normalizer"
)
var (
allTokenLongDesc = normalizer.LongDesc(`
Bootstrap tokens are used for establishing bidirectional trust between a node joining
the cluster and a the master node.
This command makes all the configurations required to make bootstrap tokens works
and then creates an initial token.
` + cmdutil.AlphaDisclaimer)
allTokenExamples = normalizer.Examples(`
# Makes all the bootstrap token configurations and creates an initial token, functionally
# equivalent to what generated by kubeadm init.
kubeadm alpha phase bootstrap-token all
`)
createTokenLongDesc = normalizer.LongDesc(`
Creates a bootstrap token. If no token value is given, kubeadm will generate a random token instead.
Alternatively, you can use kubeadm token.
` + cmdutil.AlphaDisclaimer)
clusterInfoLongDesc = fmt.Sprintf(normalizer.LongDesc(`
Uploads the %q ConfigMap in the %q namespace, populating it with cluster information extracted from the
given kubeconfig file. The ConfigMap is used for the node bootstrap process in its initial phases,
before the client trusts the API server.
See online documentation about Authenticating with Bootstrap Tokens for more details.
`+cmdutil.AlphaDisclaimer), bootstrapapi.ConfigMapClusterInfo, metav1.NamespacePublic)
nodePostCSRsLongDesc = normalizer.LongDesc(`
Configures RBAC rules to allow node bootstrap tokens to post a certificate signing request,
thus enabling nodes joining the cluster to request long term certificate credentials.
See online documentation about TLS bootstrapping for more details.
` + cmdutil.AlphaDisclaimer)
nodeAutoApproveLongDesc = normalizer.LongDesc(`
Configures RBAC rules to allow the csrapprover controller to automatically approve
certificate signing requests generated by nodes joining the cluster.
It configures also RBAC rules for certificates rotation (with auto approval of new certificates).
See online documentation about TLS bootstrapping for more details.
` + cmdutil.AlphaDisclaimer)
)
// NewCmdBootstrapToken returns the Cobra command for running the mark-master phase
func NewCmdBootstrapToken() *cobra.Command {
var kubeConfigFile string
cmd := &cobra.Command{
Use: "bootstrap-token",
Short: "Manage kubeadm-specific bootstrap token functions",
Long: cmdutil.MacroCommandLongDescription,
Aliases: []string{"bootstraptoken"},
}
cmd.PersistentFlags().StringVar(&kubeConfigFile, "kubeconfig", "/etc/kubernetes/admin.conf", "The KubeConfig file to use when talking to the cluster")
// Add subcommands
cmd.AddCommand(NewSubCmdBootstrapTokenAll(&kubeConfigFile))
cmd.AddCommand(NewSubCmdBootstrapToken(&kubeConfigFile))
cmd.AddCommand(NewSubCmdClusterInfo(&kubeConfigFile))
cmd.AddCommand(NewSubCmdNodeBootstrapToken(&kubeConfigFile))
return cmd
}
// NewSubCmdBootstrapTokenAll returns the Cobra command for running the token all sub-phase
func NewSubCmdBootstrapTokenAll(kubeConfigFile *string) *cobra.Command {
cfg := &kubeadmapiext.MasterConfiguration{
// KubernetesVersion is not used by bootstrap-token, but we set this explicitly to avoid
// the lookup of the version from the internet when executing ConfigFileAndDefaultsToInternalConfig
KubernetesVersion: "v1.9.0",
}
// Default values for the cobra help text
legacyscheme.Scheme.Default(cfg)
var cfgPath, description string
var usages, extraGroups []string
var skipTokenPrint bool
cmd := &cobra.Command{
Use: "all",
Short: "Makes all the bootstrap token configurations and creates an initial token",
Long: allTokenLongDesc,
Example: allTokenExamples,
Run: func(cmd *cobra.Command, args []string) {
err := validation.ValidateMixedArguments(cmd.Flags())
kubeadmutil.CheckErr(err)
client, err := kubeconfigutil.ClientSetFromFile(*kubeConfigFile)
kubeadmutil.CheckErr(err)
// Creates the bootstap token
err = createBootstrapToken(client, cfgPath, cfg, description, usages, extraGroups, skipTokenPrint)
kubeadmutil.CheckErr(err)
// Create the cluster-info ConfigMap or update if it already exists
err = clusterinfo.CreateBootstrapConfigMapIfNotExists(client, *kubeConfigFile)
kubeadmutil.CheckErr(err)
// Create the RBAC rules that expose the cluster-info ConfigMap properly
err = clusterinfo.CreateClusterInfoRBACRules(client)
kubeadmutil.CheckErr(err)
// Create RBAC rules that makes the bootstrap tokens able to post CSRs
err = node.AllowBootstrapTokensToPostCSRs(client)
kubeadmutil.CheckErr(err)
// Create RBAC rules that makes the bootstrap tokens able to get their CSRs approved automatically
err = node.AutoApproveNodeBootstrapTokens(client)
kubeadmutil.CheckErr(err)
// Create/update RBAC rules that makes the nodes to rotate certificates and get their CSRs approved automatically
err = node.AutoApproveNodeCertificateRotation(client)
kubeadmutil.CheckErr(err)
},
}
// Adds flags to the command
addBootstrapTokenFlags(cmd.Flags(), cfg, &cfgPath, &description, &usages, &extraGroups, &skipTokenPrint)
return cmd
}
// NewSubCmdBootstrapToken returns the Cobra command for running the create token phase
func NewSubCmdBootstrapToken(kubeConfigFile *string) *cobra.Command {
cfg := &kubeadmapiext.MasterConfiguration{
// KubernetesVersion is not used by bootstrap-token, but we set this explicitly to avoid
// the lookup of the version from the internet when executing ConfigFileAndDefaultsToInternalConfig
KubernetesVersion: "v1.9.0",
}
// Default values for the cobra help text
legacyscheme.Scheme.Default(cfg)
var cfgPath, description string
var usages, extraGroups []string
var skipTokenPrint bool
cmd := &cobra.Command{
Use: "create",
Short: "Creates a bootstrap token to be used for node joining",
Long: createTokenLongDesc,
Run: func(cmd *cobra.Command, args []string) {
err := validation.ValidateMixedArguments(cmd.Flags())
kubeadmutil.CheckErr(err)
client, err := kubeconfigutil.ClientSetFromFile(*kubeConfigFile)
kubeadmutil.CheckErr(err)
err = createBootstrapToken(client, cfgPath, cfg, description, usages, extraGroups, skipTokenPrint)
kubeadmutil.CheckErr(err)
},
}
// Adds flags to the command
addBootstrapTokenFlags(cmd.Flags(), cfg, &cfgPath, &description, &usages, &extraGroups, &skipTokenPrint)
return cmd
}
// NewSubCmdClusterInfo returns the Cobra command for running the cluster-info sub-phase
func NewSubCmdClusterInfo(kubeConfigFile *string) *cobra.Command {
cmd := &cobra.Command{
Use: "cluster-info",
Short: "Uploads the cluster-info ConfigMap from the given kubeconfig file",
Long: clusterInfoLongDesc,
Aliases: []string{"clusterinfo"},
Run: func(cmd *cobra.Command, args []string) {
client, err := kubeconfigutil.ClientSetFromFile(*kubeConfigFile)
kubeadmutil.CheckErr(err)
// Create the cluster-info ConfigMap or update if it already exists
err = clusterinfo.CreateBootstrapConfigMapIfNotExists(client, *kubeConfigFile)
kubeadmutil.CheckErr(err)
// Create the RBAC rules that expose the cluster-info ConfigMap properly
err = clusterinfo.CreateClusterInfoRBACRules(client)
kubeadmutil.CheckErr(err)
},
}
return cmd
}
// NewSubCmdNodeBootstrapToken returns the Cobra command for running the node sub-phase
func NewSubCmdNodeBootstrapToken(kubeConfigFile *string) *cobra.Command {
cmd := &cobra.Command{
Use: "node",
Short: "Configures the node bootstrap process",
Aliases: []string{"clusterinfo"},
Long: cmdutil.MacroCommandLongDescription,
}
cmd.AddCommand(NewSubCmdNodeBootstrapTokenPostCSRs(kubeConfigFile))
cmd.AddCommand(NewSubCmdNodeBootstrapTokenAutoApprove(kubeConfigFile))
return cmd
}
// NewSubCmdNodeBootstrapTokenPostCSRs returns the Cobra command for running the allow-post-csrs sub-phase
func NewSubCmdNodeBootstrapTokenPostCSRs(kubeConfigFile *string) *cobra.Command {
cmd := &cobra.Command{
Use: "allow-post-csrs",
Short: "Configures RBAC to allow node bootstrap tokens to post CSRs in order for nodes to get long term certificate credentials",
Long: nodePostCSRsLongDesc,
Run: func(cmd *cobra.Command, args []string) {
client, err := kubeconfigutil.ClientSetFromFile(*kubeConfigFile)
kubeadmutil.CheckErr(err)
// Create RBAC rules that makes the bootstrap tokens able to post CSRs
err = node.AllowBootstrapTokensToPostCSRs(client)
kubeadmutil.CheckErr(err)
},
}
return cmd
}
// NewSubCmdNodeBootstrapTokenAutoApprove returns the Cobra command for running the allow-auto-approve sub-phase
func NewSubCmdNodeBootstrapTokenAutoApprove(kubeConfigFile *string) *cobra.Command {
cmd := &cobra.Command{
Use: "allow-auto-approve",
Short: "Configures RBAC rules to allow the csrapprover controller automatically approve CSRs from a node bootstrap token",
Long: nodeAutoApproveLongDesc,
Run: func(cmd *cobra.Command, args []string) {
client, err := kubeconfigutil.ClientSetFromFile(*kubeConfigFile)
kubeadmutil.CheckErr(err)
// Create RBAC rules that makes the bootstrap tokens able to get their CSRs approved automatically
err = node.AutoApproveNodeBootstrapTokens(client)
kubeadmutil.CheckErr(err)
// Create/update RBAC rules that makes the nodes to rotate certificates and get their CSRs approved automatically
err = node.AutoApproveNodeCertificateRotation(client)
kubeadmutil.CheckErr(err)
},
}
return cmd
}
func addBootstrapTokenFlags(flagSet *pflag.FlagSet, cfg *kubeadmapiext.MasterConfiguration, cfgPath, description *string, usages, extraGroups *[]string, skipTokenPrint *bool) {
flagSet.StringVar(
cfgPath, "config", *cfgPath,
"Path to kubeadm config file (WARNING: Usage of a configuration file is experimental)",
)
flagSet.StringVar(
&cfg.CertificatesDir, "cert-dir", cfg.CertificatesDir,
"The path where certificates are stored",
)
flagSet.StringVar(
&cfg.Token, "token", cfg.Token,
"The token to use for establishing bidirectional trust between nodes and masters",
)
flagSet.DurationVar(
&cfg.TokenTTL.Duration, "ttl", kubeadmconstants.DefaultTokenDuration,
"The duration before the token is automatically deleted (e.g. 1s, 2m, 3h). If set to '0', the token will never expire",
)
flagSet.StringSliceVar(
usages, "usages", kubeadmconstants.DefaultTokenUsages,
fmt.Sprintf("Describes the ways in which this token can be used. You can pass --usages multiple times or provide a comma separated list of options. Valid options: [%s]", strings.Join(kubeadmconstants.DefaultTokenUsages, ",")),
)
flagSet.StringSliceVar(
extraGroups, "groups", []string{kubeadmconstants.NodeBootstrapTokenAuthGroup},
fmt.Sprintf("Extra groups that this token will authenticate as when used for authentication. Must match %q", bootstrapapi.BootstrapGroupPattern),
)
flagSet.StringVar(
description, "description", "The default bootstrap token generated by 'kubeadm init'.",
"A human friendly description of how this token is used.",
)
flagSet.BoolVar(
skipTokenPrint, "skip-token-print", *skipTokenPrint,
"Skip printing of the bootstrap token",
)
}
func createBootstrapToken(client clientset.Interface, cfgPath string, cfg *kubeadmapiext.MasterConfiguration, description string, usages, extraGroups []string, skipTokenPrint bool) error {
// adding groups only makes sense for authentication
usagesSet := sets.NewString(usages...)
usageAuthentication := strings.TrimPrefix(bootstrapapi.BootstrapTokenUsageAuthentication, bootstrapapi.BootstrapTokenUsagePrefix)
if len(extraGroups) > 0 && !usagesSet.Has(usageAuthentication) {
return fmt.Errorf("--groups cannot be specified unless --usages includes %q", usageAuthentication)
}
// validate any extra group names
for _, group := range extraGroups {
if err := bootstrapapi.ValidateBootstrapGroupName(group); err != nil {
return err
}
}
// This call returns the ready-to-use configuration based on the configuration file that might or might not exist and the default cfg populated by flags
internalcfg, err := configutil.ConfigFileAndDefaultsToInternalConfig(cfgPath, cfg)
kubeadmutil.CheckErr(err)
// Load the CA certificate from so we can pin its public key
caCert, err := pkiutil.TryLoadCertFromDisk(internalcfg.CertificatesDir, kubeadmconstants.CACertAndKeyBaseName)
if err != nil {
return fmt.Errorf("error loading ca cert from disk: %v", err)
}
// Creates or updates the token
if err := node.UpdateOrCreateToken(client, internalcfg.Token, false, internalcfg.TokenTTL.Duration, usages, extraGroups, description); err != nil {
return err
}
fmt.Println("[bootstraptoken] Bootstrap token Created")
if skipTokenPrint {
internalcfg.Token = "{token}"
}
fmt.Println("[bootstraptoken] You can now join any number of machines by running:")
fmt.Printf("[bootstraptoken] kubeadm join {master} --token %s --discovery-token-ca-cert-hash %s \n", internalcfg.Token, pubkeypin.Hash(caCert))
return nil
}