Skip to content

Commit cb7083d

Browse files
committed
use dynamic serving cert controller
1 parent d06ad4c commit cb7083d

File tree

1 file changed

+19
-71
lines changed

1 file changed

+19
-71
lines changed

pkg/cvo/metrics.go

Lines changed: 19 additions & 71 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@ package cvo
33
import (
44
"context"
55
"crypto/tls"
6-
"crypto/x509"
76
"errors"
87
"fmt"
98
"net"
@@ -211,13 +210,13 @@ func RunMetrics(runContext context.Context, shutdownContext context.Context, lis
211210
}
212211

213212
// Create a dynamic serving cert/key controller to watch for serving certificate changes from files.
214-
servingCertController, err := dynamiccertificates.NewDynamicServingContentFromFiles("metrics-serving-cert", certFile, keyFile)
213+
servingContentController, err := dynamiccertificates.NewDynamicServingContentFromFiles("metrics-serving-cert", certFile, keyFile)
215214
if err != nil {
216215
return fmt.Errorf("failed to create serving certificate controller: %w", err)
217216
}
218217

219218
// Start the serving cert controller to begin watching the cert and key files
220-
go servingCertController.Run(runContext, 1)
219+
go servingContentController.Run(runContext, 1)
221220

222221
// Create a dynamic CA controller to watch for client CA changes from a ConfigMap.
223222
kubeClient, err := kubernetes.NewForConfig(restConfig)
@@ -238,19 +237,30 @@ func RunMetrics(runContext context.Context, shutdownContext context.Context, lis
238237
// Start the client CA controller to begin watching the ConfigMap
239238
go clientCAController.Run(runContext, 1)
240239

241-
// Create TLS config using the controllers. The config uses callbacks to dynamically
242-
// fetch the latest certificates and CA bundles on each connection, so no server
243-
// restart is needed when certificates change.
244-
tlsConfig, err := makeTLSConfig(servingCertController, clientCAController)
245-
if err != nil {
246-
return fmt.Errorf("failed to create TLS config: %w", err)
240+
servingCertController := dynamiccertificates.NewDynamicServingCertificateController(
241+
crypto.SecureTLSConfig(&tls.Config{
242+
ClientAuth: tls.RequireAndVerifyClientCert,
243+
}),
244+
clientCAController,
245+
servingContentController,
246+
nil,
247+
nil,
248+
)
249+
if err := servingCertController.RunOnce(); err != nil {
250+
return fmt.Errorf("failed to initialize serving certificate controller: %w", err)
247251
}
248252

253+
clientCAController.AddListener(servingCertController)
254+
servingContentController.AddListener(servingCertController)
255+
256+
go servingCertController.Run(1, runContext.Done())
257+
249258
server := createHttpServer(disableMetricsAuth)
250259

251260
resultChannel := make(chan asyncResult, 1)
252261
resultChannelCount := 1
253262

263+
tlsConfig := &tls.Config{GetConfigForClient: servingCertController.GetConfigForClient}
254264
go startListening(server, tlsConfig, listenAddress, resultChannel)
255265

256266
// Wait for server to exit or shutdown signal
@@ -608,65 +618,3 @@ func mostRecentTimestamp(cv *configv1.ClusterVersion) int64 {
608618
}
609619
return latest.Unix()
610620
}
611-
612-
func makeTLSConfig(servingCertController dynamiccertificates.CertKeyContentProvider, clientCAController dynamiccertificates.CAContentProvider) (*tls.Config, error) {
613-
// Get the current certificate and key content from the controller for validation.
614-
_, err := tls.X509KeyPair(servingCertController.CurrentCertKeyContent())
615-
if err != nil {
616-
return nil, fmt.Errorf("failed to create X509 key pair: %w", err)
617-
}
618-
619-
tlsConfig := crypto.SecureTLSConfig(&tls.Config{
620-
GetCertificate: func(_ *tls.ClientHelloInfo) (*tls.Certificate, error) {
621-
// Always get the latest certificate from the controller on each TLS handshake.
622-
// This ensures that certificate rotations are picked up immediately without server restart.
623-
cert, err := tls.X509KeyPair(servingCertController.CurrentCertKeyContent())
624-
if err != nil {
625-
// SECURITY: Never return a stale/cached certificate on error.
626-
// Fail the connection rather than risk using an expired or invalid certificate.
627-
klog.Errorf("Failed to load current serving certificate, rejecting connection: %v", err)
628-
return nil, fmt.Errorf("invalid serving certificate: %w", err)
629-
}
630-
return &cert, nil
631-
},
632-
GetConfigForClient: func(_ *tls.ClientHelloInfo) (*tls.Config, error) {
633-
// Create a fresh config with the latest CA bundle for each client connection.
634-
// This ensures CA bundle updates are picked up immediately without server restart.
635-
caBundle := clientCAController.CurrentCABundleContent()
636-
if len(caBundle) == 0 {
637-
// SECURITY: If CA bundle is not available, reject connections.
638-
// This enforces mTLS and prevents the server from operating in an insecure mode.
639-
klog.Errorf("No client CA bundle available, rejecting connection to enforce mTLS")
640-
return nil, fmt.Errorf("client CA bundle not available")
641-
}
642-
643-
certPool := x509.NewCertPool()
644-
if !certPool.AppendCertsFromPEM(caBundle) {
645-
// SECURITY: If CA bundle is present but invalid, reject the connection.
646-
// This prevents a downgrade attack where corrupted CA data disables mTLS.
647-
klog.Errorf("Failed to parse client CA bundle, rejecting connection to enforce mTLS")
648-
return nil, fmt.Errorf("invalid client CA bundle")
649-
}
650-
651-
return &tls.Config{
652-
ClientCAs: certPool,
653-
ClientAuth: tls.RequireAndVerifyClientCert,
654-
}, nil
655-
},
656-
})
657-
658-
// Log the initial mTLS state
659-
caBundle := clientCAController.CurrentCABundleContent()
660-
if len(caBundle) > 0 {
661-
certPool := x509.NewCertPool()
662-
if certPool.AppendCertsFromPEM(caBundle) {
663-
klog.Infof("Configured mTLS with dynamic client CA verification")
664-
} else {
665-
klog.Warningf("Client CA bundle present but invalid, mTLS will reject all connections until fixed")
666-
}
667-
} else {
668-
klog.Warningf("No client CA bundle available yet, mTLS will reject all connections until ConfigMap is created")
669-
}
670-
671-
return tlsConfig, nil
672-
}

0 commit comments

Comments
 (0)