Skip to content

Commit

Permalink
Allow TLS config to be entirely configured on webhook server
Browse files Browse the repository at this point in the history
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 <akalenyu@redhat.com>
  • Loading branch information
akalenyu committed May 15, 2022
1 parent 3f265c3 commit 5cf5bf9
Show file tree
Hide file tree
Showing 2 changed files with 51 additions and 1 deletion.
12 changes: 12 additions & 0 deletions pkg/webhook/server.go
Expand Up @@ -41,6 +41,9 @@ import (
// DefaultPort is the default port that the webhook server serves.
var DefaultPort = 9443

// ExportedTLSConfig is used in unit tests to ensure propagation of tls related configurables to server.
var ExportedTLSConfig *tls.Config

// Server is an admission webhook server that can serve traffic and
// generates related k8s resources for deploying.
//
Expand Down Expand Up @@ -76,6 +79,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

Expand Down Expand Up @@ -254,6 +260,12 @@ 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)
}
ExportedTLSConfig = cfg

listener, err := tls.Listen("tcp", net.JoinHostPort(s.Host, strconv.Itoa(s.Port)), cfg)
if err != nil {
return err
Expand Down
40 changes: 39 additions & 1 deletion pkg/webhook/server_test.go
Expand Up @@ -18,6 +18,7 @@ package webhook_test

import (
"context"
"crypto/tls"
"fmt"
"io"
"net"
Expand Down Expand Up @@ -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,
Expand All @@ -207,6 +208,43 @@ var _ = Describe("Webhook Server", func() {
ctxCancel()
Eventually(doneCh, "4s").Should(BeClosed())
})

It("should respect passed in TLS configurations", func() {
tlsCfgFunc := func(cfg *tls.Config) {
cfg.CipherSuites = []uint16{
tls.TLS_AES_128_GCM_SHA256,
tls.TLS_AES_256_GCM_SHA384,
}
}
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(webhook.ExportedTLSConfig.MinVersion).To(Equal(uint16(tls.VersionTLS12)))
Expect(webhook.ExportedTLSConfig.CipherSuites).To(ContainElements(
tls.TLS_AES_128_GCM_SHA256,
tls.TLS_AES_256_GCM_SHA384,
))

ctxCancel()
Eventually(doneCh, "4s").Should(BeClosed())
})
})

type testHandler struct {
Expand Down

0 comments on commit 5cf5bf9

Please sign in to comment.