Skip to content

Commit 2acfe66

Browse files
authored
metrics-server: inherit TLS options from CDI TLSSecurityProfile (#4033)
Previously the metrics-server would be initiated with default TLS configuration. This change makes it so the TLS configuration is updated during runtime for every request according to the CDI TLSSecurityProfile. Signed-off-by: Adi Aloni <[email protected]>
1 parent b17a4d3 commit 2acfe66

6 files changed

Lines changed: 89 additions & 0 deletions

File tree

cmd/cdi-controller/BUILD.bazel

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ go_library(
88
importpath = "kubevirt.io/containerized-data-importer/cmd/cdi-controller",
99
visibility = ["//visibility:private"],
1010
deps = [
11+
"//pkg/client/clientset/versioned:go_default_library",
1112
"//pkg/common:go_default_library",
1213
"//pkg/controller:go_default_library",
1314
"//pkg/controller/datavolume:go_default_library",
@@ -18,6 +19,7 @@ go_library(
1819
"//pkg/util/cert:go_default_library",
1920
"//pkg/util/cert/fetcher:go_default_library",
2021
"//pkg/util/cert/generator:go_default_library",
22+
"//pkg/util/tls-crypto-watch:go_default_library",
2123
"//staging/src/kubevirt.io/containerized-data-importer-api/pkg/apis/core/v1beta1:go_default_library",
2224
"//staging/src/kubevirt.io/containerized-data-importer-api/pkg/apis/forklift/v1beta1:go_default_library",
2325
"//vendor/github.com/kelseyhightower/envconfig:go_default_library",

cmd/cdi-controller/controller.go

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ import (
4141

4242
cdiv1 "kubevirt.io/containerized-data-importer-api/pkg/apis/core/v1beta1"
4343
forklift "kubevirt.io/containerized-data-importer-api/pkg/apis/forklift/v1beta1"
44+
cdiclient "kubevirt.io/containerized-data-importer/pkg/client/clientset/versioned"
4445
"kubevirt.io/containerized-data-importer/pkg/common"
4546
"kubevirt.io/containerized-data-importer/pkg/controller"
4647
dvc "kubevirt.io/containerized-data-importer/pkg/controller/datavolume"
@@ -51,6 +52,7 @@ import (
5152
"kubevirt.io/containerized-data-importer/pkg/util/cert"
5253
"kubevirt.io/containerized-data-importer/pkg/util/cert/fetcher"
5354
"kubevirt.io/containerized-data-importer/pkg/util/cert/generator"
55+
cryptowatch "kubevirt.io/containerized-data-importer/pkg/util/tls-crypto-watch"
5456
)
5557

5658
const (
@@ -193,6 +195,8 @@ func start() {
193195
klog.Fatalf("Unable to get uncached client: %v\n", errors.WithStack(err))
194196
}
195197

198+
managedTLSWatcher := cryptowatch.NewManagedTLSWatcher(cdiclient.NewForConfigOrDie(cfg))
199+
196200
opts := manager.Options{
197201
LeaderElection: true,
198202
LeaderElectionNamespace: namespace,
@@ -207,6 +211,15 @@ func start() {
207211
// See CVE-2023-44487, CVE-2023-39325
208212
TLSOpts: []func(*tls.Config){func(c *tls.Config) {
209213
c.NextProtos = []string{"http/1.1"}
214+
c.GetConfigForClient = func(t *tls.ClientHelloInfo) (*tls.Config, error) {
215+
config := c.Clone()
216+
if w := managedTLSWatcher.Watcher(); w != nil {
217+
cryptoConfig := w.GetCdiTLSConfig()
218+
config.CipherSuites = cryptoConfig.CipherSuites
219+
config.MinVersion = cryptoConfig.MinVersion
220+
}
221+
return config, nil
222+
}
210223
}},
211224
},
212225
}
@@ -322,6 +335,12 @@ func start() {
322335
os.Exit(1)
323336
}
324337

338+
managedTLSWatcher.SetCache(mgr.GetCache())
339+
if err := mgr.Add(managedTLSWatcher); err != nil {
340+
log.Error(err, "unable to add watcher to manager")
341+
os.Exit(1)
342+
}
343+
325344
klog.V(1).Infoln("created cdi controllers")
326345

327346
if err := mgr.Start(ctx); err != nil {

cmd/cdi-operator/BUILD.bazel

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,10 @@ go_library(
88
importpath = "kubevirt.io/containerized-data-importer/cmd/cdi-operator",
99
visibility = ["//visibility:private"],
1010
deps = [
11+
"//pkg/client/clientset/versioned:go_default_library",
1112
"//pkg/operator/controller:go_default_library",
1213
"//pkg/util:go_default_library",
14+
"//pkg/util/tls-crypto-watch:go_default_library",
1315
"//staging/src/kubevirt.io/containerized-data-importer-api/pkg/apis/core/v1beta1:go_default_library",
1416
"//staging/src/kubevirt.io/containerized-data-importer-api/pkg/apis/forklift/v1beta1:go_default_library",
1517
"//vendor/github.com/kubernetes-csi/volume-data-source-validator/client/apis/volumepopulator/v1beta1:go_default_library",

cmd/cdi-operator/operator.go

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,8 +45,10 @@ import (
4545

4646
cdiv1 "kubevirt.io/containerized-data-importer-api/pkg/apis/core/v1beta1"
4747
forklift "kubevirt.io/containerized-data-importer-api/pkg/apis/forklift/v1beta1"
48+
cdiclient "kubevirt.io/containerized-data-importer/pkg/client/clientset/versioned"
4849
"kubevirt.io/containerized-data-importer/pkg/operator/controller"
4950
"kubevirt.io/containerized-data-importer/pkg/util"
51+
cryptowatch "kubevirt.io/containerized-data-importer/pkg/util/tls-crypto-watch"
5052
)
5153

5254
var log = logf.Log.WithName("cmd")
@@ -91,6 +93,8 @@ func main() {
9193
os.Exit(1)
9294
}
9395

96+
managedTLSWatcher := cryptowatch.NewManagedTLSWatcher(cdiclient.NewForConfigOrDie(cfg))
97+
9498
managerOpts := manager.Options{
9599
Cache: cache.Options{
96100
DefaultNamespaces: map[string]cache.Config{
@@ -109,6 +113,15 @@ func main() {
109113
// See CVE-2023-44487, CVE-2023-39325
110114
TLSOpts: []func(*tls.Config){func(c *tls.Config) {
111115
c.NextProtos = []string{"http/1.1"}
116+
c.GetConfigForClient = func(t *tls.ClientHelloInfo) (*tls.Config, error) {
117+
config := c.Clone()
118+
if w := managedTLSWatcher.Watcher(); w != nil {
119+
cryptoConfig := w.GetCdiTLSConfig()
120+
config.CipherSuites = cryptoConfig.CipherSuites
121+
config.MinVersion = cryptoConfig.MinVersion
122+
}
123+
return config, nil
124+
}
112125
}},
113126
},
114127
}
@@ -173,6 +186,12 @@ func main() {
173186
os.Exit(1)
174187
}
175188

189+
managedTLSWatcher.SetCache(mgr.GetCache())
190+
if err := mgr.Add(managedTLSWatcher); err != nil {
191+
log.Error(err, "unable to add watcher to manager")
192+
os.Exit(1)
193+
}
194+
176195
if err := mgr.AddHealthzCheck("healthz", healthz.Ping); err != nil {
177196
log.Error(err, "unable to set up health check")
178197
os.Exit(1)

pkg/util/tls-crypto-watch/BUILD.bazel

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,5 +14,6 @@ go_library(
1414
"//vendor/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
1515
"//vendor/k8s.io/client-go/tools/cache:go_default_library",
1616
"//vendor/k8s.io/klog/v2:go_default_library",
17+
"//vendor/sigs.k8s.io/controller-runtime/pkg/cache:go_default_library",
1718
],
1819
)

pkg/util/tls-crypto-watch/tls-crypto-watch.go

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ package tlscryptowatch
2222
import (
2323
"context"
2424
"crypto/tls"
25+
"fmt"
2526
"sync"
2627

2728
ocpcrypto "github.com/openshift/library-go/pkg/crypto"
@@ -30,6 +31,8 @@ import (
3031
"k8s.io/client-go/tools/cache"
3132
"k8s.io/klog/v2"
3233

34+
runtimecache "sigs.k8s.io/controller-runtime/pkg/cache"
35+
3336
cdiv1 "kubevirt.io/containerized-data-importer-api/pkg/apis/core/v1beta1"
3437
cdiclient "kubevirt.io/containerized-data-importer/pkg/client/clientset/versioned"
3538
informers "kubevirt.io/containerized-data-importer/pkg/client/informers/externalversions"
@@ -125,6 +128,49 @@ func (ctw *cdiConfigTLSWatcher) updateConfig(config *cdiv1.CDIConfig) {
125128
ctw.config = newConfig
126129
}
127130

131+
type ManagedTLSWatcher struct {
132+
client cdiclient.Interface
133+
cache runtimecache.Cache
134+
mu sync.RWMutex
135+
watcher CdiConfigTLSWatcher
136+
}
137+
138+
func NewManagedTLSWatcher(cdiClient cdiclient.Interface) *ManagedTLSWatcher {
139+
return &ManagedTLSWatcher{
140+
client: cdiClient,
141+
}
142+
}
143+
144+
func (m *ManagedTLSWatcher) Start(ctx context.Context) error {
145+
if !m.cache.WaitForCacheSync(ctx) {
146+
return fmt.Errorf("failed to wait for caches to sync")
147+
}
148+
149+
w, err := NewCdiConfigTLSWatcher(ctx, m.client)
150+
if err != nil {
151+
return fmt.Errorf("failed to create TLS watcher: %w", err)
152+
}
153+
154+
m.mu.Lock()
155+
m.watcher = w
156+
m.mu.Unlock()
157+
158+
<-ctx.Done()
159+
return nil
160+
}
161+
162+
func (m *ManagedTLSWatcher) Watcher() CdiConfigTLSWatcher {
163+
m.mu.RLock()
164+
defer m.mu.RUnlock()
165+
return m.watcher
166+
}
167+
168+
func (m *ManagedTLSWatcher) SetCache(cache runtimecache.Cache) {
169+
m.mu.Lock()
170+
defer m.mu.Unlock()
171+
m.cache = cache
172+
}
173+
128174
// SelectCipherSuitesAndMinTLSVersion returns cipher names and minimal TLS version according to the input profile
129175
func SelectCipherSuitesAndMinTLSVersion(profile *cdiv1.TLSSecurityProfile) ([]string, cdiv1.TLSProtocolVersion) {
130176
if profile == nil {

0 commit comments

Comments
 (0)