From 6d6be083046ed5cf34a939c3a0cff8b4e26c2d19 Mon Sep 17 00:00:00 2001 From: pebanb <6670593+pebanb@users.noreply.github.com> Date: Thu, 19 Mar 2026 13:49:44 +0100 Subject: [PATCH 1/2] Introducing configurable setting for tls 1.3. as min version --- internal/cmd/run.go | 1 + internal/server/config.go | 1 + internal/server/server.go | 13 +++++++++---- internal/server/server_test.go | 22 +++++++++++++++++----- internal/server/testing.go | 13 +++++++------ 5 files changed, 35 insertions(+), 15 deletions(-) diff --git a/internal/cmd/run.go b/internal/cmd/run.go index 0a70655e..2f907309 100644 --- a/internal/cmd/run.go +++ b/internal/cmd/run.go @@ -29,6 +29,7 @@ func newRunCommand() *runCommand { runCommand.cmd.Flags().IntVar(&globalConfig.HttpsPort, "https-port", getEnvInt("HTTPS_PORT", server.DefaultHttpsPort), "Port to serve HTTPS traffic on") runCommand.cmd.Flags().IntVar(&globalConfig.MetricsPort, "metrics-port", getEnvInt("METRICS_PORT", 0), "Publish metrics on the specified port (default zero to disable)") runCommand.cmd.Flags().BoolVar(&globalConfig.HTTP3Enabled, "http3", false, "Enable HTTP/3") + runCommand.cmd.Flags().BoolVar(&globalConfig.MinTLS13, "min-tls13", getEnvBool("MIN_TLS13", false), "Set TLS 1.3 as the minimum TLS version on the HTTPS server") return runCommand } diff --git a/internal/server/config.go b/internal/server/config.go index 03148253..941f856a 100644 --- a/internal/server/config.go +++ b/internal/server/config.go @@ -18,6 +18,7 @@ type Config struct { HttpsPort int MetricsPort int HTTP3Enabled bool + MinTLS13 bool AlternateConfigDir string } diff --git a/internal/server/server.go b/internal/server/server.go index 4b336de3..5d58d6ab 100644 --- a/internal/server/server.go +++ b/internal/server/server.go @@ -150,6 +150,14 @@ func (s *Server) startHTTPServers() error { return err } s.httpsListener = httpsListener + tlsConfig := &tls.Config{ + NextProtos: []string{"h2", "http/1.1", acme.ALPNProto}, + GetCertificate: s.router.GetCertificate, + } + if s.config.MinTLS13 { + tlsConfig.MinVersion = tls.VersionTLS13 + } + s.httpsServer = &http.Server{ Handler: http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { if s.config.HTTP3Enabled { @@ -158,10 +166,7 @@ func (s *Server) startHTTPServers() error { handler.ServeHTTP(w, r) }), - TLSConfig: &tls.Config{ - NextProtos: []string{"h2", "http/1.1", acme.ALPNProto}, - GetCertificate: s.router.GetCertificate, - }, + TLSConfig: tlsConfig, } go s.httpServer.Serve(s.httpListener) diff --git a/internal/server/server_test.go b/internal/server/server_test.go index 4792d3de..1c4af717 100644 --- a/internal/server/server_test.go +++ b/internal/server/server_test.go @@ -14,7 +14,7 @@ import ( func TestServer_Deploying(t *testing.T) { target := testTarget(t, func(w http.ResponseWriter, r *http.Request) {}) - server := testServer(t, true) + server := testServer(t, false, false) testDeployTarget(t, target, server, defaultServiceOptions) @@ -24,9 +24,9 @@ func TestServer_Deploying(t *testing.T) { } func TestServer_DeployingHTTPS(t *testing.T) { - startDeployment := func(http3Enabled bool) *Server { + startDeployment := func(http3Enabled bool, minTLS13 bool) *Server { target := testTarget(t, func(w http.ResponseWriter, r *http.Request) {}) - server := testServer(t, http3Enabled) + server := testServer(t, http3Enabled, minTLS13) certPath, keyPath := prepareTestCertificateFiles(t) serviceOptions := defaultServiceOptions @@ -40,7 +40,7 @@ func TestServer_DeployingHTTPS(t *testing.T) { } t.Run("with HTTP/3 enabled", func(t *testing.T) { - server := startDeployment(true) + server := startDeployment(true, false) t.Run("http/1.1", func(t *testing.T) { resp, err := testRequestUsingHTTP11(t, server) @@ -72,8 +72,20 @@ func TestServer_DeployingHTTPS(t *testing.T) { }) }) + t.Run("with min TLS 1.3", func(t *testing.T) { + server := startDeployment(false, true) + + t.Run("http/1.1", func(t *testing.T) { + resp, err := testRequestUsingHTTP11(t, server) + require.NoError(t, err) + assert.Equal(t, http.StatusOK, resp.StatusCode) + assert.Equal(t, "HTTP/1.1", resp.Proto) + assert.Equal(t, uint16(tls.VersionTLS13), resp.TLS.Version) + }) + }) + t.Run("with HTTP/3 disabled", func(t *testing.T) { - server := startDeployment(false) + server := startDeployment(false, false) t.Run("http/1.1", func(t *testing.T) { resp, err := testRequestUsingHTTP11(t, server) diff --git a/internal/server/testing.go b/internal/server/testing.go index 99d12f52..a2605cff 100644 --- a/internal/server/testing.go +++ b/internal/server/testing.go @@ -11,11 +11,11 @@ import ( ) var ( - defaultHealthCheckConfig = HealthCheckConfig{Path: DefaultHealthCheckPath, Port: DefaultHealthCheckPort, Interval: DefaultHealthCheckInterval, Timeout: time.Second * 5} - defaultEmptyReaders = []string{} - defaultServiceOptions = ServiceOptions{TLSRedirect: true} - defaultTargetOptions = TargetOptions{HealthCheckConfig: defaultHealthCheckConfig, ResponseTimeout: DefaultTargetTimeout} - defaultDeploymentOptions = DeploymentOptions{DeployTimeout: DefaultDeployTimeout, DrainTimeout: DefaultDrainTimeout, Force: false} + defaultHealthCheckConfig = HealthCheckConfig{Path: DefaultHealthCheckPath, Port: DefaultHealthCheckPort, Interval: DefaultHealthCheckInterval, Timeout: time.Second * 5} + defaultEmptyReaders = []string{} + defaultServiceOptions = ServiceOptions{TLSRedirect: true} + defaultTargetOptions = TargetOptions{HealthCheckConfig: defaultHealthCheckConfig, ResponseTimeout: DefaultTargetTimeout} + defaultDeploymentOptions = DeploymentOptions{DeployTimeout: DefaultDeployTimeout, DrainTimeout: DefaultDrainTimeout, Force: false} ) func testTarget(t testing.TB, handler http.HandlerFunc) *Target { @@ -69,7 +69,7 @@ func testBackendWithHandler(t testing.TB, handler http.HandlerFunc) (*httptest.S return server, serverURL.Host } -func testServer(t testing.TB, http3Enabled bool) *Server { +func testServer(t testing.TB, http3Enabled bool, minTLS13 bool) *Server { t.Helper() config := &Config{ @@ -78,6 +78,7 @@ func testServer(t testing.TB, http3Enabled bool) *Server { HttpsPort: 0, AlternateConfigDir: t.TempDir(), HTTP3Enabled: http3Enabled, + MinTLS13: minTLS13, } router := NewRouter(config.StatePath()) server := NewServer(config, router) From 46e80ae2b3db4c5401637497d7a3f354395e5cb7 Mon Sep 17 00:00:00 2001 From: Petar Banov Date: Thu, 26 Mar 2026 13:27:20 +0100 Subject: [PATCH 2/2] adding a configuration option of min tls version --- internal/cmd/run.go | 2 +- internal/cmd/util.go | 9 +++++++ internal/server/config.go | 2 +- internal/server/server.go | 13 ++++++++- internal/server/server_test.go | 48 +++++++++++++++++++++++++++++----- internal/server/testing.go | 4 +-- 6 files changed, 67 insertions(+), 11 deletions(-) diff --git a/internal/cmd/run.go b/internal/cmd/run.go index 2f907309..96b40049 100644 --- a/internal/cmd/run.go +++ b/internal/cmd/run.go @@ -29,7 +29,7 @@ func newRunCommand() *runCommand { runCommand.cmd.Flags().IntVar(&globalConfig.HttpsPort, "https-port", getEnvInt("HTTPS_PORT", server.DefaultHttpsPort), "Port to serve HTTPS traffic on") runCommand.cmd.Flags().IntVar(&globalConfig.MetricsPort, "metrics-port", getEnvInt("METRICS_PORT", 0), "Publish metrics on the specified port (default zero to disable)") runCommand.cmd.Flags().BoolVar(&globalConfig.HTTP3Enabled, "http3", false, "Enable HTTP/3") - runCommand.cmd.Flags().BoolVar(&globalConfig.MinTLS13, "min-tls13", getEnvBool("MIN_TLS13", false), "Set TLS 1.3 as the minimum TLS version on the HTTPS server") + runCommand.cmd.Flags().StringVar(&globalConfig.MinTLS, "min-tls", getEnvString("MIN_TLS", ""), "Set minimum TLS version (tls1_0, tls1_1, tls1_2, tls1_3)") return runCommand } diff --git a/internal/cmd/util.go b/internal/cmd/util.go index d28618c6..fc53414c 100644 --- a/internal/cmd/util.go +++ b/internal/cmd/util.go @@ -47,6 +47,15 @@ func getEnvInt(key string, defaultValue int) int { return intValue } +func getEnvString(key string, defaultValue string) string { + value, ok := findEnv(key) + if !ok { + return defaultValue + } + + return value +} + func getEnvBool(key string, defaultValue bool) bool { value, ok := findEnv(key) if !ok { diff --git a/internal/server/config.go b/internal/server/config.go index 941f856a..346427a0 100644 --- a/internal/server/config.go +++ b/internal/server/config.go @@ -18,7 +18,7 @@ type Config struct { HttpsPort int MetricsPort int HTTP3Enabled bool - MinTLS13 bool + MinTLS string AlternateConfigDir string } diff --git a/internal/server/server.go b/internal/server/server.go index 5d58d6ab..7fde7ea5 100644 --- a/internal/server/server.go +++ b/internal/server/server.go @@ -154,8 +154,19 @@ func (s *Server) startHTTPServers() error { NextProtos: []string{"h2", "http/1.1", acme.ALPNProto}, GetCertificate: s.router.GetCertificate, } - if s.config.MinTLS13 { + switch s.config.MinTLS { + case "tls1_0": + tlsConfig.MinVersion = tls.VersionTLS10 + case "tls1_1": + tlsConfig.MinVersion = tls.VersionTLS11 + case "tls1_2": + tlsConfig.MinVersion = tls.VersionTLS12 + case "tls1_3": tlsConfig.MinVersion = tls.VersionTLS13 + case "": + // No minimum TLS version set + default: + return fmt.Errorf("unsupported minimum TLS version: %q (use tls1_0, tls1_1, tls1_2, or tls1_3)", s.config.MinTLS) } s.httpsServer = &http.Server{ diff --git a/internal/server/server_test.go b/internal/server/server_test.go index 1c4af717..e95b9efe 100644 --- a/internal/server/server_test.go +++ b/internal/server/server_test.go @@ -14,7 +14,7 @@ import ( func TestServer_Deploying(t *testing.T) { target := testTarget(t, func(w http.ResponseWriter, r *http.Request) {}) - server := testServer(t, false, false) + server := testServer(t, false, "") testDeployTarget(t, target, server, defaultServiceOptions) @@ -24,9 +24,9 @@ func TestServer_Deploying(t *testing.T) { } func TestServer_DeployingHTTPS(t *testing.T) { - startDeployment := func(http3Enabled bool, minTLS13 bool) *Server { + startDeployment := func(http3Enabled bool, minTLS string) *Server { target := testTarget(t, func(w http.ResponseWriter, r *http.Request) {}) - server := testServer(t, http3Enabled, minTLS13) + server := testServer(t, http3Enabled, minTLS) certPath, keyPath := prepareTestCertificateFiles(t) serviceOptions := defaultServiceOptions @@ -40,7 +40,7 @@ func TestServer_DeployingHTTPS(t *testing.T) { } t.Run("with HTTP/3 enabled", func(t *testing.T) { - server := startDeployment(true, false) + server := startDeployment(true, "") t.Run("http/1.1", func(t *testing.T) { resp, err := testRequestUsingHTTP11(t, server) @@ -72,8 +72,44 @@ func TestServer_DeployingHTTPS(t *testing.T) { }) }) + t.Run("with min TLS 1.0", func(t *testing.T) { + server := startDeployment(false, "tls1_0") + + t.Run("http/1.1", func(t *testing.T) { + resp, err := testRequestUsingHTTP11(t, server) + require.NoError(t, err) + assert.Equal(t, http.StatusOK, resp.StatusCode) + assert.Equal(t, "HTTP/1.1", resp.Proto) + assert.GreaterOrEqual(t, resp.TLS.Version, uint16(tls.VersionTLS10)) + }) + }) + + t.Run("with min TLS 1.1", func(t *testing.T) { + server := startDeployment(false, "tls1_1") + + t.Run("http/1.1", func(t *testing.T) { + resp, err := testRequestUsingHTTP11(t, server) + require.NoError(t, err) + assert.Equal(t, http.StatusOK, resp.StatusCode) + assert.Equal(t, "HTTP/1.1", resp.Proto) + assert.GreaterOrEqual(t, resp.TLS.Version, uint16(tls.VersionTLS11)) + }) + }) + + t.Run("with min TLS 1.2", func(t *testing.T) { + server := startDeployment(false, "tls1_2") + + t.Run("http/1.1", func(t *testing.T) { + resp, err := testRequestUsingHTTP11(t, server) + require.NoError(t, err) + assert.Equal(t, http.StatusOK, resp.StatusCode) + assert.Equal(t, "HTTP/1.1", resp.Proto) + assert.GreaterOrEqual(t, resp.TLS.Version, uint16(tls.VersionTLS12)) + }) + }) + t.Run("with min TLS 1.3", func(t *testing.T) { - server := startDeployment(false, true) + server := startDeployment(false, "tls1_3") t.Run("http/1.1", func(t *testing.T) { resp, err := testRequestUsingHTTP11(t, server) @@ -85,7 +121,7 @@ func TestServer_DeployingHTTPS(t *testing.T) { }) t.Run("with HTTP/3 disabled", func(t *testing.T) { - server := startDeployment(false, false) + server := startDeployment(false, "") t.Run("http/1.1", func(t *testing.T) { resp, err := testRequestUsingHTTP11(t, server) diff --git a/internal/server/testing.go b/internal/server/testing.go index a2605cff..40bc7b5f 100644 --- a/internal/server/testing.go +++ b/internal/server/testing.go @@ -69,7 +69,7 @@ func testBackendWithHandler(t testing.TB, handler http.HandlerFunc) (*httptest.S return server, serverURL.Host } -func testServer(t testing.TB, http3Enabled bool, minTLS13 bool) *Server { +func testServer(t testing.TB, http3Enabled bool, minTLS string) *Server { t.Helper() config := &Config{ @@ -78,7 +78,7 @@ func testServer(t testing.TB, http3Enabled bool, minTLS13 bool) *Server { HttpsPort: 0, AlternateConfigDir: t.TempDir(), HTTP3Enabled: http3Enabled, - MinTLS13: minTLS13, + MinTLS: minTLS, } router := NewRouter(config.StatePath()) server := NewServer(config, router)