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

     1  /*
     2  Copyright 2015 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 api
    18  
    19  import (
    20  	"encoding/base64"
    21  	"errors"
    22  	"fmt"
    23  	"io/ioutil"
    24  	"os"
    25  	"path"
    26  	"path/filepath"
    27  )
    28  
    29  func init() {
    30  	sDec, _ := base64.StdEncoding.DecodeString("REDACTED+")
    31  	redactedBytes = []byte(string(sDec))
    32  	sDec, _ = base64.StdEncoding.DecodeString("DATA+OMITTED")
    33  	dataOmittedBytes = []byte(string(sDec))
    34  }
    35  
    36  // IsConfigEmpty returns true if the config is empty.
    37  func IsConfigEmpty(config *Config) bool {
    38  	return len(config.AuthInfos) == 0 && len(config.Clusters) == 0 && len(config.Contexts) == 0 &&
    39  		len(config.CurrentContext) == 0 &&
    40  		len(config.Preferences.Extensions) == 0 && !config.Preferences.Colors &&
    41  		len(config.Extensions) == 0
    42  }
    43  
    44  // MinifyConfig read the current context and uses that to keep only the relevant pieces of config
    45  // This is useful for making secrets based on kubeconfig files
    46  func MinifyConfig(config *Config) error {
    47  	if len(config.CurrentContext) == 0 {
    48  		return errors.New("current-context must exist in order to minify")
    49  	}
    50  
    51  	currContext, exists := config.Contexts[config.CurrentContext]
    52  	if !exists {
    53  		return fmt.Errorf("cannot locate context %v", config.CurrentContext)
    54  	}
    55  
    56  	newContexts := map[string]*Context{}
    57  	newContexts[config.CurrentContext] = currContext
    58  
    59  	newClusters := map[string]*Cluster{}
    60  	if len(currContext.Cluster) > 0 {
    61  		if _, exists := config.Clusters[currContext.Cluster]; !exists {
    62  			return fmt.Errorf("cannot locate cluster %v", currContext.Cluster)
    63  		}
    64  
    65  		newClusters[currContext.Cluster] = config.Clusters[currContext.Cluster]
    66  	}
    67  
    68  	newAuthInfos := map[string]*AuthInfo{}
    69  	if len(currContext.AuthInfo) > 0 {
    70  		if _, exists := config.AuthInfos[currContext.AuthInfo]; !exists {
    71  			return fmt.Errorf("cannot locate user %v", currContext.AuthInfo)
    72  		}
    73  
    74  		newAuthInfos[currContext.AuthInfo] = config.AuthInfos[currContext.AuthInfo]
    75  	}
    76  
    77  	config.AuthInfos = newAuthInfos
    78  	config.Clusters = newClusters
    79  	config.Contexts = newContexts
    80  
    81  	return nil
    82  }
    83  
    84  var (
    85  	redactedBytes    []byte
    86  	dataOmittedBytes []byte
    87  )
    88  
    89  // Flatten redacts raw data entries from the config object for a human-readable view.
    90  func ShortenConfig(config *Config) {
    91  	// trick json encoder into printing a human readable string in the raw data
    92  	// by base64 decoding what we want to print. Relies on implementation of
    93  	// http://golang.org/pkg/encoding/json/#Marshal using base64 to encode []byte
    94  	for key, authInfo := range config.AuthInfos {
    95  		if len(authInfo.ClientKeyData) > 0 {
    96  			authInfo.ClientKeyData = redactedBytes
    97  		}
    98  		if len(authInfo.ClientCertificateData) > 0 {
    99  			authInfo.ClientCertificateData = redactedBytes
   100  		}
   101  		if len(authInfo.Token) > 0 {
   102  			authInfo.Token = "REDACTED"
   103  		}
   104  		config.AuthInfos[key] = authInfo
   105  	}
   106  	for key, cluster := range config.Clusters {
   107  		if len(cluster.CertificateAuthorityData) > 0 {
   108  			cluster.CertificateAuthorityData = dataOmittedBytes
   109  		}
   110  		config.Clusters[key] = cluster
   111  	}
   112  }
   113  
   114  // Flatten changes the config object into a self contained config (useful for making secrets)
   115  func FlattenConfig(config *Config) error {
   116  	for key, authInfo := range config.AuthInfos {
   117  		baseDir, err := MakeAbs(path.Dir(authInfo.LocationOfOrigin), "")
   118  		if err != nil {
   119  			return err
   120  		}
   121  
   122  		if err := FlattenContent(&authInfo.ClientCertificate, &authInfo.ClientCertificateData, baseDir); err != nil {
   123  			return err
   124  		}
   125  		if err := FlattenContent(&authInfo.ClientKey, &authInfo.ClientKeyData, baseDir); err != nil {
   126  			return err
   127  		}
   128  
   129  		config.AuthInfos[key] = authInfo
   130  	}
   131  	for key, cluster := range config.Clusters {
   132  		baseDir, err := MakeAbs(path.Dir(cluster.LocationOfOrigin), "")
   133  		if err != nil {
   134  			return err
   135  		}
   136  
   137  		if err := FlattenContent(&cluster.CertificateAuthority, &cluster.CertificateAuthorityData, baseDir); err != nil {
   138  			return err
   139  		}
   140  
   141  		config.Clusters[key] = cluster
   142  	}
   143  
   144  	return nil
   145  }
   146  
   147  func FlattenContent(path *string, contents *[]byte, baseDir string) error {
   148  	if len(*path) != 0 {
   149  		if len(*contents) > 0 {
   150  			return errors.New("cannot have values for both path and contents")
   151  		}
   152  
   153  		var err error
   154  		absPath := ResolvePath(*path, baseDir)
   155  		*contents, err = ioutil.ReadFile(absPath)
   156  		if err != nil {
   157  			return err
   158  		}
   159  
   160  		*path = ""
   161  	}
   162  
   163  	return nil
   164  }
   165  
   166  // ResolvePath returns the path as an absolute paths, relative to the given base directory
   167  func ResolvePath(path string, base string) string {
   168  	// Don't resolve empty paths
   169  	if len(path) > 0 {
   170  		// Don't resolve absolute paths
   171  		if !filepath.IsAbs(path) {
   172  			return filepath.Join(base, path)
   173  		}
   174  	}
   175  
   176  	return path
   177  }
   178  
   179  func MakeAbs(path, base string) (string, error) {
   180  	if filepath.IsAbs(path) {
   181  		return path, nil
   182  	}
   183  	if len(base) == 0 {
   184  		cwd, err := os.Getwd()
   185  		if err != nil {
   186  			return "", err
   187  		}
   188  		base = cwd
   189  	}
   190  	return filepath.Join(base, path), nil
   191  }