From 54d6a152df1820fc348c526e41c63f1dee252db7 Mon Sep 17 00:00:00 2001 From: Alex Kalenyuk Date: Wed, 11 May 2022 17:30:55 +0300 Subject: [PATCH] Allow TLS config to be entirely configured on webhook server Some operators might want to respect cluster-wide TLS ciphers for example, which means that these will eventually have to be passed down to the webhook server. Signed-off-by: Alex Kalenyuk --- pkg/webhook/server.go | 8 +++++++ pkg/webhook/server_test.go | 43 +++++++++++++++++++++++++++++++++++++- 2 files changed, 50 insertions(+), 1 deletion(-) diff --git a/pkg/webhook/server.go b/pkg/webhook/server.go index 5bdc847e17..fa56be5d55 100644 --- a/pkg/webhook/server.go +++ b/pkg/webhook/server.go @@ -76,6 +76,9 @@ type Server struct { // "", "1.0", "1.1", "1.2" and "1.3" only ("" is equivalent to "1.0" for backwards compatibility) TLSMinVersion string + // TLSOpts is used to allow configuring the TLS config used for the server + TLSOpts []func(*tls.Config) + // WebhookMux is the multiplexer that handles different webhooks. WebhookMux *http.ServeMux @@ -254,6 +257,11 @@ func (s *Server) Start(ctx context.Context) error { cfg.ClientAuth = tls.RequireAndVerifyClientCert } + // fallback TLS config ready, will now mutate if passer wants full control over it + for _, op := range s.TLSOpts { + op(cfg) + } + listener, err := tls.Listen("tcp", net.JoinHostPort(s.Host, strconv.Itoa(s.Port)), cfg) if err != nil { return err diff --git a/pkg/webhook/server_test.go b/pkg/webhook/server_test.go index 2ed986e405..5e77564194 100644 --- a/pkg/webhook/server_test.go +++ b/pkg/webhook/server_test.go @@ -18,6 +18,7 @@ package webhook_test import ( "context" + "crypto/tls" "fmt" "io" "net" @@ -186,7 +187,7 @@ var _ = Describe("Webhook Server", func() { }) }) - It("should serve be able to serve in unmanaged mode", func() { + It("should be able to serve in unmanaged mode", func() { server = &webhook.Server{ Host: servingOpts.LocalServingHost, Port: servingOpts.LocalServingPort, @@ -207,6 +208,46 @@ var _ = Describe("Webhook Server", func() { ctxCancel() Eventually(doneCh, "4s").Should(BeClosed()) }) + + It("should respect passed in TLS configurations", func() { + var finalCfg *tls.Config + tlsCfgFunc := func(cfg *tls.Config) { + cfg.CipherSuites = []uint16{ + tls.TLS_AES_128_GCM_SHA256, + tls.TLS_AES_256_GCM_SHA384, + } + // save cfg after changes to test against + finalCfg = cfg + } + server = &webhook.Server{ + Host: servingOpts.LocalServingHost, + Port: servingOpts.LocalServingPort, + CertDir: servingOpts.LocalServingCertDir, + TLSMinVersion: "1.2", + TLSOpts: []func(*tls.Config){ + tlsCfgFunc, + }, + } + server.Register("/somepath", &testHandler{}) + doneCh := genericStartServer(func(ctx context.Context) { + Expect(server.StartStandalone(ctx, scheme.Scheme)) + }) + + Eventually(func() ([]byte, error) { + resp, err := client.Get(fmt.Sprintf("https://%s/somepath", testHostPort)) + Expect(err).NotTo(HaveOccurred()) + defer resp.Body.Close() + return io.ReadAll(resp.Body) + }).Should(Equal([]byte("gadzooks!"))) + Expect(finalCfg.MinVersion).To(Equal(uint16(tls.VersionTLS12))) + Expect(finalCfg.CipherSuites).To(ContainElements( + tls.TLS_AES_128_GCM_SHA256, + tls.TLS_AES_256_GCM_SHA384, + )) + + ctxCancel() + Eventually(doneCh, "4s").Should(BeClosed()) + }) }) type testHandler struct {