diff --git a/CHANGELOG.md b/CHANGELOG.md index cd7b479b010..19798d155e0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -62,6 +62,7 @@ Here is an overview of all new **experimental** features: - **General**: Add a warning when KEDA run outside supported k8s versions ([#4130](https://github.com/kedacore/keda/issues/4130)) - **General**: Use (self-signed) certificates for all the communications (internals and externals) ([#3931](https://github.com/kedacore/keda/issues/3931)) +- **General**: Use TLS1.2 as minimum TLS version ([#4193](https://github.com/kedacore/keda/issues/4193)) - **Azure Pipelines Scaler**: Improve error logging for `validatePoolID` ([#3996](https://github.com/kedacore/keda/issues/3996)) - **Hashicorp Vault**: Add support to secrets backend version 1 ([#2645](https://github.com/kedacore/keda/issues/2645)) - **RabbitMQ Scaler**: Add TLS support ([#967](https://github.com/kedacore/keda/issues/967)) diff --git a/pkg/scalers/authentication/authentication_helpers.go b/pkg/scalers/authentication/authentication_helpers.go index 6ecf5c315a5..db5c9d8a49f 100644 --- a/pkg/scalers/authentication/authentication_helpers.go +++ b/pkg/scalers/authentication/authentication_helpers.go @@ -94,7 +94,10 @@ func NewTLSConfig(auth *AuthMeta) (*tls.Config, error) { } func CreateHTTPRoundTripper(roundTripperType TransportType, auth *AuthMeta, conf ...*HTTPTransport) (rt http.RoundTripper, err error) { - tlsConfig := &tls.Config{InsecureSkipVerify: false} + tlsConfig := &tls.Config{ + MinVersion: kedautil.GetMinTLSVersion(), + InsecureSkipVerify: false, + } if auth != nil && (auth.CA != "" || auth.EnableTLS) { tlsConfig, err = NewTLSConfig(auth) if err != nil || tlsConfig == nil { diff --git a/pkg/scalers/elasticsearch_scaler.go b/pkg/scalers/elasticsearch_scaler.go index 25a64dee38a..73c3cc22788 100644 --- a/pkg/scalers/elasticsearch_scaler.go +++ b/pkg/scalers/elasticsearch_scaler.go @@ -244,7 +244,10 @@ func newElasticsearchClient(meta *elasticsearchMetadata, logger logr.Logger) (*e } transport := http.DefaultTransport.(*http.Transport) - transport.TLSClientConfig = &tls.Config{InsecureSkipVerify: meta.unsafeSsl} + transport.TLSClientConfig = &tls.Config{ + MinVersion: kedautil.GetMinTLSVersion(), + InsecureSkipVerify: meta.unsafeSsl, + } config.Transport = transport esClient, err := elasticsearch.NewClient(config) diff --git a/pkg/scalers/ibmmq_scaler.go b/pkg/scalers/ibmmq_scaler.go index 8ac90c9e70f..700a69e2161 100644 --- a/pkg/scalers/ibmmq_scaler.go +++ b/pkg/scalers/ibmmq_scaler.go @@ -179,7 +179,10 @@ func (s *IBMMQScaler) getQueueDepthViaHTTP(ctx context.Context) (int64, error) { req.SetBasicAuth(s.metadata.username, s.metadata.password) tr := &http.Transport{ - TLSClientConfig: &tls.Config{InsecureSkipVerify: s.metadata.tlsDisabled}, + TLSClientConfig: &tls.Config{ + MinVersion: kedautil.GetMinTLSVersion(), + InsecureSkipVerify: s.metadata.tlsDisabled, + }, } client := kedautil.CreateHTTPClient(s.defaultHTTPTimeout, false) client.Transport = tr diff --git a/pkg/scalers/influxdb_scaler.go b/pkg/scalers/influxdb_scaler.go index a9b5aff8837..6a3d605c948 100644 --- a/pkg/scalers/influxdb_scaler.go +++ b/pkg/scalers/influxdb_scaler.go @@ -52,7 +52,10 @@ func NewInfluxDBScaler(config *ScalerConfig) (Scaler, error) { client := influxdb2.NewClientWithOptions( meta.serverURL, meta.authToken, - influxdb2.DefaultOptions().SetTLSConfig(&tls.Config{InsecureSkipVerify: meta.unsafeSsl})) + influxdb2.DefaultOptions().SetTLSConfig(&tls.Config{ + MinVersion: kedautil.GetMinTLSVersion(), + InsecureSkipVerify: meta.unsafeSsl, + })) return &influxDBScaler{ client: client, diff --git a/pkg/scalers/predictkube_scaler.go b/pkg/scalers/predictkube_scaler.go index 7d67ffe7551..4ea7341a088 100644 --- a/pkg/scalers/predictkube_scaler.go +++ b/pkg/scalers/predictkube_scaler.go @@ -113,6 +113,7 @@ func (s *PredictKubeScaler) setupClientConn() error { if !grpcConf.Conn.Insecure { clientOpt = append(clientOpt, grpc.WithTransportCredentials( credentials.NewTLS(&tls.Config{ + MinVersion: kedautil.GetMinTLSVersion(), ServerName: mlEngineHost, }), )) diff --git a/pkg/scalers/redis_scaler.go b/pkg/scalers/redis_scaler.go index ca79d503e51..edc88a8f1f1 100644 --- a/pkg/scalers/redis_scaler.go +++ b/pkg/scalers/redis_scaler.go @@ -465,6 +465,7 @@ func getRedisClusterClient(ctx context.Context, info redisConnectionInfo) (*redi } if info.enableTLS { options.TLSConfig = &tls.Config{ + MinVersion: kedautil.GetMinTLSVersion(), InsecureSkipVerify: info.unsafeSsl, } } @@ -489,6 +490,7 @@ func getRedisSentinelClient(ctx context.Context, info redisConnectionInfo, dbInd } if info.enableTLS { options.TLSConfig = &tls.Config{ + MinVersion: kedautil.GetMinTLSVersion(), InsecureSkipVerify: info.unsafeSsl, } } @@ -510,6 +512,7 @@ func getRedisClient(ctx context.Context, info redisConnectionInfo, dbIndex int) } if info.enableTLS { options.TLSConfig = &tls.Config{ + MinVersion: kedautil.GetMinTLSVersion(), InsecureSkipVerify: info.unsafeSsl, } } diff --git a/pkg/util/http.go b/pkg/util/http.go index cf8481e2cbc..23c3a8c3397 100644 --- a/pkg/util/http.go +++ b/pkg/util/http.go @@ -18,18 +18,48 @@ package util import ( "crypto/tls" + "fmt" "net/http" + "os" "time" + + "github.com/go-logr/logr" + ctrl "sigs.k8s.io/controller-runtime" ) var disableKeepAlives bool +var minTLSVersion uint16 func init() { + setupLog := ctrl.Log.WithName("http_setup") var err error disableKeepAlives, err = ResolveOsEnvBool("KEDA_HTTP_DISABLE_KEEP_ALIVE", false) if err != nil { disableKeepAlives = false } + + minTLSVersion = initMinTLSVersion(setupLog) +} + +func initMinTLSVersion(logger logr.Logger) uint16 { + version, found := os.LookupEnv("KEDA_HTTP_MIN_TLS_VERSION") + minVersion := tls.VersionTLS12 + if found { + switch version { + case "TLS13": + minVersion = tls.VersionTLS13 + case "TLS12": + minVersion = tls.VersionTLS12 + case "TLS11": + minVersion = tls.VersionTLS11 + case "TLS10": + minVersion = tls.VersionTLS10 + default: + logger.Info(fmt.Sprintf("%s is not a valid value, using `TLS12`. Allowed values are: `TLS13`,`TLS12`,`TLS11`,`TLS10`", version)) + minVersion = tls.VersionTLS12 + } + } + return uint16(minVersion) } // HTTPDoer is an interface that matches the Do method on @@ -48,8 +78,11 @@ func CreateHTTPClient(timeout time.Duration, unsafeSsl bool) *http.Client { timeout = 300 * time.Millisecond } transport := &http.Transport{ - TLSClientConfig: &tls.Config{InsecureSkipVerify: unsafeSsl}, - Proxy: http.ProxyFromEnvironment, + TLSClientConfig: &tls.Config{ + InsecureSkipVerify: unsafeSsl, + MinVersion: GetMinTLSVersion(), + }, + Proxy: http.ProxyFromEnvironment, } if disableKeepAlives { // disable keep http connection alive @@ -62,3 +95,7 @@ func CreateHTTPClient(timeout time.Duration, unsafeSsl bool) *http.Client { } return httpClient } + +func GetMinTLSVersion() uint16 { + return minTLSVersion +} diff --git a/pkg/util/http_test.go b/pkg/util/http_test.go new file mode 100644 index 00000000000..970a6c76dcf --- /dev/null +++ b/pkg/util/http_test.go @@ -0,0 +1,73 @@ +/* +Copyright 2023 The KEDA Authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package util + +import ( + "crypto/tls" + "os" + "testing" + + "github.com/go-logr/logr" +) + +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(logr.Discard()) + + if testData.expectedVersion != minVersion { + t.Error("Failed to resolve minTLSVersion correctly", "wants", testData.expectedVersion, "got", minVersion) + } + } +} diff --git a/pkg/util/tls_config.go b/pkg/util/tls_config.go index cb6e6932fdb..3a64f1ed752 100644 --- a/pkg/util/tls_config.go +++ b/pkg/util/tls_config.go @@ -54,7 +54,9 @@ func decryptClientKey(clientKey, clientKeyPassword string) ([]byte, error) { func NewTLSConfigWithPassword(clientCert, clientKey, clientKeyPassword, caCert string) (*tls.Config, error) { valid := false - config := &tls.Config{} + config := &tls.Config{ + MinVersion: GetMinTLSVersion(), + } if clientCert != "" && clientKey != "" { key := []byte(clientKey)