forked from kubernetes/kubernetes
-
Notifications
You must be signed in to change notification settings - Fork 0
/
kubeconfig.go
206 lines (175 loc) · 8.2 KB
/
kubeconfig.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
/*
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"
"io"
"github.com/pkg/errors"
"github.com/spf13/cobra"
kubeadmapi "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm"
kubeadmscheme "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm/scheme"
kubeadmapiv1beta1 "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm/v1beta1"
"k8s.io/kubernetes/cmd/kubeadm/app/cmd/phases/workflow"
cmdutil "k8s.io/kubernetes/cmd/kubeadm/app/cmd/util"
kubeadmconstants "k8s.io/kubernetes/cmd/kubeadm/app/constants"
kubeconfigphase "k8s.io/kubernetes/cmd/kubeadm/app/phases/kubeconfig"
"k8s.io/kubernetes/pkg/util/normalizer"
)
var (
kubeconfigLongDesc = normalizer.LongDesc(`
kubeconfig file utilities.
` + cmdutil.AlphaDisclaimer)
userKubeconfigLongDesc = normalizer.LongDesc(`
Outputs a kubeconfig file for an additional user.
` + cmdutil.AlphaDisclaimer)
userKubeconfigExample = normalizer.Examples(`
# Outputs a kubeconfig file for an additional user named foo
kubeadm alpha kubeconfig user --client-name=foo
`)
kubeconfigFilePhaseProperties = map[string]struct {
name string
short string
long string
}{
kubeadmconstants.AdminKubeConfigFileName: {
name: "admin",
short: "Generates a kubeconfig file for the admin to use and for kubeadm itself",
long: "Generates the kubeconfig file for the admin and for kubeadm itself, and saves it to %s file.",
},
kubeadmconstants.KubeletKubeConfigFileName: {
name: "kubelet",
short: "Generates a kubeconfig file for the kubelet to use *only* for cluster bootstrapping purposes",
long: normalizer.LongDesc(`
Generates the kubeconfig file for the kubelet to use and saves it to %s file.
Please note that this should *only* be used for cluster bootstrapping purposes. After your control plane is up,
you should request all kubelet credentials from the CSR API.`),
},
kubeadmconstants.ControllerManagerKubeConfigFileName: {
name: "controller-manager",
short: "Generates a kubeconfig file for the controller manager to use",
long: "Generates the kubeconfig file for the controller manager to use and saves it to %s file",
},
kubeadmconstants.SchedulerKubeConfigFileName: {
name: "scheduler",
short: "Generates a kubeconfig file for the scheduler to use",
long: "Generates the kubeconfig file for the scheduler to use and saves it to %s file.",
},
}
)
// kubeConfigData defines the behavior that a runtime data struct passed to the kubeconfig phase
// should have. Please note that we are using an interface in order to make this phase reusable in different workflows
// (and thus with different runtime data struct, all of them requested to be compliant to this interface)
type kubeConfigData interface {
Cfg() *kubeadmapi.InitConfiguration
ExternalCA() bool
CertificateDir() string
CertificateWriteDir() string
KubeConfigDir() string
}
// NewKubeConfigPhase creates a kubeadm workflow phase that creates all kubeconfig files necessary to establish the control plane and the admin kubeconfig file.
func NewKubeConfigPhase() workflow.Phase {
return workflow.Phase{
Name: "kubeconfig",
Short: "Generates all kubeconfig files necessary to establish the control plane and the admin kubeconfig file",
Phases: []workflow.Phase{
NewKubeConfigFilePhase(kubeadmconstants.AdminKubeConfigFileName),
NewKubeConfigFilePhase(kubeadmconstants.KubeletKubeConfigFileName),
NewKubeConfigFilePhase(kubeadmconstants.ControllerManagerKubeConfigFileName),
NewKubeConfigFilePhase(kubeadmconstants.SchedulerKubeConfigFileName),
},
Run: runKubeConfig,
}
}
// NewKubeConfigFilePhase creates a kubeadm workflow phase that creates a kubeconfig file.
func NewKubeConfigFilePhase(kubeConfigFileName string) workflow.Phase {
return workflow.Phase{
Name: kubeconfigFilePhaseProperties[kubeConfigFileName].name,
Short: kubeconfigFilePhaseProperties[kubeConfigFileName].short,
Long: fmt.Sprintf(kubeconfigFilePhaseProperties[kubeConfigFileName].long, kubeConfigFileName),
Run: runKubeConfigFile(kubeConfigFileName),
}
}
func runKubeConfig(c workflow.RunData) error {
data, ok := c.(kubeConfigData)
if !ok {
return errors.New("kubeconfig phase invoked with an invalid data struct")
}
fmt.Printf("[kubeconfig] Using kubeconfig folder %q\n", data.KubeConfigDir())
return nil
}
// runKubeConfigFile executes kubeconfig creation logic.
func runKubeConfigFile(kubeConfigFileName string) func(workflow.RunData) error {
return func(c workflow.RunData) error {
data, ok := c.(kubeConfigData)
if !ok {
return errors.New("kubeconfig phase invoked with an invalid data struct")
}
// if external CA mode, skip certificate authority generation
if data.ExternalCA() {
//TODO: implement validation of existing kubeconfig files
fmt.Printf("[kubeconfig] External CA mode: Using user provided %s\n", kubeConfigFileName)
return nil
}
// if dryrunning, reads certificates from a temporary folder (and defer restore to the path originally specified by the user)
cfg := data.Cfg()
cfg.CertificatesDir = data.CertificateWriteDir()
defer func() { cfg.CertificatesDir = data.CertificateDir() }()
// creates the KubeConfig file (or use existing)
return kubeconfigphase.CreateKubeConfigFile(kubeConfigFileName, data.KubeConfigDir(), data.Cfg())
}
}
// NewCmdKubeConfig returns main command for kubeconfig phase
func NewCmdKubeConfig(out io.Writer) *cobra.Command {
cmd := &cobra.Command{
Use: "kubeconfig",
Short: "kubeconfig file utilities",
Long: kubeconfigLongDesc,
}
cmd.AddCommand(NewCmdUserKubeConfig(out, kubeadmconstants.KubernetesDir, ""))
return cmd
}
// NewCmdUserKubeConfig returns sub commands for kubeconfig phase
func NewCmdUserKubeConfig(out io.Writer, outDir, defaultKubernetesVersion string) *cobra.Command {
cfg := &kubeadmapiv1beta1.InitConfiguration{}
// Default values for the cobra help text
kubeadmscheme.Scheme.Default(cfg)
var cfgPath, token, clientName string
var organizations []string
// Creates the UX Command
cmd := &cobra.Command{
Use: "user",
Short: "Outputs a kubeconfig file for an additional user",
Long: userKubeconfigLongDesc,
Example: userKubeconfigExample,
Run: runCmdPhase(func(outDir string, cfg *kubeadmapi.InitConfiguration) error {
if clientName == "" {
return errors.New("missing required argument --client-name")
}
// if the kubeconfig file for an additional user has to use a token, use it
if token != "" {
return kubeconfigphase.WriteKubeConfigWithToken(out, cfg, clientName, token)
}
// Otherwise, write a kubeconfig file with a generate client cert
return kubeconfigphase.WriteKubeConfigWithClientCert(out, cfg, clientName, organizations)
}, &outDir, &cfgPath, cfg, defaultKubernetesVersion),
}
// Add flags to the command
cmd.Flags().StringVar(&cfg.CertificatesDir, "cert-dir", cfg.CertificatesDir, "The path where certificates are stored")
cmd.Flags().StringVar(&cfg.APIEndpoint.AdvertiseAddress, "apiserver-advertise-address", cfg.APIEndpoint.AdvertiseAddress, "The IP address the API server is accessible on")
cmd.Flags().Int32Var(&cfg.APIEndpoint.BindPort, "apiserver-bind-port", cfg.APIEndpoint.BindPort, "The port the API server is accessible on")
cmd.Flags().StringVar(&outDir, "kubeconfig-dir", outDir, "The path where to save the kubeconfig file")
cmd.Flags().StringVar(&token, "token", token, "The token that should be used as the authentication mechanism for this kubeconfig, instead of client certificates")
cmd.Flags().StringVar(&clientName, "client-name", clientName, "The name of user. It will be used as the CN if client certificates are created")
cmd.Flags().StringSliceVar(&organizations, "org", organizations, "The orgnizations of the client certificate. It will be used as the O if client certificates are created")
return cmd
}