1/*
2Copyright 2014 The Kubernetes Authors.
3
4Licensed under the Apache License, Version 2.0 (the "License");
5you may not use this file except in compliance with the License.
6You may obtain a copy of the License at
7
8    http://www.apache.org/licenses/LICENSE-2.0
9
10Unless required by applicable law or agreed to in writing, software
11distributed under the License is distributed on an "AS IS" BASIS,
12WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13See the License for the specific language governing permissions and
14limitations under the License.
15*/
16
17package clientcmd
18
19import (
20	"fmt"
21	"io"
22	"io/ioutil"
23	"net/http"
24	"net/url"
25	"os"
26	"strings"
27	"unicode"
28
29	restclient "k8s.io/client-go/rest"
30	clientauth "k8s.io/client-go/tools/auth"
31	clientcmdapi "k8s.io/client-go/tools/clientcmd/api"
32	"k8s.io/klog/v2"
33
34	"github.com/imdario/mergo"
35)
36
37const (
38	// clusterExtensionKey is reserved in the cluster extensions list for exec plugin config.
39	clusterExtensionKey = "client.authentication.k8s.io/exec"
40)
41
42var (
43	// ClusterDefaults has the same behavior as the old EnvVar and DefaultCluster fields
44	// DEPRECATED will be replaced
45	ClusterDefaults = clientcmdapi.Cluster{Server: getDefaultServer()}
46	// DefaultClientConfig represents the legacy behavior of this package for defaulting
47	// DEPRECATED will be replace
48	DefaultClientConfig = DirectClientConfig{*clientcmdapi.NewConfig(), "", &ConfigOverrides{
49		ClusterDefaults: ClusterDefaults,
50	}, nil, NewDefaultClientConfigLoadingRules(), promptedCredentials{}}
51)
52
53// getDefaultServer returns a default setting for DefaultClientConfig
54// DEPRECATED
55func getDefaultServer() string {
56	if server := os.Getenv("KUBERNETES_MASTER"); len(server) > 0 {
57		return server
58	}
59	return "http://localhost:8080"
60}
61
62// ClientConfig is used to make it easy to get an api server client
63type ClientConfig interface {
64	// RawConfig returns the merged result of all overrides
65	RawConfig() (clientcmdapi.Config, error)
66	// ClientConfig returns a complete client config
67	ClientConfig() (*restclient.Config, error)
68	// Namespace returns the namespace resulting from the merged
69	// result of all overrides and a boolean indicating if it was
70	// overridden
71	Namespace() (string, bool, error)
72	// ConfigAccess returns the rules for loading/persisting the config.
73	ConfigAccess() ConfigAccess
74}
75
76type PersistAuthProviderConfigForUser func(user string) restclient.AuthProviderConfigPersister
77
78type promptedCredentials struct {
79	username string
80	password string `datapolicy:"password"`
81}
82
83// DirectClientConfig is a ClientConfig interface that is backed by a clientcmdapi.Config, options overrides, and an optional fallbackReader for auth information
84type DirectClientConfig struct {
85	config         clientcmdapi.Config
86	contextName    string
87	overrides      *ConfigOverrides
88	fallbackReader io.Reader
89	configAccess   ConfigAccess
90	// promptedCredentials store the credentials input by the user
91	promptedCredentials promptedCredentials
92}
93
94// NewDefaultClientConfig creates a DirectClientConfig using the config.CurrentContext as the context name
95func NewDefaultClientConfig(config clientcmdapi.Config, overrides *ConfigOverrides) ClientConfig {
96	return &DirectClientConfig{config, config.CurrentContext, overrides, nil, NewDefaultClientConfigLoadingRules(), promptedCredentials{}}
97}
98
99// NewNonInteractiveClientConfig creates a DirectClientConfig using the passed context name and does not have a fallback reader for auth information
100func NewNonInteractiveClientConfig(config clientcmdapi.Config, contextName string, overrides *ConfigOverrides, configAccess ConfigAccess) ClientConfig {
101	return &DirectClientConfig{config, contextName, overrides, nil, configAccess, promptedCredentials{}}
102}
103
104// NewInteractiveClientConfig creates a DirectClientConfig using the passed context name and a reader in case auth information is not provided via files or flags
105func NewInteractiveClientConfig(config clientcmdapi.Config, contextName string, overrides *ConfigOverrides, fallbackReader io.Reader, configAccess ConfigAccess) ClientConfig {
106	return &DirectClientConfig{config, contextName, overrides, fallbackReader, configAccess, promptedCredentials{}}
107}
108
109// NewClientConfigFromBytes takes your kubeconfig and gives you back a ClientConfig
110func NewClientConfigFromBytes(configBytes []byte) (ClientConfig, error) {
111	config, err := Load(configBytes)
112	if err != nil {
113		return nil, err
114	}
115
116	return &DirectClientConfig{*config, "", &ConfigOverrides{}, nil, nil, promptedCredentials{}}, nil
117}
118
119// RESTConfigFromKubeConfig is a convenience method to give back a restconfig from your kubeconfig bytes.
120// For programmatic access, this is what you want 80% of the time
121func RESTConfigFromKubeConfig(configBytes []byte) (*restclient.Config, error) {
122	clientConfig, err := NewClientConfigFromBytes(configBytes)
123	if err != nil {
124		return nil, err
125	}
126	return clientConfig.ClientConfig()
127}
128
129func (config *DirectClientConfig) RawConfig() (clientcmdapi.Config, error) {
130	return config.config, nil
131}
132
133// ClientConfig implements ClientConfig
134func (config *DirectClientConfig) ClientConfig() (*restclient.Config, error) {
135	// check that getAuthInfo, getContext, and getCluster do not return an error.
136	// Do this before checking if the current config is usable in the event that an
137	// AuthInfo, Context, or Cluster config with user-defined names are not found.
138	// This provides a user with the immediate cause for error if one is found
139	configAuthInfo, err := config.getAuthInfo()
140	if err != nil {
141		return nil, err
142	}
143
144	_, err = config.getContext()
145	if err != nil {
146		return nil, err
147	}
148
149	configClusterInfo, err := config.getCluster()
150	if err != nil {
151		return nil, err
152	}
153
154	if err := config.ConfirmUsable(); err != nil {
155		return nil, err
156	}
157
158	clientConfig := &restclient.Config{}
159	clientConfig.Host = configClusterInfo.Server
160	if configClusterInfo.ProxyURL != "" {
161		u, err := parseProxyURL(configClusterInfo.ProxyURL)
162		if err != nil {
163			return nil, err
164		}
165		clientConfig.Proxy = http.ProxyURL(u)
166	}
167
168	if config.overrides != nil && len(config.overrides.Timeout) > 0 {
169		timeout, err := ParseTimeout(config.overrides.Timeout)
170		if err != nil {
171			return nil, err
172		}
173		clientConfig.Timeout = timeout
174	}
175
176	if u, err := url.ParseRequestURI(clientConfig.Host); err == nil && u.Opaque == "" && len(u.Path) > 1 {
177		u.RawQuery = ""
178		u.Fragment = ""
179		clientConfig.Host = u.String()
180	}
181	if len(configAuthInfo.Impersonate) > 0 {
182		clientConfig.Impersonate = restclient.ImpersonationConfig{
183			UserName: configAuthInfo.Impersonate,
184			Groups:   configAuthInfo.ImpersonateGroups,
185			Extra:    configAuthInfo.ImpersonateUserExtra,
186		}
187	}
188
189	// only try to read the auth information if we are secure
190	if restclient.IsConfigTransportTLS(*clientConfig) {
191		var err error
192		var persister restclient.AuthProviderConfigPersister
193		if config.configAccess != nil {
194			authInfoName, _ := config.getAuthInfoName()
195			persister = PersisterForUser(config.configAccess, authInfoName)
196		}
197		userAuthPartialConfig, err := config.getUserIdentificationPartialConfig(configAuthInfo, config.fallbackReader, persister, configClusterInfo)
198		if err != nil {
199			return nil, err
200		}
201		mergo.Merge(clientConfig, userAuthPartialConfig, mergo.WithOverride)
202
203		serverAuthPartialConfig, err := getServerIdentificationPartialConfig(configAuthInfo, configClusterInfo)
204		if err != nil {
205			return nil, err
206		}
207		mergo.Merge(clientConfig, serverAuthPartialConfig, mergo.WithOverride)
208	}
209
210	return clientConfig, nil
211}
212
213// clientauth.Info object contain both user identification and server identification.  We want different precedence orders for
214// both, so we have to split the objects and merge them separately
215// we want this order of precedence for the server identification
216// 1.  configClusterInfo (the final result of command line flags and merged .kubeconfig files)
217// 2.  configAuthInfo.auth-path (this file can contain information that conflicts with #1, and we want #1 to win the priority)
218// 3.  load the ~/.kubernetes_auth file as a default
219func getServerIdentificationPartialConfig(configAuthInfo clientcmdapi.AuthInfo, configClusterInfo clientcmdapi.Cluster) (*restclient.Config, error) {
220	mergedConfig := &restclient.Config{}
221
222	// configClusterInfo holds the information identify the server provided by .kubeconfig
223	configClientConfig := &restclient.Config{}
224	configClientConfig.CAFile = configClusterInfo.CertificateAuthority
225	configClientConfig.CAData = configClusterInfo.CertificateAuthorityData
226	configClientConfig.Insecure = configClusterInfo.InsecureSkipTLSVerify
227	configClientConfig.ServerName = configClusterInfo.TLSServerName
228	mergo.Merge(mergedConfig, configClientConfig, mergo.WithOverride)
229
230	return mergedConfig, nil
231}
232
233// clientauth.Info object contain both user identification and server identification.  We want different precedence orders for
234// both, so we have to split the objects and merge them separately
235// we want this order of precedence for user identification
236// 1.  configAuthInfo minus auth-path (the final result of command line flags and merged .kubeconfig files)
237// 2.  configAuthInfo.auth-path (this file can contain information that conflicts with #1, and we want #1 to win the priority)
238// 3.  if there is not enough information to identify the user, load try the ~/.kubernetes_auth file
239// 4.  if there is not enough information to identify the user, prompt if possible
240func (config *DirectClientConfig) getUserIdentificationPartialConfig(configAuthInfo clientcmdapi.AuthInfo, fallbackReader io.Reader, persistAuthConfig restclient.AuthProviderConfigPersister, configClusterInfo clientcmdapi.Cluster) (*restclient.Config, error) {
241	mergedConfig := &restclient.Config{}
242
243	// blindly overwrite existing values based on precedence
244	if len(configAuthInfo.Token) > 0 {
245		mergedConfig.BearerToken = configAuthInfo.Token
246		mergedConfig.BearerTokenFile = configAuthInfo.TokenFile
247	} else if len(configAuthInfo.TokenFile) > 0 {
248		tokenBytes, err := ioutil.ReadFile(configAuthInfo.TokenFile)
249		if err != nil {
250			return nil, err
251		}
252		mergedConfig.BearerToken = string(tokenBytes)
253		mergedConfig.BearerTokenFile = configAuthInfo.TokenFile
254	}
255	if len(configAuthInfo.Impersonate) > 0 {
256		mergedConfig.Impersonate = restclient.ImpersonationConfig{
257			UserName: configAuthInfo.Impersonate,
258			Groups:   configAuthInfo.ImpersonateGroups,
259			Extra:    configAuthInfo.ImpersonateUserExtra,
260		}
261	}
262	if len(configAuthInfo.ClientCertificate) > 0 || len(configAuthInfo.ClientCertificateData) > 0 {
263		mergedConfig.CertFile = configAuthInfo.ClientCertificate
264		mergedConfig.CertData = configAuthInfo.ClientCertificateData
265		mergedConfig.KeyFile = configAuthInfo.ClientKey
266		mergedConfig.KeyData = configAuthInfo.ClientKeyData
267	}
268	if len(configAuthInfo.Username) > 0 || len(configAuthInfo.Password) > 0 {
269		mergedConfig.Username = configAuthInfo.Username
270		mergedConfig.Password = configAuthInfo.Password
271	}
272	if configAuthInfo.AuthProvider != nil {
273		mergedConfig.AuthProvider = configAuthInfo.AuthProvider
274		mergedConfig.AuthConfigPersister = persistAuthConfig
275	}
276	if configAuthInfo.Exec != nil {
277		mergedConfig.ExecProvider = configAuthInfo.Exec
278		mergedConfig.ExecProvider.InstallHint = cleanANSIEscapeCodes(mergedConfig.ExecProvider.InstallHint)
279		mergedConfig.ExecProvider.Config = configClusterInfo.Extensions[clusterExtensionKey]
280	}
281
282	// if there still isn't enough information to authenticate the user, try prompting
283	if !canIdentifyUser(*mergedConfig) && (fallbackReader != nil) {
284		if len(config.promptedCredentials.username) > 0 && len(config.promptedCredentials.password) > 0 {
285			mergedConfig.Username = config.promptedCredentials.username
286			mergedConfig.Password = config.promptedCredentials.password
287			return mergedConfig, nil
288		}
289		prompter := NewPromptingAuthLoader(fallbackReader)
290		promptedAuthInfo, err := prompter.Prompt()
291		if err != nil {
292			return nil, err
293		}
294		promptedConfig := makeUserIdentificationConfig(*promptedAuthInfo)
295		previouslyMergedConfig := mergedConfig
296		mergedConfig = &restclient.Config{}
297		mergo.Merge(mergedConfig, promptedConfig, mergo.WithOverride)
298		mergo.Merge(mergedConfig, previouslyMergedConfig, mergo.WithOverride)
299		config.promptedCredentials.username = mergedConfig.Username
300		config.promptedCredentials.password = mergedConfig.Password
301	}
302
303	return mergedConfig, nil
304}
305
306// makeUserIdentificationFieldsConfig returns a client.Config capable of being merged using mergo for only user identification information
307func makeUserIdentificationConfig(info clientauth.Info) *restclient.Config {
308	config := &restclient.Config{}
309	config.Username = info.User
310	config.Password = info.Password
311	config.CertFile = info.CertFile
312	config.KeyFile = info.KeyFile
313	config.BearerToken = info.BearerToken
314	return config
315}
316
317func canIdentifyUser(config restclient.Config) bool {
318	return len(config.Username) > 0 ||
319		(len(config.CertFile) > 0 || len(config.CertData) > 0) ||
320		len(config.BearerToken) > 0 ||
321		config.AuthProvider != nil ||
322		config.ExecProvider != nil
323}
324
325// cleanANSIEscapeCodes takes an arbitrary string and ensures that there are no
326// ANSI escape sequences that could put the terminal in a weird state (e.g.,
327// "\e[1m" bolds text)
328func cleanANSIEscapeCodes(s string) string {
329	// spaceControlCharacters includes tab, new line, vertical tab, new page, and
330	// carriage return. These are in the unicode.Cc category, but that category also
331	// contains ESC (U+001B) which we don't want.
332	spaceControlCharacters := unicode.RangeTable{
333		R16: []unicode.Range16{
334			{Lo: 0x0009, Hi: 0x000D, Stride: 1},
335		},
336	}
337
338	// Why not make this deny-only (instead of allow-only)? Because unicode.C
339	// contains newline and tab characters that we want.
340	allowedRanges := []*unicode.RangeTable{
341		unicode.L,
342		unicode.M,
343		unicode.N,
344		unicode.P,
345		unicode.S,
346		unicode.Z,
347		&spaceControlCharacters,
348	}
349	builder := strings.Builder{}
350	for _, roon := range s {
351		if unicode.IsOneOf(allowedRanges, roon) {
352			builder.WriteRune(roon) // returns nil error, per go doc
353		} else {
354			fmt.Fprintf(&builder, "%U", roon)
355		}
356	}
357	return builder.String()
358}
359
360// Namespace implements ClientConfig
361func (config *DirectClientConfig) Namespace() (string, bool, error) {
362	if config.overrides != nil && config.overrides.Context.Namespace != "" {
363		// In the event we have an empty config but we do have a namespace override, we should return
364		// the namespace override instead of having config.ConfirmUsable() return an error. This allows
365		// things like in-cluster clients to execute `kubectl get pods --namespace=foo` and have the
366		// --namespace flag honored instead of being ignored.
367		return config.overrides.Context.Namespace, true, nil
368	}
369
370	if err := config.ConfirmUsable(); err != nil {
371		return "", false, err
372	}
373
374	configContext, err := config.getContext()
375	if err != nil {
376		return "", false, err
377	}
378
379	if len(configContext.Namespace) == 0 {
380		return "default", false, nil
381	}
382
383	return configContext.Namespace, false, nil
384}
385
386// ConfigAccess implements ClientConfig
387func (config *DirectClientConfig) ConfigAccess() ConfigAccess {
388	return config.configAccess
389}
390
391// ConfirmUsable looks a particular context and determines if that particular part of the config is useable.  There might still be errors in the config,
392// but no errors in the sections requested or referenced.  It does not return early so that it can find as many errors as possible.
393func (config *DirectClientConfig) ConfirmUsable() error {
394	validationErrors := make([]error, 0)
395
396	var contextName string
397	if len(config.contextName) != 0 {
398		contextName = config.contextName
399	} else {
400		contextName = config.config.CurrentContext
401	}
402
403	if len(contextName) > 0 {
404		_, exists := config.config.Contexts[contextName]
405		if !exists {
406			validationErrors = append(validationErrors, &errContextNotFound{contextName})
407		}
408	}
409
410	authInfoName, _ := config.getAuthInfoName()
411	authInfo, _ := config.getAuthInfo()
412	validationErrors = append(validationErrors, validateAuthInfo(authInfoName, authInfo)...)
413	clusterName, _ := config.getClusterName()
414	cluster, _ := config.getCluster()
415	validationErrors = append(validationErrors, validateClusterInfo(clusterName, cluster)...)
416	// when direct client config is specified, and our only error is that no server is defined, we should
417	// return a standard "no config" error
418	if len(validationErrors) == 1 && validationErrors[0] == ErrEmptyCluster {
419		return newErrConfigurationInvalid([]error{ErrEmptyConfig})
420	}
421	return newErrConfigurationInvalid(validationErrors)
422}
423
424// getContextName returns the default, or user-set context name, and a boolean that indicates
425// whether the default context name has been overwritten by a user-set flag, or left as its default value
426func (config *DirectClientConfig) getContextName() (string, bool) {
427	if config.overrides != nil && len(config.overrides.CurrentContext) != 0 {
428		return config.overrides.CurrentContext, true
429	}
430	if len(config.contextName) != 0 {
431		return config.contextName, false
432	}
433
434	return config.config.CurrentContext, false
435}
436
437// getAuthInfoName returns a string containing the current authinfo name for the current context,
438// and a boolean indicating  whether the default authInfo name is overwritten by a user-set flag, or
439// left as its default value
440func (config *DirectClientConfig) getAuthInfoName() (string, bool) {
441	if config.overrides != nil && len(config.overrides.Context.AuthInfo) != 0 {
442		return config.overrides.Context.AuthInfo, true
443	}
444	context, _ := config.getContext()
445	return context.AuthInfo, false
446}
447
448// getClusterName returns a string containing the default, or user-set cluster name, and a boolean
449// indicating whether the default clusterName has been overwritten by a user-set flag, or left as
450// its default value
451func (config *DirectClientConfig) getClusterName() (string, bool) {
452	if config.overrides != nil && len(config.overrides.Context.Cluster) != 0 {
453		return config.overrides.Context.Cluster, true
454	}
455	context, _ := config.getContext()
456	return context.Cluster, false
457}
458
459// getContext returns the clientcmdapi.Context, or an error if a required context is not found.
460func (config *DirectClientConfig) getContext() (clientcmdapi.Context, error) {
461	contexts := config.config.Contexts
462	contextName, required := config.getContextName()
463
464	mergedContext := clientcmdapi.NewContext()
465	if configContext, exists := contexts[contextName]; exists {
466		mergo.Merge(mergedContext, configContext, mergo.WithOverride)
467	} else if required {
468		return clientcmdapi.Context{}, fmt.Errorf("context %q does not exist", contextName)
469	}
470	if config.overrides != nil {
471		mergo.Merge(mergedContext, config.overrides.Context, mergo.WithOverride)
472	}
473
474	return *mergedContext, nil
475}
476
477// getAuthInfo returns the clientcmdapi.AuthInfo, or an error if a required auth info is not found.
478func (config *DirectClientConfig) getAuthInfo() (clientcmdapi.AuthInfo, error) {
479	authInfos := config.config.AuthInfos
480	authInfoName, required := config.getAuthInfoName()
481
482	mergedAuthInfo := clientcmdapi.NewAuthInfo()
483	if configAuthInfo, exists := authInfos[authInfoName]; exists {
484		mergo.Merge(mergedAuthInfo, configAuthInfo, mergo.WithOverride)
485	} else if required {
486		return clientcmdapi.AuthInfo{}, fmt.Errorf("auth info %q does not exist", authInfoName)
487	}
488	if config.overrides != nil {
489		mergo.Merge(mergedAuthInfo, config.overrides.AuthInfo, mergo.WithOverride)
490	}
491
492	return *mergedAuthInfo, nil
493}
494
495// getCluster returns the clientcmdapi.Cluster, or an error if a required cluster is not found.
496func (config *DirectClientConfig) getCluster() (clientcmdapi.Cluster, error) {
497	clusterInfos := config.config.Clusters
498	clusterInfoName, required := config.getClusterName()
499
500	mergedClusterInfo := clientcmdapi.NewCluster()
501	if config.overrides != nil {
502		mergo.Merge(mergedClusterInfo, config.overrides.ClusterDefaults, mergo.WithOverride)
503	}
504	if configClusterInfo, exists := clusterInfos[clusterInfoName]; exists {
505		mergo.Merge(mergedClusterInfo, configClusterInfo, mergo.WithOverride)
506	} else if required {
507		return clientcmdapi.Cluster{}, fmt.Errorf("cluster %q does not exist", clusterInfoName)
508	}
509	if config.overrides != nil {
510		mergo.Merge(mergedClusterInfo, config.overrides.ClusterInfo, mergo.WithOverride)
511	}
512
513	// * An override of --insecure-skip-tls-verify=true and no accompanying CA/CA data should clear already-set CA/CA data
514	// otherwise, a kubeconfig containing a CA reference would return an error that "CA and insecure-skip-tls-verify couldn't both be set".
515	// * An override of --certificate-authority should also override TLS skip settings and CA data, otherwise existing CA data will take precedence.
516	if config.overrides != nil {
517		caLen := len(config.overrides.ClusterInfo.CertificateAuthority)
518		caDataLen := len(config.overrides.ClusterInfo.CertificateAuthorityData)
519		if config.overrides.ClusterInfo.InsecureSkipTLSVerify || caLen > 0 || caDataLen > 0 {
520			mergedClusterInfo.InsecureSkipTLSVerify = config.overrides.ClusterInfo.InsecureSkipTLSVerify
521			mergedClusterInfo.CertificateAuthority = config.overrides.ClusterInfo.CertificateAuthority
522			mergedClusterInfo.CertificateAuthorityData = config.overrides.ClusterInfo.CertificateAuthorityData
523		}
524
525		// if the --tls-server-name has been set in overrides, use that value.
526		// if the --server has been set in overrides, then use the value of --tls-server-name specified on the CLI too.  This gives the property
527		// that setting a --server will effectively clear the KUBECONFIG value of tls-server-name if it is specified on the command line which is
528		// usually correct.
529		if config.overrides.ClusterInfo.TLSServerName != "" || config.overrides.ClusterInfo.Server != "" {
530			mergedClusterInfo.TLSServerName = config.overrides.ClusterInfo.TLSServerName
531		}
532	}
533
534	return *mergedClusterInfo, nil
535}
536
537// inClusterClientConfig makes a config that will work from within a kubernetes cluster container environment.
538// Can take options overrides for flags explicitly provided to the command inside the cluster container.
539type inClusterClientConfig struct {
540	overrides               *ConfigOverrides
541	inClusterConfigProvider func() (*restclient.Config, error)
542}
543
544var _ ClientConfig = &inClusterClientConfig{}
545
546func (config *inClusterClientConfig) RawConfig() (clientcmdapi.Config, error) {
547	return clientcmdapi.Config{}, fmt.Errorf("inCluster environment config doesn't support multiple clusters")
548}
549
550func (config *inClusterClientConfig) ClientConfig() (*restclient.Config, error) {
551	inClusterConfigProvider := config.inClusterConfigProvider
552	if inClusterConfigProvider == nil {
553		inClusterConfigProvider = restclient.InClusterConfig
554	}
555
556	icc, err := inClusterConfigProvider()
557	if err != nil {
558		return nil, err
559	}
560
561	// in-cluster configs only takes a host, token, or CA file
562	// if any of them were individually provided, overwrite anything else
563	if config.overrides != nil {
564		if server := config.overrides.ClusterInfo.Server; len(server) > 0 {
565			icc.Host = server
566		}
567		if len(config.overrides.AuthInfo.Token) > 0 || len(config.overrides.AuthInfo.TokenFile) > 0 {
568			icc.BearerToken = config.overrides.AuthInfo.Token
569			icc.BearerTokenFile = config.overrides.AuthInfo.TokenFile
570		}
571		if certificateAuthorityFile := config.overrides.ClusterInfo.CertificateAuthority; len(certificateAuthorityFile) > 0 {
572			icc.TLSClientConfig.CAFile = certificateAuthorityFile
573		}
574	}
575
576	return icc, nil
577}
578
579func (config *inClusterClientConfig) Namespace() (string, bool, error) {
580	// This way assumes you've set the POD_NAMESPACE environment variable using the downward API.
581	// This check has to be done first for backwards compatibility with the way InClusterConfig was originally set up
582	if ns := os.Getenv("POD_NAMESPACE"); ns != "" {
583		return ns, false, nil
584	}
585
586	// Fall back to the namespace associated with the service account token, if available
587	if data, err := ioutil.ReadFile("/var/run/secrets/kubernetes.io/serviceaccount/namespace"); err == nil {
588		if ns := strings.TrimSpace(string(data)); len(ns) > 0 {
589			return ns, false, nil
590		}
591	}
592
593	return "default", false, nil
594}
595
596func (config *inClusterClientConfig) ConfigAccess() ConfigAccess {
597	return NewDefaultClientConfigLoadingRules()
598}
599
600// Possible returns true if loading an inside-kubernetes-cluster is possible.
601func (config *inClusterClientConfig) Possible() bool {
602	fi, err := os.Stat("/var/run/secrets/kubernetes.io/serviceaccount/token")
603	return os.Getenv("KUBERNETES_SERVICE_HOST") != "" &&
604		os.Getenv("KUBERNETES_SERVICE_PORT") != "" &&
605		err == nil && !fi.IsDir()
606}
607
608// BuildConfigFromFlags is a helper function that builds configs from a master
609// url or a kubeconfig filepath. These are passed in as command line flags for cluster
610// components. Warnings should reflect this usage. If neither masterUrl or kubeconfigPath
611// are passed in we fallback to inClusterConfig. If inClusterConfig fails, we fallback
612// to the default config.
613func BuildConfigFromFlags(masterUrl, kubeconfigPath string) (*restclient.Config, error) {
614	if kubeconfigPath == "" && masterUrl == "" {
615		klog.Warning("Neither --kubeconfig nor --master was specified.  Using the inClusterConfig.  This might not work.")
616		kubeconfig, err := restclient.InClusterConfig()
617		if err == nil {
618			return kubeconfig, nil
619		}
620		klog.Warning("error creating inClusterConfig, falling back to default config: ", err)
621	}
622	return NewNonInteractiveDeferredLoadingClientConfig(
623		&ClientConfigLoadingRules{ExplicitPath: kubeconfigPath},
624		&ConfigOverrides{ClusterInfo: clientcmdapi.Cluster{Server: masterUrl}}).ClientConfig()
625}
626
627// BuildConfigFromKubeconfigGetter is a helper function that builds configs from a master
628// url and a kubeconfigGetter.
629func BuildConfigFromKubeconfigGetter(masterUrl string, kubeconfigGetter KubeconfigGetter) (*restclient.Config, error) {
630	// TODO: We do not need a DeferredLoader here. Refactor code and see if we can use DirectClientConfig here.
631	cc := NewNonInteractiveDeferredLoadingClientConfig(
632		&ClientConfigGetter{kubeconfigGetter: kubeconfigGetter},
633		&ConfigOverrides{ClusterInfo: clientcmdapi.Cluster{Server: masterUrl}})
634	return cc.ClientConfig()
635}
636