client_config.go 28 KB

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