diff --git a/cmd/kubeadm/app/phases/kubeconfig/kubeconfig.go b/cmd/kubeadm/app/phases/kubeconfig/kubeconfig.go index b22e06bcfa0..7ee3f36b348 100644 --- a/cmd/kubeadm/app/phases/kubeconfig/kubeconfig.go +++ b/cmd/kubeadm/app/phases/kubeconfig/kubeconfig.go @@ -235,8 +235,14 @@ func validateKubeConfig(outDir, filename string, config *clientcmdapi.Config) er return errors.Errorf("failed to find the given CurrentContext Cluster in Clusters of the kubeconfig file %s", kubeConfigFilePath) } + // Make sure the compared CAs are whitespace-trimmed. The function clientcmd.LoadFromFile() just decodes + // the base64 CA and places it raw in the v1.Config object. In case the user has extra whitespace + // in the CA they used to create a kubeconfig this comparison to a generated v1.Config will otherwise fail. + caCurrent := bytes.TrimSpace(currentConfig.Clusters[currentCluster].CertificateAuthorityData) + caExpected := bytes.TrimSpace(config.Clusters[expectedCluster].CertificateAuthorityData) + // If the current CA cert on disk doesn't match the expected CA cert, error out because we have a file, but it's stale - if !bytes.Equal(currentConfig.Clusters[currentCluster].CertificateAuthorityData, config.Clusters[expectedCluster].CertificateAuthorityData) { + if !bytes.Equal(caCurrent, caExpected) { return errors.Errorf("a kubeconfig file %q exists already but has got the wrong CA cert", kubeConfigFilePath) } // If the current API Server location on disk doesn't match the expected API server, error out because we have a file, but it's stale diff --git a/cmd/kubeadm/app/phases/kubeconfig/kubeconfig_test.go b/cmd/kubeadm/app/phases/kubeconfig/kubeconfig_test.go index 48060b35fa7..40ad4a79794 100644 --- a/cmd/kubeadm/app/phases/kubeconfig/kubeconfig_test.go +++ b/cmd/kubeadm/app/phases/kubeconfig/kubeconfig_test.go @@ -469,6 +469,14 @@ func TestValidateKubeConfig(t *testing.T) { configWithAnotherClusterCa := setupdKubeConfigWithClientAuth(t, anotherCaCert, anotherCaKey, "https://1.2.3.4:1234", "test-cluster", "myOrg1") configWithAnotherServerURL := setupdKubeConfigWithClientAuth(t, caCert, caKey, "https://4.3.2.1:4321", "test-cluster", "myOrg1") + // create a valid config but with whitespace around the CA PEM. + // validateKubeConfig() should tollerate that. + configWhitespace := config.DeepCopy() + configWhitespaceCtx := configWhitespace.Contexts[configWhitespace.CurrentContext] + configWhitespaceCA := string(configWhitespace.Clusters[configWhitespaceCtx.Cluster].CertificateAuthorityData) + configWhitespaceCA = "\n" + configWhitespaceCA + "\n" + configWhitespace.Clusters[configWhitespaceCtx.Cluster].CertificateAuthorityData = []byte(configWhitespaceCA) + tests := map[string]struct { existingKubeConfig *clientcmdapi.Config kubeConfig *clientcmdapi.Config @@ -493,6 +501,11 @@ func TestValidateKubeConfig(t *testing.T) { kubeConfig: config, expectedError: false, }, + "kubeconfig exist and is valid even if its CA contains whitespace": { + existingKubeConfig: configWhitespace, + kubeConfig: config, + expectedError: false, + }, } for name, test := range tests {