Skip to content

Commit 3b1283e

Browse files
committed
feat: honor TLSAdherence
1 parent 06f4b0d commit 3b1283e

9 files changed

Lines changed: 614 additions & 89 deletions

File tree

cmd/cluster-cloud-controller-manager-operator/main.go

Lines changed: 44 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ import (
2222
"errors"
2323
"flag"
2424
"os"
25+
"strings"
2526
"time"
2627

2728
"github.com/spf13/pflag"
@@ -34,6 +35,7 @@ import (
3435
"k8s.io/apimachinery/pkg/runtime"
3536
utilruntime "k8s.io/apimachinery/pkg/util/runtime"
3637
clientgoscheme "k8s.io/client-go/kubernetes/scheme"
38+
cliflag "k8s.io/component-base/cli/flag"
3739
"k8s.io/component-base/config"
3840
"k8s.io/component-base/config/options"
3941
"k8s.io/klog/v2"
@@ -56,6 +58,7 @@ import (
5658
rbacv1 "k8s.io/api/rbac/v1"
5759

5860
"github.com/openshift/cluster-cloud-controller-manager-operator/pkg/controllers"
61+
pkgtls "github.com/openshift/cluster-cloud-controller-manager-operator/pkg/tls"
5962
"github.com/openshift/cluster-cloud-controller-manager-operator/pkg/util"
6063
// +kubebuilder:scaffold:imports
6164
)
@@ -119,8 +122,16 @@ func main() {
119122
// to allow leader lection flags to be bound
120123
pflag.CommandLine.AddGoFlagSet(flag.CommandLine)
121124
options.BindLeaderElectionFlags(&leaderElectionConfig, pflag.CommandLine)
125+
126+
tlsMinVersionFlag := pflag.String("tls-min-version", "",
127+
"Minimum TLS version supported. When set, overrides the cluster-wide TLS profile. Possible values: "+strings.Join(cliflag.TLSPossibleVersions(), ", "))
128+
tlsCipherSuitesFlag := pflag.StringSlice("tls-cipher-suites", nil,
129+
"Comma-separated list of cipher suites for the server. When set, overrides the cluster-wide TLS profile. Possible values: "+strings.Join(cliflag.TLSCipherPossibleValues(), ", "))
130+
122131
pflag.Parse()
123132

133+
tlsOverrideFromFlags := *tlsMinVersionFlag != "" || len(*tlsCipherSuitesFlag) > 0
134+
124135
ctrl.SetLogger(klog.NewKlogr().WithName("CCMOperator"))
125136

126137
restConfig := ctrl.GetConfigOrDie()
@@ -136,25 +147,13 @@ func main() {
136147
// Ensure the context is cancelled when the program exits.
137148
defer cancel()
138149

139-
k8sClient, err := client.New(restConfig, client.Options{Scheme: scheme})
140-
if err != nil {
141-
setupLog.Error(err, "unable to create Kubernetes client")
142-
os.Exit(1)
143-
}
144-
145-
// Fetch the TLS profile from the APIServer resource.
146-
tlsProfileSpec, err := utiltls.FetchAPIServerTLSProfile(ctx, k8sClient)
150+
// Resolve the TLS configuration for the server endpoints.
151+
tlsResult, err := pkgtls.ResolveTLSConfig(ctx, restConfig, *tlsMinVersionFlag, *tlsCipherSuitesFlag)
147152
if err != nil {
148-
setupLog.Error(err, "unable to get TLS profile from API server")
153+
setupLog.Error(err, "unable to configure TLS")
149154
os.Exit(1)
150155
}
151-
152-
// Create the TLS configuration function for the server endpoints.
153-
tlsConfigFunc, unsupportedCiphers := utiltls.NewTLSConfigFromProfile(tlsProfileSpec)
154-
if len(unsupportedCiphers) > 0 {
155-
setupLog.Info("Some ciphers from TLS profile are not supported", "unsupportedCiphers", unsupportedCiphers)
156-
}
157-
tlsOpts := []func(*tls.Config){tlsConfigFunc}
156+
tlsOpts := []func(*tls.Config){tlsResult.TLSConfig}
158157

159158
syncPeriod := 10 * time.Minute
160159
mgr, err := ctrl.NewManager(restConfig, ctrl.Options{
@@ -265,26 +264,40 @@ func main() {
265264
Scheme: mgr.GetScheme(),
266265
ImagesFile: *imagesFile,
267266
FeatureGateAccess: featureGateAccessor,
268-
TLSProfileSpec: tlsProfileSpec,
267+
TLSConfig: tlsResult.TLSConfig,
269268
}).SetupWithManager(mgr); err != nil {
270269
setupLog.Error(err, "unable to create controller", "controller", "ClusterOperator")
271270
os.Exit(1)
272271
}
273272

274-
// Set up the TLS security profile watcher to watch for TLS config changes
275-
if err = (&utiltls.SecurityProfileWatcher{
276-
Client: mgr.GetClient(),
277-
InitialTLSProfileSpec: tlsProfileSpec,
278-
OnProfileChange: func(ctx context.Context, oldTLSProfileSpec, newTLSProfileSpec configv1.TLSProfileSpec) {
279-
klog.Infof("TLS profile has changed, initiating a shutdown to reload it. %q: %+v, %q: %+v",
280-
"old profile", oldTLSProfileSpec,
281-
"new profile", newTLSProfileSpec,
282-
)
283-
cancel()
284-
},
285-
}).SetupWithManager(mgr); err != nil {
286-
setupLog.Error(err, "unable to create controller", "controller", "TLSSecurityProfileWatcher")
287-
os.Exit(1)
273+
// Set up the TLS security profile watcher controller.
274+
// When TLS is overridden via CLI flags, the watcher is not needed since
275+
// the component is not reading from apiservers.config.openshift.io/cluster.
276+
if tlsOverrideFromFlags {
277+
setupLog.Info("TLS security profile watcher disabled because TLS is configured via CLI flags")
278+
} else {
279+
if err = (&utiltls.SecurityProfileWatcher{
280+
Client: mgr.GetClient(),
281+
InitialTLSAdherencePolicy: tlsResult.TLSAdherencePolicy,
282+
InitialTLSProfileSpec: tlsResult.TLSProfileSpec,
283+
OnAdherencePolicyChange: func(ctx context.Context, oldTLSAdherencePolicy, newTLSAdherencePolicy configv1.TLSAdherencePolicy) {
284+
klog.Infof("TLS adherence policy has changed, initiating a shutdown to reload it. %q: %+v, %q: %+v",
285+
"old adherence policy", oldTLSAdherencePolicy,
286+
"new adherence policy", newTLSAdherencePolicy,
287+
)
288+
cancel()
289+
},
290+
OnProfileChange: func(ctx context.Context, oldTLSProfileSpec, newTLSProfileSpec configv1.TLSProfileSpec) {
291+
klog.Infof("TLS profile has changed, initiating a shutdown to reload it. %q: %+v, %q: %+v",
292+
"old profile", oldTLSProfileSpec,
293+
"new profile", newTLSProfileSpec,
294+
)
295+
cancel()
296+
},
297+
}).SetupWithManager(mgr); err != nil {
298+
setupLog.Error(err, "unable to create controller", "controller", "TLSSecurityProfileWatcher")
299+
os.Exit(1)
300+
}
288301
}
289302

290303
// +kubebuilder:scaffold:builder

go.mod

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -12,21 +12,21 @@ require (
1212
github.com/golangci/golangci-lint/v2 v2.11.1
1313
github.com/onsi/ginkgo/v2 v2.28.1
1414
github.com/onsi/gomega v1.39.1
15-
github.com/openshift/api v0.0.0-20260306002634-d3bbdada155c
16-
github.com/openshift/client-go v0.0.0-20260306160707-3935d929fc7d
15+
github.com/openshift/api v0.0.0-20260317165824-54a3998d81eb
16+
github.com/openshift/client-go v0.0.0-20260317180604-743f664b82d1
1717
github.com/openshift/cluster-api-actuator-pkg/testutils v0.0.0-20260310144400-bec013a007a8
18-
github.com/openshift/controller-runtime-common v0.0.0-20260307102856-5db94f69ad3a
19-
github.com/openshift/library-go v0.0.0-20260311094140-ac826d10cb40
18+
github.com/openshift/controller-runtime-common v0.0.0-20260318085703-1812aed6dbd2
19+
github.com/openshift/library-go v0.0.0-20260318142011-72bf34f474bc
2020
github.com/spf13/cobra v1.10.2
2121
github.com/spf13/pflag v1.0.10
2222
github.com/stretchr/testify v1.11.1
2323
gopkg.in/gcfg.v1 v1.2.3
2424
gopkg.in/ini.v1 v1.67.1
2525
gopkg.in/yaml.v2 v2.4.0
26-
k8s.io/api v0.35.1
26+
k8s.io/api v0.35.2
2727
k8s.io/apiextensions-apiserver v0.35.1
28-
k8s.io/apimachinery v0.35.1
29-
k8s.io/client-go v0.35.1
28+
k8s.io/apimachinery v0.35.2
29+
k8s.io/client-go v0.35.2
3030
k8s.io/cloud-provider-aws v1.35.1
3131
k8s.io/cloud-provider-vsphere v1.34.0
3232
k8s.io/component-base v0.35.1
@@ -35,7 +35,7 @@ require (
3535
k8s.io/utils v0.0.0-20260210185600-b8788abfbbc2
3636
sigs.k8s.io/cloud-provider-azure v1.35.1
3737
sigs.k8s.io/cloud-provider-azure/pkg/azclient v0.13.0
38-
sigs.k8s.io/controller-runtime v0.23.2
38+
sigs.k8s.io/controller-runtime v0.23.3
3939
sigs.k8s.io/controller-runtime/tools/setup-envtest v0.0.0-20251103140007-7a1b16d039d2
4040
sigs.k8s.io/controller-tools v0.20.1
4141
sigs.k8s.io/yaml v1.6.0

go.sum

Lines changed: 16 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -466,16 +466,16 @@ github.com/onsi/gomega v1.39.1 h1:1IJLAad4zjPn2PsnhH70V4DKRFlrCzGBNrNaru+Vf28=
466466
github.com/onsi/gomega v1.39.1/go.mod h1:hL6yVALoTOxeWudERyfppUcZXjMwIMLnuSfruD2lcfg=
467467
github.com/openshift-cloud-team/cloud-provider-vsphere v1.19.1-0.20260317135518-758abc9d59a5 h1:Mayj50dtdLPzUVmJNHJpM4GpFWq7fcy9FDIoYUfngQ4=
468468
github.com/openshift-cloud-team/cloud-provider-vsphere v1.19.1-0.20260317135518-758abc9d59a5/go.mod h1:3uaiy47HteyMlDjJankjteem/s1hnbRBU1FgbekLMKU=
469-
github.com/openshift/api v0.0.0-20260306002634-d3bbdada155c h1:YQYiDzOLJzwQunxCaa5OpyNyMLPz4HJ2CLaKqUQOQjQ=
470-
github.com/openshift/api v0.0.0-20260306002634-d3bbdada155c/go.mod h1:pyVjK0nZ4sRs4fuQVQ4rubsJdahI1PB94LnQ8sGdvxo=
471-
github.com/openshift/client-go v0.0.0-20260306160707-3935d929fc7d h1:T+9HFgEEcnu1TDDfsO5JcJC6N0/Kzob5AtG9IpITHJ8=
472-
github.com/openshift/client-go v0.0.0-20260306160707-3935d929fc7d/go.mod h1:tIA3XSb/WsC/Fg0YNRfs/JrMrloBKPGF+NKVutd7nMI=
469+
github.com/openshift/api v0.0.0-20260317165824-54a3998d81eb h1:iwBR3mzmyE3EMFx7R3CQ9lOccTS0dNht8TW82aGITg0=
470+
github.com/openshift/api v0.0.0-20260317165824-54a3998d81eb/go.mod h1:pyVjK0nZ4sRs4fuQVQ4rubsJdahI1PB94LnQ8sGdvxo=
471+
github.com/openshift/client-go v0.0.0-20260317180604-743f664b82d1 h1:Hr/R38eg5ZJXfbiaHumjJIN1buDZwhsm4ys4npVCXH0=
472+
github.com/openshift/client-go v0.0.0-20260317180604-743f664b82d1/go.mod h1:Za51LlH76ALiQ/aKGBYJXmyJNkA//IDJ+I///30CA2M=
473473
github.com/openshift/cluster-api-actuator-pkg/testutils v0.0.0-20260310144400-bec013a007a8 h1:x62h16RetnB1ZP+zjSM9fsoMz98g95zte+DXeUDF34o=
474474
github.com/openshift/cluster-api-actuator-pkg/testutils v0.0.0-20260310144400-bec013a007a8/go.mod h1:n8RwIitgr5SAfvisrU0Ps+Szrn545DBU7nqtwATZphw=
475-
github.com/openshift/controller-runtime-common v0.0.0-20260307102856-5db94f69ad3a h1:EQfdaEHOOBDkbvyHAn69u6eZDMuHPK3CTr1i89eEmss=
476-
github.com/openshift/controller-runtime-common v0.0.0-20260307102856-5db94f69ad3a/go.mod h1:9HQZbBpikedL8l9mQpaDB4C15FNgLlnNuLP5ADrkVOI=
477-
github.com/openshift/library-go v0.0.0-20260311094140-ac826d10cb40 h1:0Q7pg6Et+9Zg5wlom0hX4viqTtyRSj2uVjX74N6gcBw=
478-
github.com/openshift/library-go v0.0.0-20260311094140-ac826d10cb40/go.mod h1:D797O/ssKTNglbrGchjIguFq+DbyRYdeds5w4/VTrKM=
475+
github.com/openshift/controller-runtime-common v0.0.0-20260318085703-1812aed6dbd2 h1:GrZlVichOCE/lz8fg1+eNrAtkM0VSlqa9buuzN0vnb0=
476+
github.com/openshift/controller-runtime-common v0.0.0-20260318085703-1812aed6dbd2/go.mod h1:XGabTMnNbz0M5Oa7IbscZp/jmcc7aHobvOCUWwkzKvM=
477+
github.com/openshift/library-go v0.0.0-20260318142011-72bf34f474bc h1:a+rVRzEdFIwgDQLTbhiG3MEVuBXjLb/6HJRikTob+nY=
478+
github.com/openshift/library-go v0.0.0-20260318142011-72bf34f474bc/go.mod h1:3bi4pLpYRdVd1aEhsHfRTJkwxwPLfRZ+ZePn3RmJd2k=
479479
github.com/otiai10/copy v1.2.0/go.mod h1:rrF5dJ5F0t/EWSYODDu4j9/vEeYHMkc8jt0zJChqQWw=
480480
github.com/otiai10/copy v1.14.0 h1:dCI/t1iTdYGtkvCuBG2BgR6KZa83PTclw4U5n2wAllU=
481481
github.com/otiai10/copy v1.14.0/go.mod h1:ECfuL02W+/FkTWZWgQqXPWZgW9oeKCSQ5qVfSc4qc4w=
@@ -829,16 +829,16 @@ gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
829829
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
830830
honnef.co/go/tools v0.7.0 h1:w6WUp1VbkqPEgLz4rkBzH/CSU6HkoqNLp6GstyTx3lU=
831831
honnef.co/go/tools v0.7.0/go.mod h1:pm29oPxeP3P82ISxZDgIYeOaf9ta6Pi0EWvCFoLG2vc=
832-
k8s.io/api v0.35.1 h1:0PO/1FhlK/EQNVK5+txc4FuhQibV25VLSdLMmGpDE/Q=
833-
k8s.io/api v0.35.1/go.mod h1:28uR9xlXWml9eT0uaGo6y71xK86JBELShLy4wR1XtxM=
832+
k8s.io/api v0.35.2 h1:tW7mWc2RpxW7HS4CoRXhtYHSzme1PN1UjGHJ1bdrtdw=
833+
k8s.io/api v0.35.2/go.mod h1:7AJfqGoAZcwSFhOjcGM7WV05QxMMgUaChNfLTXDRE60=
834834
k8s.io/apiextensions-apiserver v0.35.1 h1:p5vvALkknlOcAqARwjS20kJffgzHqwyQRM8vHLwgU7w=
835835
k8s.io/apiextensions-apiserver v0.35.1/go.mod h1:2CN4fe1GZ3HMe4wBr25qXyJnJyZaquy4nNlNmb3R7AQ=
836-
k8s.io/apimachinery v0.35.1 h1:yxO6gV555P1YV0SANtnTjXYfiivaTPvCTKX6w6qdDsU=
837-
k8s.io/apimachinery v0.35.1/go.mod h1:jQCgFZFR1F4Ik7hvr2g84RTJSZegBc8yHgFWKn//hns=
836+
k8s.io/apimachinery v0.35.2 h1:NqsM/mmZA7sHW02JZ9RTtk3wInRgbVxL8MPfzSANAK8=
837+
k8s.io/apimachinery v0.35.2/go.mod h1:jQCgFZFR1F4Ik7hvr2g84RTJSZegBc8yHgFWKn//hns=
838838
k8s.io/apiserver v0.35.1 h1:potxdhhTL4i6AYAa2QCwtlhtB1eCdWQFvJV6fXgJzxs=
839839
k8s.io/apiserver v0.35.1/go.mod h1:BiL6Dd3A2I/0lBnteXfWmCFobHM39vt5+hJQd7Lbpi4=
840-
k8s.io/client-go v0.35.1 h1:+eSfZHwuo/I19PaSxqumjqZ9l5XiTEKbIaJ+j1wLcLM=
841-
k8s.io/client-go v0.35.1/go.mod h1:1p1KxDt3a0ruRfc/pG4qT/3oHmUj1AhSHEcxNSGg+OA=
840+
k8s.io/client-go v0.35.2 h1:YUfPefdGJA4aljDdayAXkc98DnPkIetMl4PrKX97W9o=
841+
k8s.io/client-go v0.35.2/go.mod h1:4QqEwh4oQpeK8AaefZ0jwTFJw/9kIjdQi0jpKeYvz7g=
842842
k8s.io/cloud-provider-aws v1.35.1 h1:alBjzyitPhOeeHebdt6NbI64tm4MKrj7+Uo/CzYOx1U=
843843
k8s.io/cloud-provider-aws v1.35.1/go.mod h1:6R9TIgQ/ecysPukSmEUs4kZIwqvju80+FjMAhtJ22Q0=
844844
k8s.io/code-generator v0.35.1 h1:yLKR2la7Z9cWT5qmk67ayx8xXLM4RRKQMnC8YPvTWRI=
@@ -869,8 +869,8 @@ sigs.k8s.io/cloud-provider-azure/pkg/azclient v0.13.0 h1:MmCsEs5tx/5W1uRV8+Iv0tD
869869
sigs.k8s.io/cloud-provider-azure/pkg/azclient v0.13.0/go.mod h1:zIU1j1Q/+kHoYXtww3j8qDm3bPeeRYLD9JRipBR+HZQ=
870870
sigs.k8s.io/cloud-provider-azure/pkg/azclient/configloader v0.11.0 h1:xbQUC6pfgnxPE1pKiYIRmR5HkyZ7StB7fnZwQ6pr0eE=
871871
sigs.k8s.io/cloud-provider-azure/pkg/azclient/configloader v0.11.0/go.mod h1:9lQ7K/C/ms3OEDRlzLg2zyJVieNjV/7WfsQmOSnDaOQ=
872-
sigs.k8s.io/controller-runtime v0.23.2 h1:Oh3FliXaA2CS1chpUXvjVNJtsvGZYUxQH8s7bvR7aXk=
873-
sigs.k8s.io/controller-runtime v0.23.2/go.mod h1:B6COOxKptp+YaUT5q4l6LqUJTRpizbgf9KSRNdQGns0=
872+
sigs.k8s.io/controller-runtime v0.23.3 h1:VjB/vhoPoA9l1kEKZHBMnQF33tdCLQKJtydy4iqwZ80=
873+
sigs.k8s.io/controller-runtime v0.23.3/go.mod h1:B6COOxKptp+YaUT5q4l6LqUJTRpizbgf9KSRNdQGns0=
874874
sigs.k8s.io/controller-runtime/tools/setup-envtest v0.0.0-20251103140007-7a1b16d039d2 h1:xLNIemrdP6o6uyzoBQEf83zPX9nO1G10t7sttZ3qz20=
875875
sigs.k8s.io/controller-runtime/tools/setup-envtest v0.0.0-20251103140007-7a1b16d039d2/go.mod h1:sWEAaKdjIb8+pUyzfpeClTvbK2vTRdeF39lz/ee4EMU=
876876
sigs.k8s.io/controller-tools v0.20.1 h1:gkfMt9YodI0K85oT8rVi80NTXO/kDmabKR5Ajn5GYxs=

pkg/config/config.go

Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package config
22

33
import (
4+
"crypto/tls"
45
"encoding/json"
56
"fmt"
67
"os"
@@ -85,7 +86,7 @@ func getImagesFromJSONFile(filePath string) (ImagesReference, error) {
8586
}
8687

8788
// ComposeConfig creates a Config for operator
88-
func ComposeConfig(infrastructure *configv1.Infrastructure, clusterProxy *configv1.Proxy, imagesFile, managedNamespace string, featureGateAccessor featuregates.FeatureGateAccess, tlsProfile configv1.TLSProfileSpec) (OperatorConfig, error) {
89+
func ComposeConfig(infrastructure *configv1.Infrastructure, clusterProxy *configv1.Proxy, imagesFile, managedNamespace string, featureGateAccessor featuregates.FeatureGateAccess, tlsConfig func(*tls.Config)) (OperatorConfig, error) {
8990
err := checkInfrastructureResource(infrastructure)
9091
if err != nil {
9192
klog.Errorf("Unable to get platform from infrastructure: %s", err)
@@ -112,8 +113,19 @@ func ComposeConfig(infrastructure *configv1.Infrastructure, clusterProxy *config
112113
featureGatesString = util.BuildFeatureGateString(enabled, nil)
113114
}
114115

115-
// Convert OpenSSL cipher names from the TLS profile to IANA names expected by CCM CLI flags.
116-
ianaCiphers := libgocrypto.OpenSSLToIANACipherSuites(tlsProfile.Ciphers)
116+
var tlsCipherSuites string
117+
var tlsMinVersion string
118+
119+
if tlsConfig != nil {
120+
resolved := &tls.Config{}
121+
tlsConfig(resolved)
122+
123+
tlsMinVersion = libgocrypto.TLSVersionToNameOrDie(resolved.MinVersion)
124+
125+
if resolved.MinVersion != tls.VersionTLS13 {
126+
tlsCipherSuites = strings.Join(libgocrypto.CipherSuitesToNamesOrDie(resolved.CipherSuites), ",")
127+
}
128+
}
117129

118130
config := OperatorConfig{
119131
PlatformStatus: infrastructure.Status.PlatformStatus.DeepCopy(),
@@ -124,8 +136,8 @@ func ComposeConfig(infrastructure *configv1.Infrastructure, clusterProxy *config
124136
IsSingleReplica: infrastructure.Status.ControlPlaneTopology == configv1.SingleReplicaTopologyMode,
125137
FeatureGates: featureGatesString,
126138
OCPFeatureGates: features,
127-
TLSCipherSuites: strings.Join(ianaCiphers, ","),
128-
TLSMinVersion: string(tlsProfile.MinTLSVersion),
139+
TLSCipherSuites: tlsCipherSuites,
140+
TLSMinVersion: tlsMinVersion,
129141
}
130142

131143
return config, nil

0 commit comments

Comments
 (0)