kubeconfig.go 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206
  1. /*
  2. Copyright 2017 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 kubeconfig
  14. import (
  15. "fmt"
  16. "io/ioutil"
  17. clientset "k8s.io/client-go/kubernetes"
  18. "k8s.io/client-go/tools/clientcmd"
  19. clientcmdapi "k8s.io/client-go/tools/clientcmd/api"
  20. "github.com/pkg/errors"
  21. )
  22. // CreateBasic creates a basic, general KubeConfig object that then can be extended
  23. func CreateBasic(serverURL, clusterName, userName string, caCert []byte) *clientcmdapi.Config {
  24. // Use the cluster and the username as the context name
  25. contextName := fmt.Sprintf("%s@%s", userName, clusterName)
  26. return &clientcmdapi.Config{
  27. Clusters: map[string]*clientcmdapi.Cluster{
  28. clusterName: {
  29. Server: serverURL,
  30. CertificateAuthorityData: caCert,
  31. },
  32. },
  33. Contexts: map[string]*clientcmdapi.Context{
  34. contextName: {
  35. Cluster: clusterName,
  36. AuthInfo: userName,
  37. },
  38. },
  39. AuthInfos: map[string]*clientcmdapi.AuthInfo{},
  40. CurrentContext: contextName,
  41. }
  42. }
  43. // CreateWithCerts creates a KubeConfig object with access to the API server with client certificates
  44. func CreateWithCerts(serverURL, clusterName, userName string, caCert []byte, clientKey []byte, clientCert []byte) *clientcmdapi.Config {
  45. config := CreateBasic(serverURL, clusterName, userName, caCert)
  46. config.AuthInfos[userName] = &clientcmdapi.AuthInfo{
  47. ClientKeyData: clientKey,
  48. ClientCertificateData: clientCert,
  49. }
  50. return config
  51. }
  52. // CreateWithToken creates a KubeConfig object with access to the API server with a token
  53. func CreateWithToken(serverURL, clusterName, userName string, caCert []byte, token string) *clientcmdapi.Config {
  54. config := CreateBasic(serverURL, clusterName, userName, caCert)
  55. config.AuthInfos[userName] = &clientcmdapi.AuthInfo{
  56. Token: token,
  57. }
  58. return config
  59. }
  60. // ClientSetFromFile returns a ready-to-use client from a kubeconfig file
  61. func ClientSetFromFile(path string) (*clientset.Clientset, error) {
  62. config, err := clientcmd.LoadFromFile(path)
  63. if err != nil {
  64. return nil, errors.Wrap(err, "failed to load admin kubeconfig")
  65. }
  66. return ToClientSet(config)
  67. }
  68. // ToClientSet converts a KubeConfig object to a client
  69. func ToClientSet(config *clientcmdapi.Config) (*clientset.Clientset, error) {
  70. overrides := clientcmd.ConfigOverrides{Timeout: "10s"}
  71. clientConfig, err := clientcmd.NewDefaultClientConfig(*config, &overrides).ClientConfig()
  72. if err != nil {
  73. return nil, errors.Wrap(err, "failed to create API client configuration from kubeconfig")
  74. }
  75. client, err := clientset.NewForConfig(clientConfig)
  76. if err != nil {
  77. return nil, errors.Wrap(err, "failed to create API client")
  78. }
  79. return client, nil
  80. }
  81. // WriteToDisk writes a KubeConfig object down to disk with mode 0600
  82. func WriteToDisk(filename string, kubeconfig *clientcmdapi.Config) error {
  83. err := clientcmd.WriteToFile(*kubeconfig, filename)
  84. if err != nil {
  85. return err
  86. }
  87. return nil
  88. }
  89. // GetClusterFromKubeConfig returns the default Cluster of the specified KubeConfig
  90. func GetClusterFromKubeConfig(config *clientcmdapi.Config) *clientcmdapi.Cluster {
  91. // If there is an unnamed cluster object, use it
  92. if config.Clusters[""] != nil {
  93. return config.Clusters[""]
  94. }
  95. if config.Contexts[config.CurrentContext] != nil {
  96. return config.Clusters[config.Contexts[config.CurrentContext].Cluster]
  97. }
  98. return nil
  99. }
  100. // HasAuthenticationCredentials returns true if the current user has valid authentication credentials for
  101. // token authentication, basic authentication or X509 authentication
  102. func HasAuthenticationCredentials(config *clientcmdapi.Config) bool {
  103. authInfo := getCurrentAuthInfo(config)
  104. if authInfo == nil {
  105. return false
  106. }
  107. // token authentication
  108. if len(authInfo.Token) != 0 {
  109. return true
  110. }
  111. // basic authentication
  112. if len(authInfo.Username) != 0 && len(authInfo.Password) != 0 {
  113. return true
  114. }
  115. // X509 authentication
  116. if (len(authInfo.ClientCertificate) != 0 || len(authInfo.ClientCertificateData) != 0) &&
  117. (len(authInfo.ClientKey) != 0 || len(authInfo.ClientKeyData) != 0) {
  118. return true
  119. }
  120. return false
  121. }
  122. // EnsureAuthenticationInfoAreEmbedded check if some authentication info are provided as external key/certificate
  123. // files, and eventually embeds such files into the kubeconfig file
  124. func EnsureAuthenticationInfoAreEmbedded(config *clientcmdapi.Config) error {
  125. authInfo := getCurrentAuthInfo(config)
  126. if authInfo == nil {
  127. return errors.New("invalid kubeconfig file. AuthInfo is not defined for the current user")
  128. }
  129. if len(authInfo.ClientCertificateData) == 0 && len(authInfo.ClientCertificate) != 0 {
  130. clientCert, err := ioutil.ReadFile(authInfo.ClientCertificate)
  131. if err != nil {
  132. return errors.Wrap(err, "error while reading client cert file defined in kubeconfig")
  133. }
  134. authInfo.ClientCertificateData = clientCert
  135. authInfo.ClientCertificate = ""
  136. }
  137. if len(authInfo.ClientKeyData) == 0 && len(authInfo.ClientKey) != 0 {
  138. clientKey, err := ioutil.ReadFile(authInfo.ClientKey)
  139. if err != nil {
  140. return errors.Wrap(err, "error while reading client key file defined in kubeconfig")
  141. }
  142. authInfo.ClientKeyData = clientKey
  143. authInfo.ClientKey = ""
  144. }
  145. return nil
  146. }
  147. // EnsureCertificateAuthorityIsEmbedded check if the certificate authority is provided as an external
  148. // file and eventually embeds it into the kubeconfig
  149. func EnsureCertificateAuthorityIsEmbedded(cluster *clientcmdapi.Cluster) error {
  150. if cluster == nil {
  151. return errors.New("received nil value for Cluster")
  152. }
  153. if len(cluster.CertificateAuthorityData) == 0 && len(cluster.CertificateAuthority) != 0 {
  154. ca, err := ioutil.ReadFile(cluster.CertificateAuthority)
  155. if err != nil {
  156. return errors.Wrap(err, "error while reading certificate authority file defined in kubeconfig")
  157. }
  158. cluster.CertificateAuthorityData = ca
  159. cluster.CertificateAuthority = ""
  160. }
  161. return nil
  162. }
  163. // getCurrentAuthInfo returns current authInfo, if defined
  164. func getCurrentAuthInfo(config *clientcmdapi.Config) *clientcmdapi.AuthInfo {
  165. if config == nil || config.CurrentContext == "" ||
  166. len(config.Contexts) == 0 || config.Contexts[config.CurrentContext] == nil {
  167. return nil
  168. }
  169. user := config.Contexts[config.CurrentContext].AuthInfo
  170. if user == "" || len(config.AuthInfos) == 0 || config.AuthInfos[user] == nil {
  171. return nil
  172. }
  173. return config.AuthInfos[user]
  174. }