k8s.io/client-go@v0.31.1/tools/auth/exec/exec.go (about) 1 /* 2 Copyright 2020 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 exec contains helper utilities for exec credential plugins. 18 package exec 19 20 import ( 21 "errors" 22 "fmt" 23 "os" 24 25 "k8s.io/apimachinery/pkg/runtime" 26 "k8s.io/apimachinery/pkg/runtime/schema" 27 "k8s.io/apimachinery/pkg/runtime/serializer" 28 "k8s.io/client-go/pkg/apis/clientauthentication" 29 "k8s.io/client-go/pkg/apis/clientauthentication/install" 30 "k8s.io/client-go/rest" 31 ) 32 33 const execInfoEnv = "KUBERNETES_EXEC_INFO" 34 35 var scheme = runtime.NewScheme() 36 var codecs = serializer.NewCodecFactory(scheme) 37 38 func init() { 39 install.Install(scheme) 40 } 41 42 // LoadExecCredentialFromEnv is a helper-wrapper around LoadExecCredential that loads from the 43 // well-known KUBERNETES_EXEC_INFO environment variable. 44 // 45 // When the KUBERNETES_EXEC_INFO environment variable is not set or is empty, then this function 46 // will immediately return an error. 47 func LoadExecCredentialFromEnv() (runtime.Object, *rest.Config, error) { 48 env := os.Getenv(execInfoEnv) 49 if env == "" { 50 return nil, nil, errors.New("KUBERNETES_EXEC_INFO env var is unset or empty") 51 } 52 return LoadExecCredential([]byte(env)) 53 } 54 55 // LoadExecCredential loads the configuration needed for an exec plugin to communicate with a 56 // cluster. 57 // 58 // LoadExecCredential expects the provided data to be a serialized client.authentication.k8s.io 59 // ExecCredential object (of any version). If the provided data is invalid (i.e., it cannot be 60 // unmarshalled into any known client.authentication.k8s.io ExecCredential version), an error will 61 // be returned. A successfully unmarshalled ExecCredential will be returned as the first return 62 // value. 63 // 64 // If the provided data is successfully unmarshalled, but it does not contain cluster information 65 // (i.e., ExecCredential.Spec.Cluster == nil), then an error will be returned. 66 // 67 // Note that the returned rest.Config will use anonymous authentication, since the exec plugin has 68 // not returned credentials for this cluster yet. 69 func LoadExecCredential(data []byte) (runtime.Object, *rest.Config, error) { 70 obj, gvk, err := codecs.UniversalDeserializer().Decode(data, nil, nil) 71 if err != nil { 72 return nil, nil, fmt.Errorf("decode: %w", err) 73 } 74 75 expectedGK := schema.GroupKind{ 76 Group: clientauthentication.SchemeGroupVersion.Group, 77 Kind: "ExecCredential", 78 } 79 if gvk.GroupKind() != expectedGK { 80 return nil, nil, fmt.Errorf( 81 "invalid group/kind: wanted %s, got %s", 82 expectedGK.String(), 83 gvk.GroupKind().String(), 84 ) 85 } 86 87 // Explicitly convert object here so that we can return a nicer error message above for when the 88 // data represents an invalid type. 89 var execCredential clientauthentication.ExecCredential 90 if err := scheme.Convert(obj, &execCredential, nil); err != nil { 91 return nil, nil, fmt.Errorf("cannot convert to ExecCredential: %w", err) 92 } 93 94 if execCredential.Spec.Cluster == nil { 95 return nil, nil, errors.New("ExecCredential does not contain cluster information") 96 } 97 98 restConfig, err := rest.ExecClusterToConfig(execCredential.Spec.Cluster) 99 if err != nil { 100 return nil, nil, fmt.Errorf("cannot create rest.Config: %w", err) 101 } 102 103 return obj, restConfig, nil 104 }