Skip to content

Commit

Permalink
Allow TLS ciphers to be 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,
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 12, 2022
1 parent 2f77235 commit 5dd273b
Show file tree
Hide file tree
Showing 2 changed files with 72 additions and 1 deletion.
31 changes: 31 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,10 @@ type Server struct {
// "", "1.0", "1.1", "1.2" and "1.3" only ("" is equivalent to "1.0" for backwards compatibility)
TLSMinVersion string

// TLSCiphers is used to specify the cipher algorithms that are negotiated
// during the TLS handshake, refer to https://pkg.go.dev/crypto/tls#CipherSuites
TLSCiphers []string

// WebhookMux is the multiplexer that handles different webhooks.
WebhookMux *http.ServeMux

Expand Down Expand Up @@ -204,6 +211,23 @@ func tlsVersion(version string) (uint16, error) {
}
}

// tlsCipherSuitesIDs converts cipher suite names
// to the values accepted by tls.Config (for example 0xc02b).
func tlsCipherSuitesIDs(names []string) []uint16 {
idByName := map[string]uint16{}
for _, cipherSuite := range tls.CipherSuites() {
idByName[cipherSuite.Name] = cipherSuite.ID
}

ids := []uint16{}
for _, name := range names {
if id, ok := idByName[name]; ok {
ids = append(ids, id)
}
}
return ids
}

// Start runs the server.
// It will install the webhook related resources depend on the server configuration.
func (s *Server) Start(ctx context.Context) error {
Expand Down Expand Up @@ -254,6 +278,13 @@ func (s *Server) Start(ctx context.Context) error {
cfg.ClientAuth = tls.RequireAndVerifyClientCert
}

// load passed in TLS ciphers
if s.TLSCiphers != nil {
cipherSuites := tlsCipherSuitesIDs(s.TLSCiphers)
cfg.CipherSuites = cipherSuites
}
ExportedTLSConfig = cfg

listener, err := tls.Listen("tcp", net.JoinHostPort(s.Host, strconv.Itoa(s.Port)), cfg)
if err != nil {
return err
Expand Down
42 changes: 41 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,45 @@ var _ = Describe("Webhook Server", func() {
ctxCancel()
Eventually(doneCh, "4s").Should(BeClosed())
})

It("should respect passed in TLS configurations", func() {
ciphers := []string{
"TLS_AES_128_GCM_SHA256",
"TLS_AES_256_GCM_SHA384",
"TLS_CHACHA20_POLY1305_SHA256",
"ECDHE-ECDSA-AES128-GCM-SHA256",
"ECDHE-RSA-AES128-GCM-SHA256",
"ECDHE-ECDSA-AES256-GCM-SHA384",
"ECDHE-RSA-AES256-GCM-SHA384",
"ECDHE-ECDSA-CHACHA20-POLY1305",
"ECDHE-RSA-CHACHA20-POLY1305",
"DHE-RSA-AES128-GCM-SHA256",
"DHE-RSA-AES256-GCM-SHA384",
}
server = &webhook.Server{
Host: servingOpts.LocalServingHost,
Port: servingOpts.LocalServingPort,
CertDir: servingOpts.LocalServingCertDir,
TLSMinVersion: "1.2",
TLSCiphers: ciphers,
}
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(ContainElement(tls.TLS_AES_128_GCM_SHA256))

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

type testHandler struct {
Expand Down

0 comments on commit 5dd273b

Please sign in to comment.