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
9 changes: 6 additions & 3 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,10 @@ require (
github.com/mitchellh/mapstructure v1.5.0
github.com/onsi/ginkgo/v2 v2.28.1
github.com/onsi/gomega v1.39.1
github.com/openshift/api v0.0.0-20260728120005-8ba0b25b0f29
github.com/openshift/client-go v0.0.0-20260723174158-ae2315de9d73
github.com/openshift/api v0.0.0-20260805215214-cfb63858e9d7
github.com/openshift/client-go v0.0.0-20260806041845-b74fb348f1e7
github.com/openshift/controller-runtime-common v0.0.0-20260428152732-64ee174f5e2e
github.com/openshift/library-go v0.0.0-20260727154952-0aacacf2673e
github.com/openshift/library-go v0.0.0-20260807194649-ee0a87843dda
github.com/prometheus/client_golang v1.23.2
github.com/spf13/pflag v1.0.10
k8s.io/api v0.36.2
Expand Down Expand Up @@ -129,3 +129,6 @@ require (
sigs.k8s.io/kube-storage-version-migrator v0.0.6-0.20230721195810-5c8923c5ff96 // indirect
sigs.k8s.io/yaml v1.6.0 // indirect
)

// TODO: Remove this replace directive once the TLS groups/curve preferences support is merged and released in controller-runtime-common upstream.
replace github.com/openshift/controller-runtime-common => github.com/damdo/controller-runtime-common v0.0.0-20260811190531-d15ac976d032
16 changes: 8 additions & 8 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ github.com/cenkalti/backoff/v5 v5.0.3/go.mod h1:rkhZdG3JZukswDf7f0cwqPNk4K0sa+F9
github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs=
github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
github.com/cpuguy83/go-md2man/v2 v2.0.6/go.mod h1:oOW0eioCTA6cOiMLiUPZOpcVxMig6NIQQ7OS05n1F4g=
github.com/damdo/controller-runtime-common v0.0.0-20260811190531-d15ac976d032 h1:WKDblzIGYBrvbAqg+xFACBNd1FHGv2iuDrqizhCOLn4=
github.com/damdo/controller-runtime-common v0.0.0-20260811190531-d15ac976d032/go.mod h1:zyxfp5JNVAFiTBwG0j+RxKPeLUVIEuzkeGMvTeYMaoA=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM=
Expand Down Expand Up @@ -142,14 +144,12 @@ github.com/onsi/ginkgo/v2 v2.28.1 h1:S4hj+HbZp40fNKuLUQOYLDgZLwNUVn19N3Atb98NCyI
github.com/onsi/ginkgo/v2 v2.28.1/go.mod h1:CLtbVInNckU3/+gC8LzkGUb9oF+e8W8TdUsxPwvdOgE=
github.com/onsi/gomega v1.39.1 h1:1IJLAad4zjPn2PsnhH70V4DKRFlrCzGBNrNaru+Vf28=
github.com/onsi/gomega v1.39.1/go.mod h1:hL6yVALoTOxeWudERyfppUcZXjMwIMLnuSfruD2lcfg=
github.com/openshift/api v0.0.0-20260728120005-8ba0b25b0f29 h1:WrS2vkQtwJyo5xHJnJfjmHPDasdyKLKwojhMDV3tPto=
github.com/openshift/api v0.0.0-20260728120005-8ba0b25b0f29/go.mod h1:k6qH5QOVa5GDln2VVm8Jz4NV3Z7R2SATHFLwGS6Wh3M=
github.com/openshift/client-go v0.0.0-20260723174158-ae2315de9d73 h1:sM06vuu8s7EyWnOQZ4CMqLl2sJLFop1fL54GeK6nE0A=
github.com/openshift/client-go v0.0.0-20260723174158-ae2315de9d73/go.mod h1:qHlvvQ2Y5kt+AN/TrrmJPqdv9P4x5ho8+IpqiPCALUQ=
github.com/openshift/controller-runtime-common v0.0.0-20260428152732-64ee174f5e2e h1:k89oIo2EjX0PRSdi1kesktCyWp50SC9WwKurvupvRGs=
github.com/openshift/controller-runtime-common v0.0.0-20260428152732-64ee174f5e2e/go.mod h1:XGabTMnNbz0M5Oa7IbscZp/jmcc7aHobvOCUWwkzKvM=
github.com/openshift/library-go v0.0.0-20260727154952-0aacacf2673e h1:l6cLG0rB740YxNQRkwsrZFoBBTW9rDqfbtiS3bpACD4=
github.com/openshift/library-go v0.0.0-20260727154952-0aacacf2673e/go.mod h1:+y3GAquPZijlchEMMUAPd9cq+3oP42+SQwiQ+mYX91Q=
github.com/openshift/api v0.0.0-20260805215214-cfb63858e9d7 h1:Z6p+yoWjFXbfnN2zPdQ8SRXPKDs9QtT3P8hN3SP2zuw=
github.com/openshift/api v0.0.0-20260805215214-cfb63858e9d7/go.mod h1:k6qH5QOVa5GDln2VVm8Jz4NV3Z7R2SATHFLwGS6Wh3M=
github.com/openshift/client-go v0.0.0-20260806041845-b74fb348f1e7 h1:Lphm0uMAyM26ibbOca0+dg7uLz7GmmrIdeWjzOh5R/U=
github.com/openshift/client-go v0.0.0-20260806041845-b74fb348f1e7/go.mod h1:u08LcpI8Hq3IpelQLbciGRa/P158cE/O3uQe2Bt3Roo=
github.com/openshift/library-go v0.0.0-20260807194649-ee0a87843dda h1:yVQlJiQZGCi3ydS74ysAkLbP+bVbvAQaAuCDZi6UgDY=
github.com/openshift/library-go v0.0.0-20260807194649-ee0a87843dda/go.mod h1:IrZbEK+wVUMEd+aXzYR2DCCh0p5IaQ7DvycYGP7qIYM=
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
Expand Down
19 changes: 12 additions & 7 deletions main.go
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,7 @@ func main() {
var metricsBindAddress string
var tlsMinVersionFlag string
var tlsCipherSuitesFlag []string
var tlsCurvePreferencesFlag []int32

flagSet := flag.NewFlagSet("cluster-machine-approver", flag.ExitOnError)

Expand All @@ -99,6 +100,7 @@ func main() {
flagSet.StringVar(&metricsBindAddress, "metrics-bind-address", metrics.DefaultMetricsBindAddress, "the address the metrics endpoint binds to.")
flagSet.StringVar(&tlsMinVersionFlag, "tls-min-version", "", "Minimum TLS version supported. When set, overrides the cluster-wide TLS profile. Possible values: "+strings.Join(cliflag.TLSPossibleVersions(), ", "))
flagSet.StringSliceVar(&tlsCipherSuitesFlag, "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(), ", "))
flagSet.Int32SliceVar(&tlsCurvePreferencesFlag, "tls-curve-preferences", nil, "Comma-separated list of TLS curve preferences (as numeric Go crypto/tls CurveID values) for the server. When set, overrides the cluster-wide TLS profile. See https://pkg.go.dev/crypto/tls#CurveID for supported values.")

// Deprecated options
flagSet.StringVar(&apiGroup, "apigroup", "", "API group for machines")
Expand All @@ -110,7 +112,7 @@ func main() {
klog.Fatal("Cannot set both --apigroup and --api-group-version options together.")
}

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

var parsedAPIGroupVersions []schema.GroupVersion

Expand Down Expand Up @@ -152,17 +154,20 @@ func main() {
klog.Fatalf("Can't set client configs: %v", err)
}

// Create a context that can be cancelled when there is a need to shut down the manager.
ctx, cancel := context.WithCancel(control.SetupSignalHandler())
// Ensure the context is cancelled when the program exits.
defer cancel()

// Resolve the TLS configuration for the server endpoints.
tlsResult, err := pkgtls.ResolveTLSConfig(context.Background(), workloadConfig, tlsMinVersionFlag, tlsCipherSuitesFlag)
startupCtx, startupCancel := context.WithTimeout(ctx, 30*time.Second)
defer startupCancel()

tlsResult, err := pkgtls.ResolveTLSConfig(startupCtx, workloadConfig, tlsMinVersionFlag, tlsCipherSuitesFlag, tlsCurvePreferencesFlag)
if err != nil {
klog.Fatalf("unable to configure TLS: %v", err)
}

// Create a context that can be cancelled when there is a need to shut down the manager .
ctx, cancel := context.WithCancel(control.SetupSignalHandler())
// Ensure the context is cancelled when the program exits.
defer cancel()

// Create a new Cmd to provide shared dependencies and start components
klog.Info("setting up manager")
mgr, err := manager.New(workloadConfig, manager.Options{
Expand Down
28 changes: 18 additions & 10 deletions pkg/tls/tls.go
Original file line number Diff line number Diff line change
Expand Up @@ -48,18 +48,18 @@ type TLSConfigResult struct {
// take precedence over the cluster-wide TLS profile. When not set, the profile
// from apiservers.config.openshift.io/cluster is fetched and applied if the
// adherence policy requires it.
func ResolveTLSConfig(ctx context.Context, restConfig *rest.Config, tlsMinVersion string, tlsCipherSuites []string) (TLSConfigResult, error) {
func ResolveTLSConfig(ctx context.Context, restConfig *rest.Config, tlsMinVersion string, tlsCipherSuites []string, tlsCurvePreferences []int32) (TLSConfigResult, error) {
// If CLI flags are set they take precedence over the cluster-wide TLS profile.
if tlsMinVersion != "" || len(tlsCipherSuites) > 0 {
return resolveTLSConfigFromFlags(tlsMinVersion, tlsCipherSuites)
if tlsMinVersion != "" || len(tlsCipherSuites) > 0 || len(tlsCurvePreferences) > 0 {
return resolveTLSConfigFromFlags(tlsMinVersion, tlsCipherSuites, tlsCurvePreferences)
Comment thread
coderabbitai[bot] marked this conversation as resolved.
}

return resolveClusterTLSConfig(ctx, restConfig)
}

// resolveTLSConfigFromFlags builds a TLS configuration from CLI flag values,
// bypassing the cluster-wide TLS profile.
func resolveTLSConfigFromFlags(tlsMinVersion string, tlsCipherSuites []string) (TLSConfigResult, error) {
func resolveTLSConfigFromFlags(tlsMinVersion string, tlsCipherSuites []string, tlsCurvePreferences []int32) (TLSConfigResult, error) {
klog.Info("TLS configuration overridden via CLI flags, skipping honoring the cluster-wide TLS profile")

minVersion, err := cliflag.TLSVersion(tlsMinVersion)
Expand All @@ -72,9 +72,17 @@ func resolveTLSConfigFromFlags(tlsMinVersion string, tlsCipherSuites []string) (
return TLSConfigResult{}, fmt.Errorf("invalid --tls-cipher-suites value: %w", err)
}

curvePrefs, err := cliflag.TLSCurvePreferences(tlsCurvePreferences)
if err != nil {
return TLSConfigResult{}, fmt.Errorf("invalid --tls-curve-preferences value: %w", err)
}

return TLSConfigResult{
TLSConfig: func(cfg *tls.Config) {
cfg.MinVersion = minVersion
if len(curvePrefs) > 0 {
cfg.CurvePreferences = curvePrefs
}
Comment thread
coderabbitai[bot] marked this conversation as resolved.
// Only set CipherSuites when MinVersion is below TLS 1.3, as Go's TLS 1.3 implementation
// does not allow configuring cipher suites - all TLS 1.3 ciphers are always enabled.
// See: https://github.com/golang/go/issues/29349
Expand Down Expand Up @@ -122,19 +130,19 @@ func resolveClusterTLSConfig(ctx context.Context, restConfig *rest.Config) (TLSC
// If the cluster-wide TLS adherence policy is set to honor the cluster-wide TLS profile,
// use the cluster-wide TLS profile-based configuration.
if libgocrypto.ShouldHonorClusterTLSProfile(tlsAdherencePolicy) {
profileTLSConfig, unsupportedCiphers := utiltls.NewTLSConfigFromProfile(tlsProfileSpec)
if len(unsupportedCiphers) > 0 {
klog.Infof("TLS configuration contains unsupported ciphers that will be ignored: %v", unsupportedCiphers)
profileTLSConfig, unsupported := utiltls.NewTLSConfigFromProfile(tlsProfileSpec)
if len(unsupported) > 0 {
klog.Infof("TLS configuration contains unsupported ciphers/groups that will be ignored: %v", unsupported)
}

// Set the TLS configuration to the cluster-wide TLS profile-based configuration.
tlsConfig = profileTLSConfig
} else {
// If the cluster-wide TLS adherence policy is not set to honor the cluster-wide TLS profile,
// use the default TLS profile-based configuration.
defaultTLSConfig, unsupportedCiphers := utiltls.NewTLSConfigFromProfile(*configv1.TLSProfiles[libgocrypto.DefaultTLSProfileType])
if len(unsupportedCiphers) > 0 {
klog.Infof("TLS configuration contains unsupported ciphers that will be ignored: %v", unsupportedCiphers)
defaultTLSConfig, unsupported := utiltls.NewTLSConfigFromProfile(*configv1.TLSProfiles[libgocrypto.DefaultTLSProfileType])
if len(unsupported) > 0 {
klog.Infof("TLS configuration contains unsupported ciphers/groups that will be ignored: %v", unsupported)
}

// Set the TLS configuration to the default TLS profile-based configuration.
Expand Down
24 changes: 12 additions & 12 deletions pkg/tls/tls_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ var _ = Describe("ResolveTLSConfig", func() {
result, err := ResolveTLSConfig(ctx, cfg, "VersionTLS12", []string{
"TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256",
"TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384",
})
}, nil)
Expect(err).NotTo(HaveOccurred())

tlsCfg := &tls.Config{}
Expand All @@ -51,7 +51,7 @@ var _ = Describe("ResolveTLSConfig", func() {
It("should not set cipher suites when TLS 1.3 is specified", func() {
result, err := ResolveTLSConfig(ctx, cfg, "VersionTLS13", []string{
"TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256",
})
}, nil)
Expect(err).NotTo(HaveOccurred())

tlsCfg := &tls.Config{}
Expand All @@ -63,7 +63,7 @@ var _ = Describe("ResolveTLSConfig", func() {

It("should accept TLS 1.3 cipher suites from the Modern profile", func() {
modernProfile := configv1.TLSProfiles[configv1.TLSProfileModernType]
result, err := ResolveTLSConfig(ctx, cfg, string(modernProfile.MinTLSVersion), modernProfile.Ciphers)
result, err := ResolveTLSConfig(ctx, cfg, string(modernProfile.MinTLSVersion), modernProfile.Ciphers, nil)
Expect(err).NotTo(HaveOccurred())

tlsCfg := &tls.Config{}
Expand All @@ -76,7 +76,7 @@ var _ = Describe("ResolveTLSConfig", func() {
It("should not populate TLSAdherencePolicy or TLSProfileSpec", func() {
result, err := ResolveTLSConfig(ctx, cfg, "VersionTLS12", []string{
"TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256",
})
}, nil)
Expect(err).NotTo(HaveOccurred())

Expect(result.TLSAdherencePolicy).To(BeEmpty())
Expand All @@ -86,15 +86,15 @@ var _ = Describe("ResolveTLSConfig", func() {
It("should return an error for an invalid TLS version", func() {
_, err := ResolveTLSConfig(ctx, cfg, "InvalidVersion", []string{
"TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256",
})
}, nil)
Expect(err).To(HaveOccurred())
Expect(err.Error()).To(ContainSubstring("invalid --tls-min-version"))
})

It("should return an error for an invalid cipher suite", func() {
_, err := ResolveTLSConfig(ctx, cfg, "VersionTLS12", []string{
"INVALID_CIPHER_SUITE",
})
}, nil)
Expect(err).To(HaveOccurred())
Expect(err.Error()).To(ContainSubstring("invalid --tls-cipher-suites"))
})
Expand Down Expand Up @@ -125,7 +125,7 @@ var _ = Describe("ResolveTLSConfig", func() {
return k8sClient.Create(ctx, apiServer)
}).Should(Succeed())

result, err := ResolveTLSConfig(ctx, cfg, "", nil)
result, err := ResolveTLSConfig(ctx, cfg, "", nil, nil)
Expect(err).NotTo(HaveOccurred())

tlsCfg := &tls.Config{}
Expand Down Expand Up @@ -153,7 +153,7 @@ var _ = Describe("ResolveTLSConfig", func() {
return k8sClient.Create(ctx, apiServer)
}).Should(Succeed())

result, err := ResolveTLSConfig(ctx, cfg, "", nil)
result, err := ResolveTLSConfig(ctx, cfg, "", nil, nil)
Expect(err).NotTo(HaveOccurred())

tlsCfg := &tls.Config{}
Expand Down Expand Up @@ -184,7 +184,7 @@ var _ = Describe("ResolveTLSConfig", func() {
return k8sClient.Create(ctx, apiServer)
}).Should(Succeed())

result, err := ResolveTLSConfig(ctx, cfg, "", nil)
result, err := ResolveTLSConfig(ctx, cfg, "", nil, nil)
Expect(err).NotTo(HaveOccurred())

tlsCfg := &tls.Config{}
Expand Down Expand Up @@ -218,7 +218,7 @@ var _ = Describe("ResolveTLSConfig", func() {
return k8sClient.Create(ctx, apiServer)
}).Should(Succeed())

result, err := ResolveTLSConfig(ctx, cfg, "", nil)
result, err := ResolveTLSConfig(ctx, cfg, "", nil, nil)
Expect(err).NotTo(HaveOccurred())

tlsCfg := &tls.Config{}
Expand All @@ -232,7 +232,7 @@ var _ = Describe("ResolveTLSConfig", func() {
})

It("should gracefully default when no APIServer resource exists", func() {
result, err := ResolveTLSConfig(ctx, cfg, "", nil)
result, err := ResolveTLSConfig(ctx, cfg, "", nil, nil)
Expect(err).NotTo(HaveOccurred())

tlsCfg := &tls.Config{}
Expand Down Expand Up @@ -261,7 +261,7 @@ var _ = Describe("ResolveTLSConfig", func() {
return k8sClient.Create(ctx, apiServer)
}).Should(Succeed())

result, err := ResolveTLSConfig(ctx, cfg, "", nil)
result, err := ResolveTLSConfig(ctx, cfg, "", nil, nil)
Expect(err).NotTo(HaveOccurred())

Expect(result.TLSAdherencePolicy).To(Equal(configv1.TLSAdherencePolicyStrictAllComponents))
Expand Down

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading