Skip to content

Commit eafe635

Browse files
cahillsfclaude
andcommitted
wire certwatcher for dynamic client TLS cert reloading
Emissary rotates TLS certs on disk via atomic symlink swaps, but Crossplane's client mTLS config was loaded once at startup. This adds a controller-runtime certwatcher to dynamically reload client certs and CA on rotation, eliminating the need for manual rollout restarts. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1 parent e9f498b commit eafe635

1 file changed

Lines changed: 28 additions & 0 deletions

File tree

cmd/crossplane/core/core.go

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ package core
2020
import (
2121
"context"
2222
"crypto/tls"
23+
"crypto/x509"
2324
"fmt"
2425
"io"
2526
"os"
@@ -40,6 +41,7 @@ import (
4041
"k8s.io/client-go/tools/record"
4142
ctrl "sigs.k8s.io/controller-runtime"
4243
"sigs.k8s.io/controller-runtime/pkg/cache"
44+
"sigs.k8s.io/controller-runtime/pkg/certwatcher"
4345
"sigs.k8s.io/controller-runtime/pkg/client"
4446
"sigs.k8s.io/controller-runtime/pkg/healthz"
4547
metricsserver "sigs.k8s.io/controller-runtime/pkg/metrics/server"
@@ -307,6 +309,32 @@ func (c *startCommand) Run(s *runtime.Scheme, log logging.Logger) error { //noli
307309
return errors.Wrap(err, "cannot load client TLS certificates")
308310
}
309311

312+
clientCertWatcher, err := certwatcher.New(
313+
filepath.Join(c.TLSClientCertsDir, c.TLSClientCertFileName),
314+
filepath.Join(c.TLSClientCertsDir, c.TLSClientKeyFileName),
315+
)
316+
if err != nil {
317+
return errors.Wrap(err, "cannot create client certificate watcher")
318+
}
319+
clienttls.GetClientCertificate = func(_ *tls.CertificateRequestInfo) (*tls.Certificate, error) {
320+
return clientCertWatcher.GetCertificate(nil)
321+
}
322+
caPath := filepath.Join(c.TLSClientCertsDir, c.TLSClientCACertFileName)
323+
clientCertWatcher.RegisterCallback(func(_ tls.Certificate) {
324+
ca, err := os.ReadFile(filepath.Clean(caPath))
325+
if err != nil {
326+
log.Debug("Cannot reload CA certificate", "error", err)
327+
return
328+
}
329+
pool := x509.NewCertPool()
330+
if pool.AppendCertsFromPEM(ca) {
331+
clienttls.RootCAs = pool
332+
}
333+
})
334+
if err := mgr.Add(clientCertWatcher); err != nil {
335+
return errors.Wrap(err, "cannot add client certificate watcher to manager")
336+
}
337+
310338
pfrm := xfn.NewPrometheusMetrics()
311339
metrics.Registry.MustRegister(pfrm)
312340

0 commit comments

Comments
 (0)