diff --git a/staging/src/k8s.io/cli-runtime/pkg/genericclioptions/config_flags.go b/staging/src/k8s.io/cli-runtime/pkg/genericclioptions/config_flags.go index 8dba84e3420..d73b0b6d8e7 100644 --- a/staging/src/k8s.io/cli-runtime/pkg/genericclioptions/config_flags.go +++ b/staging/src/k8s.io/cli-runtime/pkg/genericclioptions/config_flags.go @@ -170,9 +170,11 @@ func (f *ConfigFlags) toRawKubeConfigLoader() clientcmd.ClientConfig { // bind auth info flag values to overrides if f.CertFile != nil { overrides.AuthInfo.ClientCertificate = *f.CertFile + overrides.AuthInfo.ClientCertificateData = nil } if f.KeyFile != nil { overrides.AuthInfo.ClientKey = *f.KeyFile + overrides.AuthInfo.ClientKeyData = nil } if f.BearerToken != nil { overrides.AuthInfo.Token = *f.BearerToken diff --git a/staging/src/k8s.io/client-go/tools/clientcmd/client_config.go b/staging/src/k8s.io/client-go/tools/clientcmd/client_config.go index cd0a8649b18..e41fa46c144 100644 --- a/staging/src/k8s.io/client-go/tools/clientcmd/client_config.go +++ b/staging/src/k8s.io/client-go/tools/clientcmd/client_config.go @@ -533,6 +533,19 @@ func (config *DirectClientConfig) getAuthInfo() (clientcmdapi.AuthInfo, error) { if err := merge(mergedAuthInfo, &config.overrides.AuthInfo); err != nil { return clientcmdapi.AuthInfo{}, err } + + // Handle ClientKey/ClientKeyData conflict: if override sets ClientKey, also use override's ClientKeyData + // otherwise if original config has ClientKeyData set, + // validation returns error "client-key-data and client-key are both specified " + if len(config.overrides.AuthInfo.ClientKey) > 0 { + mergedAuthInfo.ClientKeyData = config.overrides.AuthInfo.ClientKeyData + } + // Handle ClientCertificate/ClientCertificateData conflict, if override sets ClientCertificate, also use override's ClientCertificateData + // otherwise if original config has ClientCertificateData set, + // validation returns error "client-cert-data and client-cert are both specified " + if len(config.overrides.AuthInfo.ClientCertificate) > 0 { + mergedAuthInfo.ClientCertificateData = config.overrides.AuthInfo.ClientCertificateData + } } return *mergedAuthInfo, nil diff --git a/staging/src/k8s.io/client-go/tools/clientcmd/client_config_test.go b/staging/src/k8s.io/client-go/tools/clientcmd/client_config_test.go index 4872eadf3d2..593d4b016e8 100644 --- a/staging/src/k8s.io/client-go/tools/clientcmd/client_config_test.go +++ b/staging/src/k8s.io/client-go/tools/clientcmd/client_config_test.go @@ -1222,3 +1222,76 @@ func TestMergeRawConfigDoOverride(t *testing.T) { t.Errorf("Expected namespace %v, got %v", config.Contexts["clean"].Namespace, act.Contexts["clean"].Namespace) } } + +func TestClientCertOverrideData(t *testing.T) { + // Test that when overrides contain cert/key file paths, the corresponding + // data fields are properly handled to avoid validation conflicts + // in particular code in DirectClientConfig::getAuthInfo + + certFile, err := os.CreateTemp("", "test-client-*.crt") + if err != nil { + t.Fatalf("Failed to create temp cert file: %v", err) + } + defer utiltesting.CloseAndRemove(t, certFile) + + keyFile, err := os.CreateTemp("", "test-client-*.key") + if err != nil { + t.Fatalf("Failed to create temp key file: %v", err) + } + defer utiltesting.CloseAndRemove(t, keyFile) + + if err := os.WriteFile(certFile.Name(), []byte("dummy-cert-content"), 0600); err != nil { + t.Fatalf("Failed to write cert file: %v", err) + } + if err := os.WriteFile(keyFile.Name(), []byte("dummy-key-content"), 0600); err != nil { + t.Fatalf("Failed to write key file: %v", err) + } + + baseConfig := clientcmdapi.Config{ + Clusters: map[string]*clientcmdapi.Cluster{ + "test-cluster": { + Server: "https://example.com:6443", + CertificateAuthorityData: []byte("fake-ca-data"), + }, + }, + AuthInfos: map[string]*clientcmdapi.AuthInfo{ + "test-user": { + ClientCertificateData: []byte("base-cert-data"), + ClientKeyData: []byte("base-key-data"), + }, + }, + Contexts: map[string]*clientcmdapi.Context{ + "test-context": { + Cluster: "test-cluster", + AuthInfo: "test-user", + }, + }, + CurrentContext: "test-context", + } + + overrides := &ConfigOverrides{ + AuthInfo: clientcmdapi.AuthInfo{ + ClientCertificate: certFile.Name(), + ClientCertificateData: nil, + ClientKey: keyFile.Name(), + ClientKeyData: nil, + }, + } + + clientConfig := NewNonInteractiveClientConfig(baseConfig, "test-context", overrides, nil) + + mergedConfig, err := clientConfig.MergedRawConfig() + if err != nil { + t.Fatalf("MergedRawConfig() failed: %v", err) + } + + authInfo := mergedConfig.AuthInfos["test-user"] + if authInfo == nil { + t.Fatalf("Expected AuthInfo 'test-user' not found") + } + + matchStringArg(certFile.Name(), authInfo.ClientCertificate, t) + matchStringArg(keyFile.Name(), authInfo.ClientKey, t) + matchByteArg(nil, authInfo.ClientCertificateData, t) + matchByteArg(nil, authInfo.ClientKeyData, t) +}