Merge pull request #113998 from SataQiu/fix-kubeadm-20221117

kubeadm: respect user provided kubeconfig during discovery process
This commit is contained in:
Kubernetes Prow Robot 2022-12-10 03:17:39 -08:00 committed by GitHub
commit 2e6d3393f7
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 27 additions and 29 deletions

View File

@ -589,7 +589,7 @@ func fetchInitConfigurationFromJoinConfiguration(cfg *kubeadmapi.JoinConfigurati
} }
// Create the final KubeConfig file with the cluster name discovered after fetching the cluster configuration // Create the final KubeConfig file with the cluster name discovered after fetching the cluster configuration
clusterinfo := kubeconfigutil.GetClusterFromKubeConfig(tlsBootstrapCfg) _, clusterinfo := kubeconfigutil.GetClusterFromKubeConfig(tlsBootstrapCfg)
tlsBootstrapCfg.Clusters = map[string]*clientcmdapi.Cluster{ tlsBootstrapCfg.Clusters = map[string]*clientcmdapi.Cluster{
initConfiguration.ClusterName: clusterinfo, initConfiguration.ClusterName: clusterinfo,
} }

View File

@ -59,7 +59,7 @@ func getJoinCommand(kubeConfigFile, token, key string, controlPlane, skipTokenPr
} }
// load the default cluster config // load the default cluster config
clusterConfig := kubeconfigutil.GetClusterFromKubeConfig(config) _, clusterConfig := kubeconfigutil.GetClusterFromKubeConfig(config)
if clusterConfig == nil { if clusterConfig == nil {
return "", errors.New("failed to get default cluster config") return "", errors.New("failed to get default cluster config")
} }

View File

