k8s.io/client-go@v0.22.2/tools/clientcmd/client_config.go (about)

     1  /*
     2  Copyright 2014 The Kubernetes Authors.
     3  
     4  Licensed under the Apache License, Version 2.0 (the "License");
     5  you may not use this file except in compliance with the License.
     6  You may obtain a copy of the License at
     7  
     8      http://www.apache.org/licenses/LICENSE-2.0
     9  
    10  Unless required by applicable law or agreed to in writing, software
    11  distributed under the License is distributed on an "AS IS" BASIS,
    12  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13  See the License for the specific language governing permissions and
    14  limitations under the License.
    15  */
    16  
    17  package clientcmd
    18  
    19  import (
    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  
    37  const (
    38  	// clusterExtensionKey is reserved in the cluster extensions list for exec plugin config.
    39  	clusterExtensionKey = "client.authentication.k8s.io/exec"
    40  )
    41  
    42  var (
    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
    55  func 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
    63  type 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  
    76  type PersistAuthProviderConfigForUser func(user string) restclient.AuthProviderConfigPersister
    77  
    78  type 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
    84  type 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
    95  func 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
   100  func 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
   105  func 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
   110  func 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
   121  func 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  
   129  func (config *DirectClientConfig) RawConfig() (clientcmdapi.Config, error) {
   130  	return config.config, nil
   131  }
   132  
   133  // ClientConfig implements ClientConfig
   134  func (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
   219  func 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
   240  func (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
   307  func 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  
   317  func 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)
   328  func 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
   361  func (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
   387  func (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.
   393  func (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
   426  func (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
   440  func (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
   451  func (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.
   460  func (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.
   478  func (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.
   496  func (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.
   539  type inClusterClientConfig struct {
   540  	overrides               *ConfigOverrides
   541  	inClusterConfigProvider func() (*restclient.Config, error)
   542  }
   543  
   544  var _ ClientConfig = &inClusterClientConfig{}
   545  
   546  func (config *inClusterClientConfig) RawConfig() (clientcmdapi.Config, error) {
   547  	return clientcmdapi.Config{}, fmt.Errorf("inCluster environment config doesn't support multiple clusters")
   548  }
   549  
   550  func (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  
   579  func (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  
   596  func (config *inClusterClientConfig) ConfigAccess() ConfigAccess {
   597  	return NewDefaultClientConfigLoadingRules()
   598  }
   599  
   600  // Possible returns true if loading an inside-kubernetes-cluster is possible.
   601  func (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.
   613  func 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.
   629  func 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  }