diff --git a/CHANGELOG.md b/CHANGELOG.md index de0b5ebec20..e435a97fbb7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -68,6 +68,7 @@ Here is an overview of all new **experimental** features: ### Improvements +- **General**: Allow configuring minimum TLS version for GRPC client via `KEDA_GRPC_MIN_TLS_VERSION` ([#6320](https://github.com/kedacore/keda/pull/6320)) - TODO ([#XXX](https://github.com/kedacore/keda/issues/XXX)) ### Fixes diff --git a/pkg/common/tls/tls.go b/pkg/common/tls/tls.go new file mode 100644 index 00000000000..1af38f1edea --- /dev/null +++ b/pkg/common/tls/tls.go @@ -0,0 +1,54 @@ +package tls + +import ( + ctls "crypto/tls" + "fmt" + "os" +) + +type tlsVersion string + +const ( + TLS10 tlsVersion = "TLS10" + TLS11 tlsVersion = "TLS11" + TLS12 tlsVersion = "TLS12" + TLS13 tlsVersion = "TLS13" +) + +type tlsEnvVariableName string + +const ( + minHTTPTLSVersionEnv tlsEnvVariableName = "KEDA_HTTP_MIN_TLS_VERSION" + minGrpcTLSVersionEnv tlsEnvVariableName = "KEDA_GRPC_MIN_TLS_VERSION" +) + +const ( + defaultMinHTTPTLSVersion = TLS12 + defaultMinGrpcTLSVersion = TLS13 +) + +func getMinTLSVersion(envKey tlsEnvVariableName, defaultVal tlsVersion) (uint16, error) { + version := string(defaultVal) + if val, ok := os.LookupEnv(string(envKey)); ok { + version = val + } + mapping := map[string]uint16{ + string(TLS10): ctls.VersionTLS10, + string(TLS11): ctls.VersionTLS11, + string(TLS12): ctls.VersionTLS12, + string(TLS13): ctls.VersionTLS13, + } + if v, ok := mapping[version]; ok { + return v, nil + } + fallback := mapping[string(defaultVal)] + return fallback, fmt.Errorf("invalid TLS version: %s, using %s", version, defaultVal) +} + +func GetMinHTTPTLSVersion() (uint16, error) { + return getMinTLSVersion(minHTTPTLSVersionEnv, defaultMinHTTPTLSVersion) +} + +func GetMinGrpcTLSVersion() (uint16, error) { + return getMinTLSVersion(minGrpcTLSVersionEnv, defaultMinGrpcTLSVersion) +} diff --git a/pkg/common/tls/tls_test.go b/pkg/common/tls/tls_test.go new file mode 100644 index 00000000000..b1a5d849e59 --- /dev/null +++ b/pkg/common/tls/tls_test.go @@ -0,0 +1,81 @@ +package tls + +import ( + "crypto/tls" + "fmt" + "os" + "testing" +) + +type minTLSVersionTestData struct { + name string + envSet bool + envValue string + expectedVersion uint16 + shouldError bool +} + +var minTLSVersionTestDatas = []minTLSVersionTestData{ + { + name: "Set to TLS10", + envSet: true, + envValue: "TLS10", + expectedVersion: tls.VersionTLS10, + }, + { + name: "Set to TLS11", + envSet: true, + envValue: "TLS11", + expectedVersion: tls.VersionTLS11, + }, + { + name: "Set to TLS12", + envSet: true, + envValue: "TLS12", + expectedVersion: tls.VersionTLS12, + }, + { + name: "Set to TLS13", + envSet: true, + envValue: "TLS13", + expectedVersion: tls.VersionTLS13, + }, + { + name: "No setting", + envSet: false, + }, + { + name: "Invalid settings", + envSet: true, + envValue: "TLS9", + shouldError: true, + }, +} + +func testResolveMinTLSVersion(t *testing.T, minVersionFunc func() (uint16, error), envName string, defaultVersion uint16) { + defer os.Unsetenv(envName) + for _, testData := range minTLSVersionTestDatas { + name := fmt.Sprintf("%s: %s", envName, testData.name) + t.Run(name, func(t *testing.T) { + os.Unsetenv(envName) + expectedVersion := defaultVersion + if testData.expectedVersion != 0 { + expectedVersion = testData.expectedVersion + } + if testData.envSet { + os.Setenv(envName, testData.envValue) + } + minVersion, err := minVersionFunc() + if testData.shouldError && err == nil { + t.Error("Expected error but got none") + } + if expectedVersion != minVersion { + t.Error("Failed to resolve minTLSVersion correctly", "wants", testData.expectedVersion, "got", minVersion) + } + }) + } +} +func TestResolveMinTLSVersion(t *testing.T) { + testResolveMinTLSVersion(t, GetMinHTTPTLSVersion, "KEDA_HTTP_MIN_TLS_VERSION", tls.VersionTLS12) + testResolveMinTLSVersion(t, GetMinGrpcTLSVersion, "KEDA_GRPC_MIN_TLS_VERSION", tls.VersionTLS13) +} diff --git a/pkg/metricsservice/utils/tls.go b/pkg/metricsservice/utils/tls.go index 3cc72ddf159..b866f7d2103 100644 --- a/pkg/metricsservice/utils/tls.go +++ b/pkg/metricsservice/utils/tls.go @@ -24,6 +24,9 @@ import ( "path" "google.golang.org/grpc/credentials" + ctrl "sigs.k8s.io/controller-runtime" + + kedatls "github.com/kedacore/keda/v2/pkg/common/tls" ) // LoadGrpcTLSCredentials reads the certificate from the given path and returns TLS transport credentials @@ -50,8 +53,12 @@ func LoadGrpcTLSCredentials(certDir string, server bool) (credentials.TransportC } // Create the credentials and return it + minTLSVersion, err := kedatls.GetMinGrpcTLSVersion() + if err != nil { + ctrl.Log.WithName("grpc_tls_setup").Info(err.Error()) + } config := &tls.Config{ - MinVersion: tls.VersionTLS13, + MinVersion: minTLSVersion, Certificates: []tls.Certificate{cert}, } if server { diff --git a/pkg/util/tls_config.go b/pkg/util/tls_config.go index fd1cdb11345..49fd35b03c1 100644 --- a/pkg/util/tls_config.go +++ b/pkg/util/tls_config.go @@ -21,10 +21,11 @@ import ( "crypto/x509" "encoding/pem" "fmt" - "os" "github.com/youmark/pkcs8" ctrl "sigs.k8s.io/controller-runtime" + + kedatls "github.com/kedacore/keda/v2/pkg/common/tls" ) var minTLSVersion uint16 @@ -89,24 +90,7 @@ func GetMinTLSVersion() uint16 { } func initMinTLSVersion() (uint16, error) { - version, _ := os.LookupEnv("KEDA_HTTP_MIN_TLS_VERSION") - - switch version { - case "": - minTLSVersion = tls.VersionTLS12 - case "TLS10": - minTLSVersion = tls.VersionTLS10 - case "TLS11": - minTLSVersion = tls.VersionTLS11 - case "TLS12": - minTLSVersion = tls.VersionTLS12 - case "TLS13": - minTLSVersion = tls.VersionTLS13 - default: - return tls.VersionTLS12, fmt.Errorf("%s is not a valid value, using `TLS12`. Allowed values are: `TLS13`,`TLS12`,`TLS11`,`TLS10`", version) - } - - return minTLSVersion, nil + return kedatls.GetMinHTTPTLSVersion() } func decryptClientKey(clientKey, clientKeyPassword string) ([]byte, error) { diff --git a/pkg/util/tls_config_test.go b/pkg/util/tls_config_test.go index 792965d80f0..1092a57282f 100644 --- a/pkg/util/tls_config_test.go +++ b/pkg/util/tls_config_test.go @@ -17,9 +17,7 @@ limitations under the License. package util import ( - "crypto/tls" "crypto/x509" - "os" "strings" "testing" ) @@ -252,51 +250,3 @@ func TestNewTLSConfig_WithPassword(t *testing.T) { }) } } - -type minTLSVersionTestData struct { - envSet bool - envValue string - expectedVersion uint16 -} - -var minTLSVersionTestDatas = []minTLSVersionTestData{ - { - envSet: true, - envValue: "TLS10", - expectedVersion: tls.VersionTLS10, - }, - { - envSet: true, - envValue: "TLS11", - expectedVersion: tls.VersionTLS11, - }, - { - envSet: true, - envValue: "TLS12", - expectedVersion: tls.VersionTLS12, - }, - { - envSet: true, - envValue: "TLS13", - expectedVersion: tls.VersionTLS13, - }, - { - envSet: false, - expectedVersion: tls.VersionTLS12, - }, -} - -func TestResolveMinTLSVersion(t *testing.T) { - defer os.Unsetenv("KEDA_HTTP_MIN_TLS_VERSION") - for _, testData := range minTLSVersionTestDatas { - os.Unsetenv("KEDA_HTTP_MIN_TLS_VERSION") - if testData.envSet { - os.Setenv("KEDA_HTTP_MIN_TLS_VERSION", testData.envValue) - } - minVersion, _ := initMinTLSVersion() - - if testData.expectedVersion != minVersion { - t.Error("Failed to resolve minTLSVersion correctly", "wants", testData.expectedVersion, "got", minVersion) - } - } -}