Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
75 changes: 44 additions & 31 deletions cmd/cluster-cloud-controller-manager-operator/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import (
"errors"
"flag"
"os"
"strings"
"time"

"github.com/spf13/pflag"
Expand All @@ -34,6 +35,7 @@ import (
"k8s.io/apimachinery/pkg/runtime"
utilruntime "k8s.io/apimachinery/pkg/util/runtime"
clientgoscheme "k8s.io/client-go/kubernetes/scheme"
cliflag "k8s.io/component-base/cli/flag"
"k8s.io/component-base/config"
"k8s.io/component-base/config/options"
"k8s.io/klog/v2"
Expand All @@ -56,6 +58,7 @@ import (
rbacv1 "k8s.io/api/rbac/v1"

"github.com/openshift/cluster-cloud-controller-manager-operator/pkg/controllers"
pkgtls "github.com/openshift/cluster-cloud-controller-manager-operator/pkg/tls"
"github.com/openshift/cluster-cloud-controller-manager-operator/pkg/util"
// +kubebuilder:scaffold:imports
)
Expand Down Expand Up @@ -119,8 +122,16 @@ func main() {
// to allow leader lection flags to be bound
pflag.CommandLine.AddGoFlagSet(flag.CommandLine)
options.BindLeaderElectionFlags(&leaderElectionConfig, pflag.CommandLine)

tlsMinVersionFlag := pflag.String("tls-min-version", "",
"Minimum TLS version supported. When set, overrides the cluster-wide TLS profile. Possible values: "+strings.Join(cliflag.TLSPossibleVersions(), ", "))
tlsCipherSuitesFlag := pflag.StringSlice("tls-cipher-suites", nil,
"Comma-separated list of cipher suites for the server. When set, overrides the cluster-wide TLS profile. Possible values: "+strings.Join(cliflag.TLSCipherPossibleValues(), ", "))

pflag.Parse()

tlsOverrideFromFlags := *tlsMinVersionFlag != "" || len(*tlsCipherSuitesFlag) > 0

ctrl.SetLogger(klog.NewKlogr().WithName("CCMOperator"))

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

k8sClient, err := client.New(restConfig, client.Options{Scheme: scheme})
if err != nil {
setupLog.Error(err, "unable to create Kubernetes client")
os.Exit(1)
}

// Fetch the TLS profile from the APIServer resource.
tlsProfileSpec, err := utiltls.FetchAPIServerTLSProfile(ctx, k8sClient)
// Resolve the TLS configuration for the server endpoints.
tlsResult, err := pkgtls.ResolveTLSConfig(ctx, restConfig, *tlsMinVersionFlag, *tlsCipherSuitesFlag)
if err != nil {
setupLog.Error(err, "unable to get TLS profile from API server")
setupLog.Error(err, "unable to configure TLS")
os.Exit(1)
}

// Create the TLS configuration function for the server endpoints.
tlsConfigFunc, unsupportedCiphers := utiltls.NewTLSConfigFromProfile(tlsProfileSpec)
if len(unsupportedCiphers) > 0 {
setupLog.Info("Some ciphers from TLS profile are not supported", "unsupportedCiphers", unsupportedCiphers)
}
tlsOpts := []func(*tls.Config){tlsConfigFunc}
tlsOpts := []func(*tls.Config){tlsResult.TLSConfig}

syncPeriod := 10 * time.Minute
mgr, err := ctrl.NewManager(restConfig, ctrl.Options{
Expand Down Expand Up @@ -265,26 +264,40 @@ func main() {
Scheme: mgr.GetScheme(),
ImagesFile: *imagesFile,
FeatureGateAccess: featureGateAccessor,
TLSProfileSpec: tlsProfileSpec,
TLSConfig: tlsResult.TLSConfig,
}).SetupWithManager(mgr); err != nil {
setupLog.Error(err, "unable to create controller", "controller", "ClusterOperator")
os.Exit(1)
}

// Set up the TLS security profile watcher to watch for TLS config changes
if err = (&utiltls.SecurityProfileWatcher{
Client: mgr.GetClient(),
InitialTLSProfileSpec: tlsProfileSpec,
OnProfileChange: func(ctx context.Context, oldTLSProfileSpec, newTLSProfileSpec configv1.TLSProfileSpec) {
klog.Infof("TLS profile has changed, initiating a shutdown to reload it. %q: %+v, %q: %+v",
"old profile", oldTLSProfileSpec,
"new profile", newTLSProfileSpec,
)
cancel()
},
}).SetupWithManager(mgr); err != nil {
setupLog.Error(err, "unable to create controller", "controller", "TLSSecurityProfileWatcher")
os.Exit(1)
// Set up the TLS security profile watcher controller.
// When TLS is overridden via CLI flags, the watcher is not needed since
// the component is not reading from apiservers.config.openshift.io/cluster.
if tlsOverrideFromFlags {
setupLog.Info("TLS security profile watcher disabled because TLS is configured via CLI flags")
} else {
if err = (&utiltls.SecurityProfileWatcher{
Client: mgr.GetClient(),
InitialTLSAdherencePolicy: tlsResult.TLSAdherencePolicy,
InitialTLSProfileSpec: tlsResult.TLSProfileSpec,
OnAdherencePolicyChange: func(ctx context.Context, oldTLSAdherencePolicy, newTLSAdherencePolicy configv1.TLSAdherencePolicy) {
klog.Infof("TLS adherence policy has changed, initiating a shutdown to reload it. %q: %+v, %q: %+v",
"old adherence policy", oldTLSAdherencePolicy,
"new adherence policy", newTLSAdherencePolicy,
)
cancel()
},
OnProfileChange: func(ctx context.Context, oldTLSProfileSpec, newTLSProfileSpec configv1.TLSProfileSpec) {
klog.Infof("TLS profile has changed, initiating a shutdown to reload it. %q: %+v, %q: %+v",
"old profile", oldTLSProfileSpec,
"new profile", newTLSProfileSpec,
)
cancel()
},
}).SetupWithManager(mgr); err != nil {
setupLog.Error(err, "unable to create controller", "controller", "TLSSecurityProfileWatcher")
os.Exit(1)
}
}

// +kubebuilder:scaffold:builder
Expand Down
16 changes: 8 additions & 8 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -12,21 +12,21 @@ require (
github.com/golangci/golangci-lint/v2 v2.11.1
github.com/onsi/ginkgo/v2 v2.28.1
github.com/onsi/gomega v1.39.1
github.com/openshift/api v0.0.0-20260306002634-d3bbdada155c
github.com/openshift/client-go v0.0.0-20260306160707-3935d929fc7d
github.com/openshift/api v0.0.0-20260317165824-54a3998d81eb
github.com/openshift/client-go v0.0.0-20260317180604-743f664b82d1
github.com/openshift/cluster-api-actuator-pkg/testutils v0.0.0-20260310144400-bec013a007a8
github.com/openshift/controller-runtime-common v0.0.0-20260307102856-5db94f69ad3a
github.com/openshift/library-go v0.0.0-20260311094140-ac826d10cb40
github.com/openshift/controller-runtime-common v0.0.0-20260318085703-1812aed6dbd2
github.com/openshift/library-go v0.0.0-20260318142011-72bf34f474bc
github.com/spf13/cobra v1.10.2
github.com/spf13/pflag v1.0.10
github.com/stretchr/testify v1.11.1
gopkg.in/gcfg.v1 v1.2.3
gopkg.in/ini.v1 v1.67.1
gopkg.in/yaml.v2 v2.4.0
k8s.io/api v0.35.1
k8s.io/api v0.35.2
k8s.io/apiextensions-apiserver v0.35.1
k8s.io/apimachinery v0.35.1
k8s.io/client-go v0.35.1
k8s.io/apimachinery v0.35.2
k8s.io/client-go v0.35.2
k8s.io/cloud-provider-aws v1.35.1
k8s.io/cloud-provider-vsphere v1.34.0
k8s.io/component-base v0.35.1
Expand All @@ -35,7 +35,7 @@ require (
k8s.io/utils v0.0.0-20260210185600-b8788abfbbc2
sigs.k8s.io/cloud-provider-azure v1.35.1
sigs.k8s.io/cloud-provider-azure/pkg/azclient v0.13.0
sigs.k8s.io/controller-runtime v0.23.2
sigs.k8s.io/controller-runtime v0.23.3
sigs.k8s.io/controller-runtime/tools/setup-envtest v0.0.0-20251103140007-7a1b16d039d2
sigs.k8s.io/controller-tools v0.20.1
sigs.k8s.io/yaml v1.6.0
Expand Down
32 changes: 16 additions & 16 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -466,16 +466,16 @@ github.com/onsi/gomega v1.39.1 h1:1IJLAad4zjPn2PsnhH70V4DKRFlrCzGBNrNaru+Vf28=
github.com/onsi/gomega v1.39.1/go.mod h1:hL6yVALoTOxeWudERyfppUcZXjMwIMLnuSfruD2lcfg=
github.com/openshift-cloud-team/cloud-provider-vsphere v1.19.1-0.20260317135518-758abc9d59a5 h1:Mayj50dtdLPzUVmJNHJpM4GpFWq7fcy9FDIoYUfngQ4=
github.com/openshift-cloud-team/cloud-provider-vsphere v1.19.1-0.20260317135518-758abc9d59a5/go.mod h1:3uaiy47HteyMlDjJankjteem/s1hnbRBU1FgbekLMKU=
github.com/openshift/api v0.0.0-20260306002634-d3bbdada155c h1:YQYiDzOLJzwQunxCaa5OpyNyMLPz4HJ2CLaKqUQOQjQ=
github.com/openshift/api v0.0.0-20260306002634-d3bbdada155c/go.mod h1:pyVjK0nZ4sRs4fuQVQ4rubsJdahI1PB94LnQ8sGdvxo=
github.com/openshift/client-go v0.0.0-20260306160707-3935d929fc7d h1:T+9HFgEEcnu1TDDfsO5JcJC6N0/Kzob5AtG9IpITHJ8=
github.com/openshift/client-go v0.0.0-20260306160707-3935d929fc7d/go.mod h1:tIA3XSb/WsC/Fg0YNRfs/JrMrloBKPGF+NKVutd7nMI=
github.com/openshift/api v0.0.0-20260317165824-54a3998d81eb h1:iwBR3mzmyE3EMFx7R3CQ9lOccTS0dNht8TW82aGITg0=
github.com/openshift/api v0.0.0-20260317165824-54a3998d81eb/go.mod h1:pyVjK0nZ4sRs4fuQVQ4rubsJdahI1PB94LnQ8sGdvxo=
github.com/openshift/client-go v0.0.0-20260317180604-743f664b82d1 h1:Hr/R38eg5ZJXfbiaHumjJIN1buDZwhsm4ys4npVCXH0=
github.com/openshift/client-go v0.0.0-20260317180604-743f664b82d1/go.mod h1:Za51LlH76ALiQ/aKGBYJXmyJNkA//IDJ+I///30CA2M=
github.com/openshift/cluster-api-actuator-pkg/testutils v0.0.0-20260310144400-bec013a007a8 h1:x62h16RetnB1ZP+zjSM9fsoMz98g95zte+DXeUDF34o=
github.com/openshift/cluster-api-actuator-pkg/testutils v0.0.0-20260310144400-bec013a007a8/go.mod h1:n8RwIitgr5SAfvisrU0Ps+Szrn545DBU7nqtwATZphw=
github.com/openshift/controller-runtime-common v0.0.0-20260307102856-5db94f69ad3a h1:EQfdaEHOOBDkbvyHAn69u6eZDMuHPK3CTr1i89eEmss=
github.com/openshift/controller-runtime-common v0.0.0-20260307102856-5db94f69ad3a/go.mod h1:9HQZbBpikedL8l9mQpaDB4C15FNgLlnNuLP5ADrkVOI=
github.com/openshift/library-go v0.0.0-20260311094140-ac826d10cb40 h1:0Q7pg6Et+9Zg5wlom0hX4viqTtyRSj2uVjX74N6gcBw=
github.com/openshift/library-go v0.0.0-20260311094140-ac826d10cb40/go.mod h1:D797O/ssKTNglbrGchjIguFq+DbyRYdeds5w4/VTrKM=
github.com/openshift/controller-runtime-common v0.0.0-20260318085703-1812aed6dbd2 h1:GrZlVichOCE/lz8fg1+eNrAtkM0VSlqa9buuzN0vnb0=
github.com/openshift/controller-runtime-common v0.0.0-20260318085703-1812aed6dbd2/go.mod h1:XGabTMnNbz0M5Oa7IbscZp/jmcc7aHobvOCUWwkzKvM=
github.com/openshift/library-go v0.0.0-20260318142011-72bf34f474bc h1:a+rVRzEdFIwgDQLTbhiG3MEVuBXjLb/6HJRikTob+nY=
github.com/openshift/library-go v0.0.0-20260318142011-72bf34f474bc/go.mod h1:3bi4pLpYRdVd1aEhsHfRTJkwxwPLfRZ+ZePn3RmJd2k=
github.com/otiai10/copy v1.2.0/go.mod h1:rrF5dJ5F0t/EWSYODDu4j9/vEeYHMkc8jt0zJChqQWw=
github.com/otiai10/copy v1.14.0 h1:dCI/t1iTdYGtkvCuBG2BgR6KZa83PTclw4U5n2wAllU=
github.com/otiai10/copy v1.14.0/go.mod h1:ECfuL02W+/FkTWZWgQqXPWZgW9oeKCSQ5qVfSc4qc4w=
Expand Down Expand Up @@ -829,16 +829,16 @@ gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
honnef.co/go/tools v0.7.0 h1:w6WUp1VbkqPEgLz4rkBzH/CSU6HkoqNLp6GstyTx3lU=
honnef.co/go/tools v0.7.0/go.mod h1:pm29oPxeP3P82ISxZDgIYeOaf9ta6Pi0EWvCFoLG2vc=
k8s.io/api v0.35.1 h1:0PO/1FhlK/EQNVK5+txc4FuhQibV25VLSdLMmGpDE/Q=
k8s.io/api v0.35.1/go.mod h1:28uR9xlXWml9eT0uaGo6y71xK86JBELShLy4wR1XtxM=
k8s.io/api v0.35.2 h1:tW7mWc2RpxW7HS4CoRXhtYHSzme1PN1UjGHJ1bdrtdw=
k8s.io/api v0.35.2/go.mod h1:7AJfqGoAZcwSFhOjcGM7WV05QxMMgUaChNfLTXDRE60=
k8s.io/apiextensions-apiserver v0.35.1 h1:p5vvALkknlOcAqARwjS20kJffgzHqwyQRM8vHLwgU7w=
k8s.io/apiextensions-apiserver v0.35.1/go.mod h1:2CN4fe1GZ3HMe4wBr25qXyJnJyZaquy4nNlNmb3R7AQ=
k8s.io/apimachinery v0.35.1 h1:yxO6gV555P1YV0SANtnTjXYfiivaTPvCTKX6w6qdDsU=
k8s.io/apimachinery v0.35.1/go.mod h1:jQCgFZFR1F4Ik7hvr2g84RTJSZegBc8yHgFWKn//hns=
k8s.io/apimachinery v0.35.2 h1:NqsM/mmZA7sHW02JZ9RTtk3wInRgbVxL8MPfzSANAK8=
k8s.io/apimachinery v0.35.2/go.mod h1:jQCgFZFR1F4Ik7hvr2g84RTJSZegBc8yHgFWKn//hns=
k8s.io/apiserver v0.35.1 h1:potxdhhTL4i6AYAa2QCwtlhtB1eCdWQFvJV6fXgJzxs=
k8s.io/apiserver v0.35.1/go.mod h1:BiL6Dd3A2I/0lBnteXfWmCFobHM39vt5+hJQd7Lbpi4=
k8s.io/client-go v0.35.1 h1:+eSfZHwuo/I19PaSxqumjqZ9l5XiTEKbIaJ+j1wLcLM=
k8s.io/client-go v0.35.1/go.mod h1:1p1KxDt3a0ruRfc/pG4qT/3oHmUj1AhSHEcxNSGg+OA=
k8s.io/client-go v0.35.2 h1:YUfPefdGJA4aljDdayAXkc98DnPkIetMl4PrKX97W9o=
k8s.io/client-go v0.35.2/go.mod h1:4QqEwh4oQpeK8AaefZ0jwTFJw/9kIjdQi0jpKeYvz7g=
k8s.io/cloud-provider-aws v1.35.1 h1:alBjzyitPhOeeHebdt6NbI64tm4MKrj7+Uo/CzYOx1U=
k8s.io/cloud-provider-aws v1.35.1/go.mod h1:6R9TIgQ/ecysPukSmEUs4kZIwqvju80+FjMAhtJ22Q0=
k8s.io/code-generator v0.35.1 h1:yLKR2la7Z9cWT5qmk67ayx8xXLM4RRKQMnC8YPvTWRI=
Expand Down Expand Up @@ -869,8 +869,8 @@ sigs.k8s.io/cloud-provider-azure/pkg/azclient v0.13.0 h1:MmCsEs5tx/5W1uRV8+Iv0tD
sigs.k8s.io/cloud-provider-azure/pkg/azclient v0.13.0/go.mod h1:zIU1j1Q/+kHoYXtww3j8qDm3bPeeRYLD9JRipBR+HZQ=
sigs.k8s.io/cloud-provider-azure/pkg/azclient/configloader v0.11.0 h1:xbQUC6pfgnxPE1pKiYIRmR5HkyZ7StB7fnZwQ6pr0eE=
sigs.k8s.io/cloud-provider-azure/pkg/azclient/configloader v0.11.0/go.mod h1:9lQ7K/C/ms3OEDRlzLg2zyJVieNjV/7WfsQmOSnDaOQ=
sigs.k8s.io/controller-runtime v0.23.2 h1:Oh3FliXaA2CS1chpUXvjVNJtsvGZYUxQH8s7bvR7aXk=
sigs.k8s.io/controller-runtime v0.23.2/go.mod h1:B6COOxKptp+YaUT5q4l6LqUJTRpizbgf9KSRNdQGns0=
sigs.k8s.io/controller-runtime v0.23.3 h1:VjB/vhoPoA9l1kEKZHBMnQF33tdCLQKJtydy4iqwZ80=
sigs.k8s.io/controller-runtime v0.23.3/go.mod h1:B6COOxKptp+YaUT5q4l6LqUJTRpizbgf9KSRNdQGns0=
sigs.k8s.io/controller-runtime/tools/setup-envtest v0.0.0-20251103140007-7a1b16d039d2 h1:xLNIemrdP6o6uyzoBQEf83zPX9nO1G10t7sttZ3qz20=
sigs.k8s.io/controller-runtime/tools/setup-envtest v0.0.0-20251103140007-7a1b16d039d2/go.mod h1:sWEAaKdjIb8+pUyzfpeClTvbK2vTRdeF39lz/ee4EMU=
sigs.k8s.io/controller-tools v0.20.1 h1:gkfMt9YodI0K85oT8rVi80NTXO/kDmabKR5Ajn5GYxs=
Expand Down
22 changes: 17 additions & 5 deletions pkg/config/config.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package config

import (
"crypto/tls"
"encoding/json"
"fmt"
"os"
Expand Down Expand Up @@ -85,7 +86,7 @@ func getImagesFromJSONFile(filePath string) (ImagesReference, error) {
}

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

// Convert OpenSSL cipher names from the TLS profile to IANA names expected by CCM CLI flags.
ianaCiphers := libgocrypto.OpenSSLToIANACipherSuites(tlsProfile.Ciphers)
var tlsCipherSuites string
var tlsMinVersion string

if tlsConfig != nil {
resolved := &tls.Config{}
tlsConfig(resolved)

tlsMinVersion = libgocrypto.TLSVersionToNameOrDie(resolved.MinVersion)

if resolved.MinVersion != tls.VersionTLS13 {
tlsCipherSuites = strings.Join(libgocrypto.CipherSuitesToNamesOrDie(resolved.CipherSuites), ",")
}
}

config := OperatorConfig{
PlatformStatus: infrastructure.Status.PlatformStatus.DeepCopy(),
Expand All @@ -124,8 +136,8 @@ func ComposeConfig(infrastructure *configv1.Infrastructure, clusterProxy *config
IsSingleReplica: infrastructure.Status.ControlPlaneTopology == configv1.SingleReplicaTopologyMode,
FeatureGates: featureGatesString,
OCPFeatureGates: features,
TLSCipherSuites: strings.Join(ianaCiphers, ","),
TLSMinVersion: string(tlsProfile.MinTLSVersion),
TLSCipherSuites: tlsCipherSuites,
TLSMinVersion: tlsMinVersion,
}

return config, nil
Expand Down
Loading