KubeVirt Affected by an Authentication Bypass in Kubernetes Aggregation Layer
Description
KubeVirt is a virtual machine management add-on for Kubernetes. Versions 1.5.3 and below, and 1.6.0 contained a flawed implementation of the Kubernetes aggregation layer's authentication flow which could enable bypass of RBAC controls. It was discovered that the virt-api component fails to correctly authenticate the client when receiving API requests over mTLS. In particular, it fails to validate the CN (Common Name) field in the received client TLS certificates against the set of allowed values defined in the extension-apiserver-authentication configmap. Failre to validate certain fields in the client TLS certificate may allow an attacker to bypass existing RBAC controls by directly communicating with the aggregated API server, impersonating the Kubernetes API server and its aggregator component. This issue is fixed in versions 1.5.3 and 1.6.1.
Affected packages
Versions sourced from the GitHub Security Advisory.
| Package | Affected versions | Patched versions |
|---|---|---|
kubevirt.io/kubevirtGo | < 1.5.3 | 1.5.3 |
kubevirt.io/kubevirtGo | >= 1.6.0-alpha.0, < 1.6.1 | 1.6.1 |
kubevirt.io/kubevirtGo | >= 1.7.0-alpha.0, < 1.7.0-rc.0 | 1.7.0-rc.0 |
Affected products
1Patches
3231dc69723f3SetupTLSWithCertManager now enforces CN
3 files changed · +55 −4
pkg/util/tls/tls.go+29 −1 modified@@ -17,6 +17,7 @@ import ( ) const noSrvCertMessage = "No server certificate, server is not yet ready to receive traffic" +const serverNotReadyMsg = "Server is not yet ready to receive traffic" var ( cipherSuites = tls.CipherSuites() @@ -91,7 +92,7 @@ func SetupExportProxyTLS(certManager certificate.Manager, kubeVirtStore cache.St return tlsConfig } -func SetupTLSWithCertManager(caManager ClientCAManager, certManager certificate.Manager, clientAuth tls.ClientAuthType, clusterConfig *virtconfig.ClusterConfig) *tls.Config { +func SetupTLSWithCertManager(caManager KubernetesCAManager, certManager certificate.Manager, clientAuth tls.ClientAuthType, clusterConfig *virtconfig.ClusterConfig) *tls.Config { tlsConfig := &tls.Config{ GetCertificate: func(info *tls.ClientHelloInfo) (certificate *tls.Certificate, err error) { cert := certManager.Current() @@ -122,6 +123,33 @@ func SetupTLSWithCertManager(caManager ClientCAManager, certManager certificate. Certificates: []tls.Certificate{*cert}, ClientCAs: clientCAPool, ClientAuth: clientAuth, + VerifyPeerCertificate: func(rawCerts [][]byte, verifiedChains [][]*x509.Certificate) error { + if len(verifiedChains) == 0 || len(verifiedChains[0]) == 0 { + return nil + } + + certificate, err := x509.ParseCertificate(rawCerts[0]) + if err != nil { + return fmt.Errorf("failed to parse peer certificate: %v", err) + } + + CNs, err := caManager.GetCNs() + if err != nil { + log.Log.Reason(err).Error(serverNotReadyMsg) + return fmt.Errorf(serverNotReadyMsg) + } + + if len(CNs) == 0 { + return nil + } + for _, CN := range CNs { + if certificate.Subject.CommonName == CN { + return nil + } + } + + return fmt.Errorf("Common name is invalid") + }, } config.BuildNameToCertificate()
pkg/util/tls/tls_test.go+25 −2 modified@@ -31,6 +31,7 @@ import ( type mockCAManager struct { caBundle []byte + cns []string } type mockCertManager struct { @@ -66,9 +67,13 @@ func (m *mockCAManager) GetCurrentRaw() ([]byte, error) { return nil, fmt.Errorf("not implemented") } +func (m *mockCAManager) GetCNs() ([]string, error) { + return m.cns, nil +} + var _ = Describe("TLS", func() { - var caManager kvtls.ClientCAManager + var caManager kvtls.KubernetesCAManager var certmanagers map[string]certificate.Manager var clusterConfig *virtconfig.ClusterConfig var kubeVirtStore cache.Store @@ -220,7 +225,8 @@ var _ = Describe("TLS", func() { }), ) - DescribeTable("should verify self-signed client and server certificates", func(serverSecret, clientSecret string, errStr string) { + DescribeTable("should verify self-signed client and server certificates", func(serverSecret, clientSecret, errStr string, cns []string) { + caManager.(*mockCAManager).cns = cns serverTLSConfig := kvtls.SetupTLSWithCertManager(caManager, certmanagers[serverSecret], tls.RequireAndVerifyClientCert, clusterConfig) clientTLSConfig := kvtls.SetupTLSForVirtHandlerClients(caManager, certmanagers[clientSecret], false) srv := httptest.NewUnstartedServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { @@ -248,18 +254,35 @@ var _ = Describe("TLS", func() { components.VirtHandlerServerCertSecretName, components.VirtHandlerCertSecretName, "", + []string{"kubevirt.io:system:client:virt-handler"}, + ), + Entry( + "connect with proper certificates with no CN auth", + components.VirtHandlerServerCertSecretName, + components.VirtHandlerCertSecretName, + "", + []string{}, + ), + Entry( + "fail if client uses an invalid certificates (CN)", + components.VirtHandlerServerCertSecretName, + components.VirtHandlerCertSecretName, + "remote error: tls: bad certificate", + []string{"kubevirt.io:system:clientv2:virt-handler"}, ), Entry( "fail if client uses an invalid certificate", components.VirtHandlerServerCertSecretName, components.VirtHandlerServerCertSecretName, "remote error: tls: bad certificate", + []string{"kubevirt.io:system:client:virt-handler"}, ), Entry( "fail if server uses an invalid certificate", components.VirtHandlerCertSecretName, components.VirtHandlerCertSecretName, "x509: certificate specifies an incompatible key usage", + []string{"kubevirt.io:system:client:virt-handler"}, ), )
pkg/virt-api/api.go+1 −1 modified@@ -990,7 +990,7 @@ func (app *virtAPIApp) registerMutatingWebhook(informers *webhooks.Informers) { }) } -func (app *virtAPIApp) setupTLS(k8sCAManager kvtls.ClientCAManager, kubevirtCAManager kvtls.ClientCAManager) { +func (app *virtAPIApp) setupTLS(k8sCAManager kvtls.KubernetesCAManager, kubevirtCAManager kvtls.ClientCAManager) { // A VerifyClientCertIfGiven request means we're not guaranteed // a client has been authenticated unless they provide a peer
af2f08a9a186SetupTLSWithCertManager now enforces CN
3 files changed · +55 −4
pkg/util/tls/tls.go+29 −1 modified@@ -17,6 +17,7 @@ import ( ) const noSrvCertMessage = "No server certificate, server is not yet ready to receive traffic" +const serverNotReadyMsg = "Server is not yet ready to receive traffic" var ( cipherSuites = tls.CipherSuites() @@ -91,7 +92,7 @@ func SetupExportProxyTLS(certManager certificate.Manager, kubeVirtStore cache.St return tlsConfig } -func SetupTLSWithCertManager(caManager ClientCAManager, certManager certificate.Manager, clientAuth tls.ClientAuthType, clusterConfig *virtconfig.ClusterConfig) *tls.Config { +func SetupTLSWithCertManager(caManager KubernetesCAManager, certManager certificate.Manager, clientAuth tls.ClientAuthType, clusterConfig *virtconfig.ClusterConfig) *tls.Config { tlsConfig := &tls.Config{ GetCertificate: func(info *tls.ClientHelloInfo) (certificate *tls.Certificate, err error) { cert := certManager.Current() @@ -122,6 +123,33 @@ func SetupTLSWithCertManager(caManager ClientCAManager, certManager certificate. Certificates: []tls.Certificate{*cert}, ClientCAs: clientCAPool, ClientAuth: clientAuth, + VerifyPeerCertificate: func(rawCerts [][]byte, verifiedChains [][]*x509.Certificate) error { + if len(verifiedChains) == 0 || len(verifiedChains[0]) == 0 { + return nil + } + + certificate, err := x509.ParseCertificate(rawCerts[0]) + if err != nil { + return fmt.Errorf("failed to parse peer certificate: %v", err) + } + + CNs, err := caManager.GetCNs() + if err != nil { + log.Log.Reason(err).Error(serverNotReadyMsg) + return fmt.Errorf(serverNotReadyMsg) + } + + if len(CNs) == 0 { + return nil + } + for _, CN := range CNs { + if certificate.Subject.CommonName == CN { + return nil + } + } + + return fmt.Errorf("Common name is invalid") + }, } config.BuildNameToCertificate()
pkg/util/tls/tls_test.go+25 −2 modified@@ -31,6 +31,7 @@ import ( type mockCAManager struct { caBundle []byte + cns []string } type mockCertManager struct { @@ -66,9 +67,13 @@ func (m *mockCAManager) GetCurrentRaw() ([]byte, error) { return nil, fmt.Errorf("not implemented") } +func (m *mockCAManager) GetCNs() ([]string, error) { + return m.cns, nil +} + var _ = Describe("TLS", func() { - var caManager kvtls.ClientCAManager + var caManager kvtls.KubernetesCAManager var certmanagers map[string]certificate.Manager var clusterConfig *virtconfig.ClusterConfig var kubeVirtStore cache.Store @@ -220,7 +225,8 @@ var _ = Describe("TLS", func() { }), ) - DescribeTable("should verify self-signed client and server certificates", func(serverSecret, clientSecret string, errStr string) { + DescribeTable("should verify self-signed client and server certificates", func(serverSecret, clientSecret, errStr string, cns []string) { + caManager.(*mockCAManager).cns = cns serverTLSConfig := kvtls.SetupTLSWithCertManager(caManager, certmanagers[serverSecret], tls.RequireAndVerifyClientCert, clusterConfig) clientTLSConfig := kvtls.SetupTLSForVirtHandlerClients(caManager, certmanagers[clientSecret], false) srv := httptest.NewUnstartedServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { @@ -248,18 +254,35 @@ var _ = Describe("TLS", func() { components.VirtHandlerServerCertSecretName, components.VirtHandlerCertSecretName, "", + []string{"kubevirt.io:system:client:virt-handler"}, + ), + Entry( + "connect with proper certificates with no CN auth", + components.VirtHandlerServerCertSecretName, + components.VirtHandlerCertSecretName, + "", + []string{}, + ), + Entry( + "fail if client uses an invalid certificates (CN)", + components.VirtHandlerServerCertSecretName, + components.VirtHandlerCertSecretName, + "remote error: tls: bad certificate", + []string{"kubevirt.io:system:clientv2:virt-handler"}, ), Entry( "fail if client uses an invalid certificate", components.VirtHandlerServerCertSecretName, components.VirtHandlerServerCertSecretName, "remote error: tls: bad certificate", + []string{"kubevirt.io:system:client:virt-handler"}, ), Entry( "fail if server uses an invalid certificate", components.VirtHandlerCertSecretName, components.VirtHandlerCertSecretName, "x509: certificate specifies an incompatible key usage", + []string{"kubevirt.io:system:client:virt-handler"}, ), )
pkg/virt-api/api.go+1 −1 modified@@ -990,7 +990,7 @@ func (app *virtAPIApp) registerMutatingWebhook(informers *webhooks.Informers) { }) } -func (app *virtAPIApp) setupTLS(k8sCAManager kvtls.ClientCAManager, kubevirtCAManager kvtls.ClientCAManager) { +func (app *virtAPIApp) setupTLS(k8sCAManager kvtls.KubernetesCAManager, kubevirtCAManager kvtls.ClientCAManager) { // A VerifyClientCertIfGiven request means we're not guaranteed // a client has been authenticated unless they provide a peer
b9773bc588e6SetupTLSWithCertManager now enforces CN
3 files changed · +55 −4
pkg/util/tls/tls.go+29 −1 modified@@ -17,6 +17,7 @@ import ( ) const noSrvCertMessage = "No server certificate, server is not yet ready to receive traffic" +const serverNotReadyMsg = "Server is not yet ready to receive traffic" var ( cipherSuites = tls.CipherSuites() @@ -91,7 +92,7 @@ func SetupExportProxyTLS(certManager certificate.Manager, kubeVirtStore cache.St return tlsConfig } -func SetupTLSWithCertManager(caManager ClientCAManager, certManager certificate.Manager, clientAuth tls.ClientAuthType, clusterConfig *virtconfig.ClusterConfig) *tls.Config { +func SetupTLSWithCertManager(caManager KubernetesCAManager, certManager certificate.Manager, clientAuth tls.ClientAuthType, clusterConfig *virtconfig.ClusterConfig) *tls.Config { tlsConfig := &tls.Config{ GetCertificate: func(info *tls.ClientHelloInfo) (certificate *tls.Certificate, err error) { cert := certManager.Current() @@ -122,6 +123,33 @@ func SetupTLSWithCertManager(caManager ClientCAManager, certManager certificate. Certificates: []tls.Certificate{*cert}, ClientCAs: clientCAPool, ClientAuth: clientAuth, + VerifyPeerCertificate: func(rawCerts [][]byte, verifiedChains [][]*x509.Certificate) error { + if len(verifiedChains) == 0 || len(verifiedChains[0]) == 0 { + return nil + } + + certificate, err := x509.ParseCertificate(rawCerts[0]) + if err != nil { + return fmt.Errorf("failed to parse peer certificate: %v", err) + } + + CNs, err := caManager.GetCNs() + if err != nil { + log.Log.Reason(err).Error(serverNotReadyMsg) + return fmt.Errorf(serverNotReadyMsg) + } + + if len(CNs) == 0 { + return nil + } + for _, CN := range CNs { + if certificate.Subject.CommonName == CN { + return nil + } + } + + return fmt.Errorf("Common name is invalid") + }, } config.BuildNameToCertificate()
pkg/util/tls/tls_test.go+25 −2 modified@@ -31,6 +31,7 @@ import ( type mockCAManager struct { caBundle []byte + cns []string } type mockCertManager struct { @@ -66,9 +67,13 @@ func (m *mockCAManager) GetCurrentRaw() ([]byte, error) { return nil, fmt.Errorf("not implemented") } +func (m *mockCAManager) GetCNs() ([]string, error) { + return m.cns, nil +} + var _ = Describe("TLS", func() { - var caManager kvtls.ClientCAManager + var caManager kvtls.KubernetesCAManager var certmanagers map[string]certificate.Manager var clusterConfig *virtconfig.ClusterConfig var kubeVirtStore cache.Store @@ -220,7 +225,8 @@ var _ = Describe("TLS", func() { }), ) - DescribeTable("should verify self-signed client and server certificates", func(serverSecret, clientSecret string, errStr string) { + DescribeTable("should verify self-signed client and server certificates", func(serverSecret, clientSecret, errStr string, cns []string) { + caManager.(*mockCAManager).cns = cns serverTLSConfig := kvtls.SetupTLSWithCertManager(caManager, certmanagers[serverSecret], tls.RequireAndVerifyClientCert, clusterConfig) clientTLSConfig := kvtls.SetupTLSForVirtHandlerClients(caManager, certmanagers[clientSecret], false) srv := httptest.NewUnstartedServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { @@ -248,18 +254,35 @@ var _ = Describe("TLS", func() { components.VirtHandlerServerCertSecretName, components.VirtHandlerCertSecretName, "", + []string{"kubevirt.io:system:client:virt-handler"}, + ), + Entry( + "connect with proper certificates with no CN auth", + components.VirtHandlerServerCertSecretName, + components.VirtHandlerCertSecretName, + "", + []string{}, + ), + Entry( + "fail if client uses an invalid certificates (CN)", + components.VirtHandlerServerCertSecretName, + components.VirtHandlerCertSecretName, + "remote error: tls: bad certificate", + []string{"kubevirt.io:system:clientv2:virt-handler"}, ), Entry( "fail if client uses an invalid certificate", components.VirtHandlerServerCertSecretName, components.VirtHandlerServerCertSecretName, "remote error: tls: bad certificate", + []string{"kubevirt.io:system:client:virt-handler"}, ), Entry( "fail if server uses an invalid certificate", components.VirtHandlerCertSecretName, components.VirtHandlerCertSecretName, "x509: certificate specifies an incompatible key usage", + []string{"kubevirt.io:system:client:virt-handler"}, ), )
pkg/virt-api/api.go+1 −1 modified@@ -960,7 +960,7 @@ func (app *virtAPIApp) registerMutatingWebhook(informers *webhooks.Informers) { }) } -func (app *virtAPIApp) setupTLS(k8sCAManager kvtls.ClientCAManager, kubevirtCAManager kvtls.ClientCAManager) { +func (app *virtAPIApp) setupTLS(k8sCAManager kvtls.KubernetesCAManager, kubevirtCAManager kvtls.ClientCAManager) { // A VerifyClientCertIfGiven request means we're not guaranteed // a client has been authenticated unless they provide a peer
Vulnerability mechanics
Generated by null/stub on May 9, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.
References
6- github.com/advisories/GHSA-38jw-g2qx-4286ghsaADVISORY
- nvd.nist.gov/vuln/detail/CVE-2025-64432ghsaADVISORY
- github.com/kubevirt/kubevirt/commit/231dc69723f331dc02f65a31ab4c3d6869f40d6aghsax_refsource_MISCWEB
- github.com/kubevirt/kubevirt/commit/af2f08a9a186eccc650f87c30ab3e07b669e8b5bghsax_refsource_MISCWEB
- github.com/kubevirt/kubevirt/commit/b9773bc588e6e18ece896a2dad5336ef7a653074ghsax_refsource_MISCWEB
- github.com/kubevirt/kubevirt/security/advisories/GHSA-38jw-g2qx-4286ghsax_refsource_CONFIRMWEB
News mentions
0No linked articles in our index yet.