Skip to content

Commit b51655b

Browse files
wozniakjanJorTurFerCopilotjoaopaulosr95
authored
Prepare release v2.17.2 (#6841)
* feat: grpc mTLS certificates are hot reloaded (#6756) Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> Signed-off-by: Jan Wozniak <wozniak.jan@gmail.com> * fix: temporal scaler was not setting up tls for apikey auth (#6781) * fix: temporal scaler was not setting up tls for apikey auth Signed-off-by: joaopaulosr95 <joaopaulosr95@gmail.com> * Update CHANGELOG.md Co-authored-by: Jan Wozniak <wozniak.jan@gmail.com> Signed-off-by: João Bastos <joaopaulosr95@gmail.com> --------- Signed-off-by: joaopaulosr95 <joaopaulosr95@gmail.com> Signed-off-by: João Bastos <joaopaulosr95@gmail.com> Signed-off-by: Jan Wozniak <wozniak.jan@gmail.com> Co-authored-by: Jan Wozniak <wozniak.jan@gmail.com> Signed-off-by: Jan Wozniak <wozniak.jan@gmail.com> * chore: changelog and issue template v2.17.2 Signed-off-by: Jan Wozniak <wozniak.jan@gmail.com> --------- Signed-off-by: Jan Wozniak <wozniak.jan@gmail.com> Signed-off-by: joaopaulosr95 <joaopaulosr95@gmail.com> Signed-off-by: João Bastos <joaopaulosr95@gmail.com> Co-authored-by: Jorge Turrado Ferrero <Jorge_turrado@hotmail.es> Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> Co-authored-by: João Bastos <joaopaulosr95@gmail.com>
1 parent a3e2090 commit b51655b

File tree

27 files changed

+517
-438
lines changed

27 files changed

+517
-438
lines changed

.github/ISSUE_TEMPLATE/3_bug_report.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@ body:
5757
label: KEDA Version
5858
description: What version of KEDA that are you running?
5959
options:
60+
- "2.17.2"
6061
- "2.17.1"
6162
- "2.17.0"
6263
- "2.16.1"

BUILD.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -135,7 +135,7 @@ All components inspect the folder `/certs` for any certificates inside it. Argum
135135

136136
```bash
137137
mkdir -p /certs
138-
openssl req -newkey rsa:2048 -subj '/CN=localhost' -nodes -keyout /certs/tls.key -x509 -days 3650 -out /certs/tls.crt
138+
openssl req -newkey rsa:2048 -subj '/CN=localhost' -addext "subjectAltName = DNS:localhost" -nodes -keyout /certs/tls.key -x509 -days 3650 -out /certs/tls.crt
139139
cp /certs/tls.crt /certs/ca.crt
140140
```
141141

CHANGELOG.md

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ To learn more about active deprecations, we recommend checking [GitHub Discussio
1616
## History
1717

1818
- [Unreleased](#unreleased)
19+
- [v2.17.2](#v2172)
1920
- [v2.17.1](#v2171)
2021
- [v2.17.0](#v2170)
2122
- [v2.16.1](#v2161)
@@ -91,6 +92,16 @@ New deprecation(s):
9192

9293
- TODO ([#XXX](https://github.com/kedacore/keda/issues/XXX))
9394

95+
## v2.17.2
96+
97+
### Improvements
98+
99+
- **General**: Internal gRPC connection's certificates are hot reloaded ([#6756](https://github.com/kedacore/keda/pull/6756))
100+
101+
### Fixes
102+
103+
- **Temporal Scaler**: Fix Temporal Scaler TLS version ([#6707](https://github.com/kedacore/keda/pull/6707))
104+
94105
## v2.17.1
95106

96107
### Improvements

cmd/adapter/main.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -109,7 +109,7 @@ func (a *Adapter) makeProvider(ctx context.Context) (provider.ExternalMetricsPro
109109
}
110110

111111
logger.Info("Connecting Metrics Service gRPC client to the server", "address", metricsServiceAddr)
112-
grpcClient, err := metricsservice.NewGrpcClient(metricsServiceAddr, a.SecureServing.ServerCert.CertDirectory, metricsServiceGRPCAuthority, clientMetrics)
112+
grpcClient, err := metricsservice.NewGrpcClient(ctx, metricsServiceAddr, a.SecureServing.ServerCert.CertDirectory, metricsServiceGRPCAuthority, clientMetrics)
113113
if err != nil {
114114
logger.Error(err, "error connecting Metrics Service gRPC client to the server", "address", metricsServiceAddr)
115115
return nil, err

go.mod

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -213,7 +213,7 @@ require (
213213
github.com/facebookgo/clock v0.0.0-20150410010913-600d898af40a // indirect
214214
github.com/fatih/color v1.18.0 // indirect
215215
github.com/felixge/httpsnoop v1.0.4 // indirect
216-
github.com/fsnotify/fsnotify v1.8.0 // indirect
216+
github.com/fsnotify/fsnotify v1.9.0 // indirect
217217
github.com/fxamacker/cbor/v2 v2.7.0 // indirect
218218
github.com/gabriel-vasile/mimetype v1.4.8 // indirect
219219
github.com/go-errors/errors v1.5.1 // indirect

go.sum

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -970,8 +970,8 @@ github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHk
970970
github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0=
971971
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
972972
github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
973-
github.com/fsnotify/fsnotify v1.8.0 h1:dAwr6QBTBZIkG8roQaJjGof0pp0EeF+tNV7YBP3F/8M=
974-
github.com/fsnotify/fsnotify v1.8.0/go.mod h1:8jBTzvmWwFyi3Pb8djgCCO5IBqzKJ/Jwo8TRcHyHii0=
973+
github.com/fsnotify/fsnotify v1.9.0 h1:2Ml+OJNzbYCTzsxtv8vKSFD9PbJjmhYF14k/jKC7S9k=
974+
github.com/fsnotify/fsnotify v1.9.0/go.mod h1:8jBTzvmWwFyi3Pb8djgCCO5IBqzKJ/Jwo8TRcHyHii0=
975975
github.com/fxamacker/cbor/v2 v2.7.0 h1:iM5WgngdRBanHcxugY4JySA0nk1wZorNOpTgCMedv5E=
976976
github.com/fxamacker/cbor/v2 v2.7.0/go.mod h1:pxXPTn3joSm21Gbwsv0w9OSA2y1HFR9qXEeXQVeNoDQ=
977977
github.com/gabriel-vasile/mimetype v1.4.8 h1:FfZ3gj38NjllZIeJAmMhr+qKL8Wu+nOoI3GqacKw1NM=

pkg/metricsservice/client.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ type GrpcClient struct {
3737
connection *grpc.ClientConn
3838
}
3939

40-
func NewGrpcClient(url, certDir, authority string, clientMetrics *grpcprom.ClientMetrics) (*GrpcClient, error) {
40+
func NewGrpcClient(ctx context.Context, url, certDir, authority string, clientMetrics *grpcprom.ClientMetrics) (*GrpcClient, error) {
4141
defaultConfig := `{
4242
"methodConfig": [{
4343
"timeout": "3s",
@@ -50,7 +50,7 @@ func NewGrpcClient(url, certDir, authority string, clientMetrics *grpcprom.Clien
5050
}
5151
}]}`
5252

53-
creds, err := utils.LoadGrpcTLSCredentials(certDir, false)
53+
creds, err := utils.LoadGrpcTLSCredentials(ctx, certDir, false)
5454
if err != nil {
5555
return nil, err
5656
}

pkg/metricsservice/server.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,7 @@ func (s *GrpcServer) startServer() error {
8888
func (s *GrpcServer) Start(ctx context.Context) error {
8989
<-s.certsReady
9090
if s.server == nil {
91-
creds, err := utils.LoadGrpcTLSCredentials(s.certDir, true)
91+
creds, err := utils.LoadGrpcTLSCredentials(ctx, s.certDir, true)
9292
if err != nil {
9393
return err
9494
}

pkg/metricsservice/utils/tls.go

Lines changed: 91 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -17,19 +17,30 @@ limitations under the License.
1717
package utils
1818

1919
import (
20+
"context"
2021
"crypto/tls"
2122
"crypto/x509"
2223
"fmt"
2324
"os"
2425
"path"
26+
"strings"
27+
"sync"
2528

29+
"github.com/fsnotify/fsnotify"
2630
"google.golang.org/grpc/credentials"
31+
logf "sigs.k8s.io/controller-runtime/pkg/log"
2732
)
2833

34+
var log = logf.Log.WithName("grpc_server_certificates")
35+
2936
// LoadGrpcTLSCredentials reads the certificate from the given path and returns TLS transport credentials
30-
func LoadGrpcTLSCredentials(certDir string, server bool) (credentials.TransportCredentials, error) {
37+
func LoadGrpcTLSCredentials(ctx context.Context, certDir string, server bool) (credentials.TransportCredentials, error) {
38+
caPath := path.Join(certDir, "ca.crt")
39+
certPath := path.Join(certDir, "tls.crt")
40+
keyPath := path.Join(certDir, "tls.key")
41+
3142
// Load certificate of the CA who signed client's certificate
32-
pemClientCA, err := os.ReadFile(path.Join(certDir, "ca.crt"))
43+
pemClientCA, err := os.ReadFile(caPath)
3344
if err != nil {
3445
return nil, err
3546
}
@@ -43,16 +54,90 @@ func LoadGrpcTLSCredentials(certDir string, server bool) (credentials.TransportC
4354
return nil, fmt.Errorf("failed to add client CA's certificate")
4455
}
4556

46-
// Load certificate and private key
47-
cert, err := tls.LoadX509KeyPair(path.Join(certDir, "tls.crt"), path.Join(certDir, "tls.key"))
57+
// Load initial certificate and private key
58+
mTLSCertificate, err := tls.LoadX509KeyPair(certPath, keyPath)
4859
if err != nil {
4960
return nil, err
5061
}
5162

63+
// Start the watcher for cert updates
64+
watcher, err := fsnotify.NewWatcher()
65+
if err != nil {
66+
return nil, err
67+
}
68+
err = watcher.Add(certDir)
69+
if err != nil {
70+
return nil, err
71+
}
72+
73+
certMutex := sync.RWMutex{}
74+
go func() {
75+
log.V(1).Info("starting mTLS certificates monitoring")
76+
for {
77+
select {
78+
case event, ok := <-watcher.Events:
79+
if !ok { // Channel was closed (i.e. Watcher.Close() was called).
80+
log.Error(err, "watcher stopped")
81+
return
82+
}
83+
// We are only interested on Create changes on ..data dir
84+
// as kubernetes creates first a temp folder with the new
85+
// cert and then rename the whole folder.
86+
// This unix.IN_MOVED_TO is treated as fsnotify.Create
87+
if !event.Has(fsnotify.Create) ||
88+
!strings.HasSuffix(event.Name, "..data") {
89+
continue
90+
}
91+
log.V(1).Info("detected change on certificates, reloading")
92+
93+
pemClientCA, err := os.ReadFile(caPath)
94+
if err != nil {
95+
log.Error(err, "error reading grpc ca certificate")
96+
continue
97+
}
98+
if !certPool.AppendCertsFromPEM(pemClientCA) {
99+
log.Error(err, "failed to add client CA's certificate")
100+
continue
101+
}
102+
log.V(1).Info("grpc ca certificate has been updated")
103+
104+
// Load certificate of the CA who signed client's certificate
105+
cert, err := tls.LoadX509KeyPair(certPath, keyPath)
106+
if err != nil {
107+
log.Error(err, "error reading grpc certificate")
108+
continue
109+
}
110+
certMutex.Lock()
111+
mTLSCertificate = cert
112+
certMutex.Unlock()
113+
log.V(1).Info("grpc mTLS certificate has been updated")
114+
115+
case err, ok := <-watcher.Errors:
116+
if !ok { // Channel was closed (i.e. Watcher.Close() was called).
117+
log.Error(err, "watcher stopped")
118+
return
119+
}
120+
log.Error(err, "error reading grpc certificate changes")
121+
case <-ctx.Done():
122+
log.V(1).Info("stopping mTLS certificates monitoring")
123+
return
124+
}
125+
}
126+
}()
127+
52128
// Create the credentials and return it
53129
config := &tls.Config{
54-
MinVersion: tls.VersionTLS13,
55-
Certificates: []tls.Certificate{cert},
130+
MinVersion: tls.VersionTLS13,
131+
GetCertificate: func(_ *tls.ClientHelloInfo) (*tls.Certificate, error) {
132+
certMutex.RLock()
133+
defer certMutex.RUnlock()
134+
return &mTLSCertificate, nil
135+
},
136+
GetClientCertificate: func(_ *tls.CertificateRequestInfo) (*tls.Certificate, error) {
137+
certMutex.RLock()
138+
defer certMutex.RUnlock()
139+
return &mTLSCertificate, nil
140+
},
56141
}
57142
if server {
58143
config.ClientAuth = tls.RequireAndVerifyClientCert

pkg/scalers/temporal.go

Lines changed: 13 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -209,10 +209,13 @@ func getTemporalClient(ctx context.Context, meta *temporalMetadata, log logr.Log
209209
}),
210210
}
211211

212+
var tlsConfig *tls.Config
213+
212214
if meta.APIKey != "" {
213215
dialOptions = append(dialOptions, grpc.WithUnaryInterceptor(
214216
func(ctx context.Context, method string, req any, reply any,
215-
cc *grpc.ClientConn, invoker grpc.UnaryInvoker, opts ...grpc.CallOption) error {
217+
cc *grpc.ClientConn, invoker grpc.UnaryInvoker, opts ...grpc.CallOption,
218+
) error {
216219
return invoker(
217220
metadata.AppendToOutgoingContext(ctx, "temporal-namespace", meta.Namespace),
218221
method,
@@ -224,21 +227,22 @@ func getTemporalClient(ctx context.Context, meta *temporalMetadata, log logr.Log
224227
},
225228
))
226229
options.Credentials = sdk.NewAPIKeyStaticCredentials(meta.APIKey)
227-
options.ConnectionOptions.TLS = &tls.Config{
228-
MinVersion: tls.VersionTLS13,
230+
tlsConfig = &tls.Config{
231+
MinVersion: kedautil.GetMinTLSVersion(),
229232
}
230233
}
231234

232-
options.ConnectionOptions = sdk.ConnectionOptions{
233-
DialOptions: dialOptions,
234-
}
235-
236235
if meta.Cert != "" && meta.Key != "" {
237-
tlsConfig, err := kedautil.NewTLSConfigWithPassword(meta.Cert, meta.Key, meta.KeyPassword, meta.CA, meta.UnsafeSsl)
236+
var err error
237+
tlsConfig, err = kedautil.NewTLSConfigWithPassword(meta.Cert, meta.Key, meta.KeyPassword, meta.CA, meta.UnsafeSsl)
238238
if err != nil {
239239
return nil, err
240240
}
241-
options.ConnectionOptions.TLS = tlsConfig
241+
}
242+
243+
options.ConnectionOptions = sdk.ConnectionOptions{
244+
DialOptions: dialOptions,
245+
TLS: tlsConfig,
242246
}
243247

244248
return sdk.DialContext(ctx, options)

0 commit comments

Comments
 (0)