@ -51,7 +51,7 @@ func For(cfg *kubeadmapi.JoinConfiguration) (*clientcmdapi.Config, error) {
if len(cfg.Discovery.TLSBootstrapToken) != 0 { if len(cfg.Discovery.TLSBootstrapToken) != 0 {
klog.V(1).Info("[discovery] Using provided TLSBootstrapToken as authentication credentials for the join process") klog.V(1).Info("[discovery] Using provided TLSBootstrapToken as authentication credentials for the join process")
clusterinfo := kubeconfigutil.GetClusterFromKubeConfig(config) _, clusterinfo := kubeconfigutil.GetClusterFromKubeConfig(config)
return kubeconfigutil.CreateWithToken( return kubeconfigutil.CreateWithToken(
clusterinfo.Server, clusterinfo.Server,
kubeadmapiv1.DefaultClusterName, kubeadmapiv1.DefaultClusterName,
@ -76,9 +76,9 @@ func DiscoverValidatedKubeConfig(cfg *kubeadmapi.JoinConfiguration) (*clientcmda
case cfg.Discovery.File != nil: case cfg.Discovery.File != nil:
kubeConfigPath := cfg.Discovery.File.KubeConfigPath kubeConfigPath := cfg.Discovery.File.KubeConfigPath
if isHTTPSURL(kubeConfigPath) { if isHTTPSURL(kubeConfigPath) {
return https.RetrieveValidatedConfigInfo(kubeConfigPath, kubeadmapiv1.DefaultClusterName, cfg.Discovery.Timeout.Duration) return https.RetrieveValidatedConfigInfo(kubeConfigPath, cfg.Discovery.Timeout.Duration)
} }
return file.RetrieveValidatedConfigInfo(kubeConfigPath, kubeadmapiv1.DefaultClusterName, cfg.Discovery.Timeout.Duration) return file.RetrieveValidatedConfigInfo(kubeConfigPath, cfg.Discovery.Timeout.Duration)
case cfg.Discovery.BootstrapToken != nil: case cfg.Discovery.BootstrapToken != nil:
return token.RetrieveValidatedConfigInfo(&cfg.Discovery) return token.RetrieveValidatedConfigInfo(&cfg.Discovery)
default: default:

View File

@ -38,22 +38,22 @@ import (
// RetrieveValidatedConfigInfo connects to the API Server and makes sure it can talk // RetrieveValidatedConfigInfo connects to the API Server and makes sure it can talk
// securely to the API Server using the provided CA cert and // securely to the API Server using the provided CA cert and
// optionally refreshes the cluster-info information from the cluster-info ConfigMap // optionally refreshes the cluster-info information from the cluster-info ConfigMap
func RetrieveValidatedConfigInfo(filepath, clustername string, discoveryTimeout time.Duration) (*clientcmdapi.Config, error) { func RetrieveValidatedConfigInfo(filepath string, discoveryTimeout time.Duration) (*clientcmdapi.Config, error) {
config, err := clientcmd.LoadFromFile(filepath) config, err := clientcmd.LoadFromFile(filepath)
if err != nil { if err != nil {
return nil, err return nil, err
} }
return ValidateConfigInfo(config, clustername, discoveryTimeout) return ValidateConfigInfo(config, discoveryTimeout)
} }
// ValidateConfigInfo connects to the API Server and makes sure it can talk // ValidateConfigInfo connects to the API Server and makes sure it can talk
// securely to the API Server using the provided CA cert/client certificates and // securely to the API Server using the provided CA cert/client certificates and
// optionally refreshes the cluster-info information from the cluster-info ConfigMap // optionally refreshes the cluster-info information from the cluster-info ConfigMap
func ValidateConfigInfo(config *clientcmdapi.Config, clustername string, discoveryTimeout time.Duration) (*clientcmdapi.Config, error) { func ValidateConfigInfo(config *clientcmdapi.Config, discoveryTimeout time.Duration) (*clientcmdapi.Config, error) {
if len(config.Clusters) < 1 { if len(config.Clusters) < 1 {
return nil, errors.New("the provided kubeconfig file must have at least one Cluster defined") return nil, errors.New("the provided kubeconfig file must have at least one Cluster defined")
} }
currentCluster := kubeconfigutil.GetClusterFromKubeConfig(config) currentClusterName, currentCluster := kubeconfigutil.GetClusterFromKubeConfig(config)
if currentCluster == nil { if currentCluster == nil {
return nil, errors.New("the provided kubeconfig file must have a unnamed Cluster or a CurrentContext that specifies a non-nil Cluster") return nil, errors.New("the provided kubeconfig file must have a unnamed Cluster or a CurrentContext that specifies a non-nil Cluster")
} }
@ -78,15 +78,6 @@ func ValidateConfigInfo(config *clientcmdapi.Config, clustername string, discove
} else { } else {
// If the discovery file config does not contains authentication credentials // If the discovery file config does not contains authentication credentials
klog.V(1).Info("[discovery] Discovery file does not contains authentication credentials, using unauthenticated request for validating TLS connection") klog.V(1).Info("[discovery] Discovery file does not contains authentication credentials, using unauthenticated request for validating TLS connection")
// Create a new kubeconfig object from the discovery file config, with only the server and the CA cert.
// NB. We do this in order to not pick up other possible misconfigurations in the clusterinfo file
config = kubeconfigutil.CreateBasic(
currentCluster.Server,
clustername,
"", // no user provided
currentCluster.CertificateAuthorityData,
)
} }
// Try to read the cluster-info config map; this step was required by the original design in order // Try to read the cluster-info config map; this step was required by the original design in order
@ -131,11 +122,16 @@ func ValidateConfigInfo(config *clientcmdapi.Config, clustername string, discove
return config, nil return config, nil
} }
refreshedCluster := kubeconfigutil.GetClusterFromKubeConfig(refreshedBaseKubeConfig) _, refreshedCluster := kubeconfigutil.GetClusterFromKubeConfig(refreshedBaseKubeConfig)
currentCluster.Server = refreshedCluster.Server if currentCluster.Server != refreshedCluster.Server {
currentCluster.CertificateAuthorityData = refreshedCluster.CertificateAuthorityData klog.Warningf("[discovery] the API Server endpoint %q in use is different from the endpoint %q which defined in the %s ConfigMap", currentCluster.Server, refreshedCluster.Server, bootstrapapi.ConfigMapClusterInfo)
}
if len(currentCluster.CertificateAuthorityData) == 0 && len(refreshedCluster.CertificateAuthorityData) > 0 {
config.Clusters[currentClusterName].CertificateAuthorityData = refreshedCluster.CertificateAuthorityData
klog.V(1).Infof("[discovery] Synced CertificateAuthorityData from the %s ConfigMap", bootstrapapi.ConfigMapClusterInfo)
}
klog.V(1).Infof("[discovery] Synced Server and CertificateAuthorityData from the %s ConfigMap", bootstrapapi.ConfigMapClusterInfo)
return config, nil return config, nil
} }

View File

@ -31,7 +31,7 @@ import (
// RetrieveValidatedConfigInfo connects to the API Server and makes sure it can talk // RetrieveValidatedConfigInfo connects to the API Server and makes sure it can talk
// securely to the API Server using the provided CA cert and // securely to the API Server using the provided CA cert and
// optionally refreshes the cluster-info information from the cluster-info ConfigMap // optionally refreshes the cluster-info information from the cluster-info ConfigMap
func RetrieveValidatedConfigInfo(httpsURL, clustername string, discoveryTimeout time.Duration) (*clientcmdapi.Config, error) { func RetrieveValidatedConfigInfo(httpsURL string, discoveryTimeout time.Duration) (*clientcmdapi.Config, error) {
client := &http.Client{Transport: netutil.SetOldTransportDefaults(&http.Transport{})} client := &http.Client{Transport: netutil.SetOldTransportDefaults(&http.Transport{})}
response, err := client.Get(httpsURL) response, err := client.Get(httpsURL)
if err != nil { if err != nil {
@ -48,5 +48,5 @@ func RetrieveValidatedConfigInfo(httpsURL, clustername string, discoveryTimeout
if err != nil { if err != nil {
return nil, err return nil, err
} }
return file.ValidateConfigInfo(config, clustername, discoveryTimeout) return file.ValidateConfigInfo(config, discoveryTimeout)
} }

View File

@ -104,15 +104,17 @@ func WriteToDisk(filename string, kubeconfig *clientcmdapi.Config) error {
} }
// GetClusterFromKubeConfig returns the default Cluster of the specified KubeConfig // GetClusterFromKubeConfig returns the default Cluster of the specified KubeConfig
func GetClusterFromKubeConfig(config *clientcmdapi.Config) *clientcmdapi.Cluster { func GetClusterFromKubeConfig(config *clientcmdapi.Config) (string, *clientcmdapi.Cluster) {
// If there is an unnamed cluster object, use it // If there is an unnamed cluster object, use it
if config.Clusters[""] != nil { if config.Clusters[""] != nil {
return config.Clusters[""] return "", config.Clusters[""]
} }
if config.Contexts[config.CurrentContext] != nil {
return config.Clusters[config.Contexts[config.CurrentContext].Cluster] currentContext := config.Contexts[config.CurrentContext]
if currentContext != nil {
return currentContext.Cluster, config.Clusters[currentContext.Cluster]
} }
return nil return "", nil
} }
// HasAuthenticationCredentials returns true if the current user has valid authentication credentials for // HasAuthenticationCredentials returns true if the current user has valid authentication credentials for