Skip to content
Draft
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
26 changes: 22 additions & 4 deletions cmd/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
package main

import (
"context"
"flag"
"os"
"time"
Expand Down Expand Up @@ -69,6 +70,7 @@ import (
templatev1 "github.com/openshift/api/template/v1"

checontroller "github.com/eclipse-che/che-operator/controllers/che"
"github.com/eclipse-che/che-operator/pkg/tlssetup"

admissionregistrationv1 "k8s.io/api/admissionregistration/v1"
utilruntime "k8s.io/apimachinery/pkg/util/runtime"
Expand Down Expand Up @@ -216,6 +218,8 @@ func main() {

config := ctrl.GetConfigOrDie()

serverTLS := tlssetup.BuildServerTLSOptions(context.Background(), config, scheme, setupLog)

discoveryClient, err := discovery.NewDiscoveryClientForConfig(config)
if err != nil {
setupLog.Error(err, "failed to create discovery client")
Expand All @@ -240,9 +244,15 @@ func main() {
}

mgr, err := ctrl.NewManager(config, ctrl.Options{
Scheme: scheme,
Metrics: server.Options{BindAddress: metricsAddr},
WebhookServer: webhook.NewServer(webhook.Options{Port: 9443}),
Scheme: scheme,
Metrics: server.Options{
BindAddress: metricsAddr,
TLSOpts: serverTLS.TLSOpts,
},
WebhookServer: webhook.NewServer(webhook.Options{
Port: 9443,
TLSOpts: serverTLS.TLSOpts,
}),
HealthProbeBindAddress: probeAddr,
LeaderElection: enableLeaderElection,
LeaderElectionID: "e79b08a4.org.eclipse.che",
Expand Down Expand Up @@ -309,6 +319,14 @@ func main() {
}
sigHandler := signal.SetupSignalHandler(terminationPeriod)

ctx, cancelCtx := context.WithCancel(sigHandler)
defer cancelCtx()

if err := tlssetup.RegisterSecurityProfileWatcher(mgr, serverTLS, cancelCtx, setupLog); err != nil {
setupLog.Error(err, "unable to set up TLS security profile watcher")
os.Exit(1)
}

if os.Getenv("ENABLE_WEBHOOKS") != "false" {
if err = chev2.SetupWebhookWithManager(mgr); err != nil {
setupLog.Error(err, "unable to create webhook", "webhook", "CheCluster")
Expand All @@ -328,7 +346,7 @@ func main() {

// Start the Cmd
setupLog.Info("starting manager")
if err := mgr.Start(sigHandler); err != nil {
if err := mgr.Start(ctx); err != nil {
setupLog.Error(err, "problem running manager")
os.Exit(1)
}
Expand Down
15 changes: 15 additions & 0 deletions config/rbac/cluster_role.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -259,6 +259,21 @@ rules:
- cluster
verbs:
- get
- apiGroups:
- config.openshift.io
resources:
- apiservers
resourceNames:
- cluster
verbs:
- get
- apiGroups:
- config.openshift.io
resources:
- apiservers
verbs:
- list
- watch
- apiGroups:
- ''
resources:
Expand Down
11 changes: 7 additions & 4 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,8 @@ require (
github.com/devfile/devworkspace-operator v0.42.0
github.com/go-logr/logr v1.4.4
github.com/google/go-cmp v0.7.0
github.com/openshift/api v0.0.0-20260325070019-86893981287e
github.com/openshift/api v0.0.0-20260805215214-cfb63858e9d7
github.com/openshift/controller-runtime-common v0.0.0-20260813135806-e1187ec555fc
github.com/operator-framework/api v0.41.0
github.com/operator-framework/operator-lifecycle-manager v0.41.0
github.com/prometheus-operator/prometheus-operator/pkg/apis/monitoring v0.86.2
Expand All @@ -20,7 +21,7 @@ require (
k8s.io/apiextensions-apiserver v0.36.2
k8s.io/apimachinery v0.36.2
k8s.io/client-go v0.36.2
k8s.io/utils v0.0.0-20260319190234-28399d86e0b5
k8s.io/utils v0.0.0-20260707023825-cf1189d6abe3
sigs.k8s.io/controller-runtime v0.24.1
sigs.k8s.io/yaml v1.6.0
)
Expand All @@ -40,9 +41,11 @@ require (
github.com/go-openapi/swag/typeutils v0.25.4 // indirect
github.com/go-openapi/swag/yamlutils v0.25.4 // indirect
github.com/google/cel-go v0.29.0 // indirect
github.com/openshift/library-go v0.0.0-20260807194649-ee0a87843dda // indirect
go.opentelemetry.io/otel/sdk/metric v1.43.0 // indirect
golang.org/x/exp v0.0.0-20260410095643-746e56fc9e2f // indirect
google.golang.org/genproto/googleapis/api v0.0.0-20260203192932-546029d2fa20 // indirect
k8s.io/apiserver v0.36.2 // indirect
)

require (
Expand Down Expand Up @@ -84,7 +87,7 @@ require (
golang.org/x/sys v0.47.0 // indirect
golang.org/x/term v0.45.0 // indirect
golang.org/x/text v0.40.0 // indirect
golang.org/x/time v0.14.0 // indirect
golang.org/x/time v0.15.0 // indirect
gomodules.xyz/jsonpatch/v2 v2.5.0 // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20260311181403-84a4fc48630c // indirect
google.golang.org/grpc v1.79.3 // indirect
Expand All @@ -93,7 +96,7 @@ require (
gopkg.in/inf.v0 v0.9.1 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
k8s.io/klog/v2 v2.140.0 // indirect
k8s.io/kube-openapi v0.0.0-20260317180543-43fb72c5454a // indirect
k8s.io/kube-openapi v0.0.0-20260519202549-bbf5c5577288 // indirect
sigs.k8s.io/json v0.0.0-20250730193827-2d320260d730 // indirect
sigs.k8s.io/randfill v1.0.0 // indirect
sigs.k8s.io/structured-merge-diff/v6 v6.3.2 // indirect
Expand Down
21 changes: 13 additions & 8 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -175,6 +175,7 @@ github.com/h2non/filetype v1.1.3 h1:FKkx9QbD7HR/zjK1Ia5XiBsq9zdLi5Kf3zGyFTAFkGg=
github.com/h2non/filetype v1.1.3/go.mod h1:319b3zT68BvV+WRj7cwy856M2ehB3HqNOt6sy1HndBY=
github.com/h2non/go-is-svg v0.0.0-20160927212452-35e8c4b0612c h1:fEE5/5VNnYUoBOj2I9TP8Jc+a7lge3QWn9DKE7NCwfc=
github.com/h2non/go-is-svg v0.0.0-20160927212452-35e8c4b0612c/go.mod h1:ObS/W+h8RYb1Y7fYivughjxojTmIu5iAIjSrSLCLeqE=
github.com/hashicorp/golang-lru v0.5.4 h1:YDjusn29QI/Das2iO9M0BHnIbxPeyuCHsjMW+lJfyTc=
github.com/hashicorp/golang-lru/arc/v2 v2.0.7 h1:QxkVTxwColcduO+LP7eJO56r2hFiG8zEbfAAzRv52KQ=
github.com/hashicorp/golang-lru/arc/v2 v2.0.7/go.mod h1:Pe7gBlGdc8clY5LJ0LpJXMt5AmgmWNH1g+oFFVUHOEc=
github.com/hashicorp/golang-lru/v2 v2.0.7 h1:a+bsQ5rvGLjzHuww6tVxozPZFVghXaHOwFs4luLUK2k=
Expand Down Expand Up @@ -229,8 +230,12 @@ github.com/opencontainers/image-spec v1.1.1 h1:y0fUlFfIZhPF1W537XOLg0/fcx6zcHCJw
github.com/opencontainers/image-spec v1.1.1/go.mod h1:qpqAh3Dmcf36wStyyWU+kCeDgrGnAve2nCC8+7h8Q0M=
github.com/opencontainers/runtime-spec v1.3.0 h1:YZupQUdctfhpZy3TM39nN9Ika5CBWT5diQ8ibYCRkxg=
github.com/opencontainers/runtime-spec v1.3.0/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0=
github.com/openshift/api v0.0.0-20260325070019-86893981287e h1:a5gc+sLpHw7rDpo7FoZfBAo/Wp0NTwDMbRNu+7W/D/o=
github.com/openshift/api v0.0.0-20260325070019-86893981287e/go.mod h1:pyVjK0nZ4sRs4fuQVQ4rubsJdahI1PB94LnQ8sGdvxo=
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/controller-runtime-common v0.0.0-20260813135806-e1187ec555fc h1:7v9PXV3WR5h8h4x44yfzFKwF0KrdiG6YTKV+26YIcfo=
github.com/openshift/controller-runtime-common v0.0.0-20260813135806-e1187ec555fc/go.mod h1:zyxfp5JNVAFiTBwG0j+RxKPeLUVIEuzkeGMvTeYMaoA=
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/operator-framework/api v0.41.0 h1:B0nutndl95elbLXJGRlkFNTI8OuZIjSqvTEeORPhTKo=
github.com/operator-framework/api v0.41.0/go.mod h1:Ouud+eqruzll9X3iv8wuAOTNAyyEncYXp4IVgbIlIdg=
github.com/operator-framework/operator-lifecycle-manager v0.41.0 h1:t7NZbtKXojAqqGD1LwL0F8pdrlplzqVunMUgrwRdHJo=
Expand Down Expand Up @@ -384,8 +389,8 @@ golang.org/x/term v0.45.0 h1:NwWyBmoJCbfTHpxrWoZ9C6/VxOf7ic219I8xZZFdrf0=
golang.org/x/term v0.45.0/go.mod h1:9aqxs0blBcrm/n0L9QW0aRVD+ktan8ssZromtqJC43w=
golang.org/x/text v0.40.0 h1:Ub2Z6/xjgF1WrYQz2nuITOEegKFtiIy+rieRJ5lHZKs=
golang.org/x/text v0.40.0/go.mod h1:hpnzDAfGV753zIKo+wk3u1bVKCGPbrnF7+7LBF/UHVY=
golang.org/x/time v0.14.0 h1:MRx4UaLrDotUKUdCIqzPC48t1Y9hANFKIRpNx+Te8PI=
golang.org/x/time v0.14.0/go.mod h1:eL/Oa2bBBK0TkX57Fyni+NgnyQQN4LitPmob2Hjnqw4=
golang.org/x/time v0.15.0 h1:bbrp8t3bGUeFOx08pvsMYRTCVSMk89u4tKbNOZbp88U=
golang.org/x/time v0.15.0/go.mod h1:Y4YMaQmXwGQZoFaVFk4YpCt4FLQMYKZe9oeV/f4MSno=
golang.org/x/tools v0.47.0 h1:7Kn5x/d1svx/PzryTsqeoZN4TZwqeH5pGWjefhLi/1Q=
golang.org/x/tools v0.47.0/go.mod h1:dFHnyTvFWY212G+h7ZY4Vsp/K3U4/7W9TyVaAul8uCA=
gomodules.xyz/jsonpatch/v2 v2.5.0 h1:JELs8RLM12qJGXU4u/TO3V25KW8GreMKl9pdkk14RM0=
Expand Down Expand Up @@ -427,10 +432,10 @@ k8s.io/component-base v0.36.2 h1:Z0VH80O7Ng0HDZnZj3WRR3urEGa0kTwmO8CwEwjVK1w=
k8s.io/component-base v0.36.2/go.mod h1:mGfFOA7Gwpdm1VW2cwSQYbiDIlz8GD2WGwH88QSeCyA=
k8s.io/klog/v2 v2.140.0 h1:Tf+J3AH7xnUzZyVVXhTgGhEKnFqye14aadWv7bzXdzc=
k8s.io/klog/v2 v2.140.0/go.mod h1:o+/RWfJ6PwpnFn7OyAG3QnO47BFsymfEfrz6XyYSSp0=
k8s.io/kube-openapi v0.0.0-20260317180543-43fb72c5454a h1:xCeOEAOoGYl2jnJoHkC3hkbPJgdATINPMAxaynU2Ovg=
k8s.io/kube-openapi v0.0.0-20260317180543-43fb72c5454a/go.mod h1:uGBT7iTA6c6MvqUvSXIaYZo9ukscABYi2btjhvgKGZ0=
k8s.io/utils v0.0.0-20260319190234-28399d86e0b5 h1:kBawHLSnx/mYHmRnNUf9d4CpjREbeZuxoSGOX/J+aYM=
k8s.io/utils v0.0.0-20260319190234-28399d86e0b5/go.mod h1:xDxuJ0whA3d0I4mf/C4ppKHxXynQ+fxnkmQH0vTHnuk=
k8s.io/kube-openapi v0.0.0-20260519202549-bbf5c5577288 h1:A7Lby6ekC6nv+6oO38huCMFBRP0Os+tIeq1GkwxOQes=
k8s.io/kube-openapi v0.0.0-20260519202549-bbf5c5577288/go.mod h1:V/QaCUYDa+0QpcHhVVc5l99Uz56wEMEXBSj9oCDkNDY=
k8s.io/utils v0.0.0-20260707023825-cf1189d6abe3 h1:jVkFFVfXdXP74B/zbO3hM3hpSFD0xvhQ5U686DPurkE=
k8s.io/utils v0.0.0-20260707023825-cf1189d6abe3/go.mod h1:M2s5JB1lIYP3jzZdorPLHXIPJzt9vv2muW5a6L9DtNM=
oras.land/oras-go/v2 v2.6.0 h1:X4ELRsiGkrbeox69+9tzTu492FMUu7zJQW6eJU+I2oc=
oras.land/oras-go/v2 v2.6.0/go.mod h1:magiQDfG6H1O9APp+rOsvCPcW1GD2MM7vgnKY0Y+u1o=
sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.34.0 h1:hSfpvjjTQXQY2Fol2CS0QHMNs/WI1MOSGzCm1KhM5ec=
Expand Down
114 changes: 114 additions & 0 deletions pkg/tlssetup/server_tls.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
//
// Copyright (c) 2019-2026 Red Hat, Inc.
// This program and the accompanying materials are made
// available under the terms of the Eclipse Public License 2.0
// which is available at https://www.eclipse.org/legal/epl-2.0/
//
// SPDX-License-Identifier: EPL-2.0
//
// Contributors:
// Red Hat, Inc. - initial API and implementation
//

package tlssetup

import (
"context"
"crypto/tls"

"github.com/go-logr/logr"
configv1 "github.com/openshift/api/config/v1"
tlspkg "github.com/openshift/controller-runtime-common/pkg/tls"
k8sruntime "k8s.io/apimachinery/pkg/runtime"
"k8s.io/client-go/rest"
"sigs.k8s.io/controller-runtime/pkg/client"
"sigs.k8s.io/controller-runtime/pkg/manager"

"github.com/eclipse-che/che-operator/pkg/common/infrastructure"
)

// ServerTLS holds TLS options and initial profile/policy for watcher
type ServerTLS struct {
TLSOpts []func(*tls.Config)
InitialTLSProfileSpec configv1.TLSProfileSpec
InitialTLSAdherencePolicy configv1.TLSAdherencePolicy
profileFetched bool
}

// BuildServerTLSOptions fetches TLS profile and adherence policy from cluster.
// Returns TLS config functions when adherence policy requires strict compliance.
// Falls back to empty TLSOpts on non-OpenShift, RBAC failures, or legacy adherence policy.
func BuildServerTLSOptions(ctx context.Context, cfg *rest.Config, scheme *k8sruntime.Scheme, log logr.Logger) ServerTLS {
if !infrastructure.IsOpenShift() {
return ServerTLS{}
}

cl, err := client.New(cfg, client.Options{Scheme: scheme})
if err != nil {
log.Error(err, "failed to create client for TLS profile fetch")
return ServerTLS{}
}

profile, err := tlspkg.FetchAPIServerTLSProfile(ctx, cl)
if err != nil {
log.Error(err, "failed to fetch TLS profile, using Go defaults")
return ServerTLS{}
}

adherence, err := tlspkg.FetchAPIServerTLSAdherencePolicy(ctx, cl)
if err != nil {
log.Error(err, "failed to fetch TLS adherence policy, using Go defaults")
return ServerTLS{}
}

serverTLS := ServerTLS{
InitialTLSProfileSpec: profile,
InitialTLSAdherencePolicy: adherence,
profileFetched: true,
}

if shouldHonorClusterTLSProfile(adherence) {
tlsConfigFn, unsupported := tlspkg.NewTLSConfigFromProfile(profile)
if len(unsupported) > 0 {
log.Info("TLS profile contains ciphers unsupported by Go", "unsupported", unsupported)
}
serverTLS.TLSOpts = []func(*tls.Config){tlsConfigFn}
}

return serverTLS
}

// RegisterSecurityProfileWatcher sets up watcher to restart operator when profile/policy changes.
// Only registers when profile was successfully fetched.
func RegisterSecurityProfileWatcher(mgr manager.Manager, serverTLS ServerTLS, onCancel context.CancelFunc, log logr.Logger) error {
if !serverTLS.profileFetched {
return nil
}

watcher := &tlspkg.SecurityProfileWatcher{
Client: mgr.GetClient(),
InitialTLSProfileSpec: serverTLS.InitialTLSProfileSpec,
InitialTLSAdherencePolicy: serverTLS.InitialTLSAdherencePolicy,
OnProfileChange: func(_ context.Context, old, new configv1.TLSProfileSpec) {
log.Info("TLS security profile changed, restarting operator")
onCancel()
},
OnAdherencePolicyChange: func(_ context.Context, old, new configv1.TLSAdherencePolicy) {
log.Info("TLS adherence policy changed, restarting operator")
onCancel()
},
}

return watcher.SetupWithManager(mgr)
}

// shouldHonorClusterTLSProfile returns true when tlsAdherence requires strict adherence.
// Unknown values return true for forward compatibility.
func shouldHonorClusterTLSProfile(adherence configv1.TLSAdherencePolicy) bool {
switch adherence {
case configv1.TLSAdherencePolicyNoOpinion, configv1.TLSAdherencePolicyLegacyAdheringComponentsOnly:
return false
default:
return true
}
}
1 change: 1 addition & 0 deletions vendor/github.com/openshift/api/config/v1/doc.go

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

2 changes: 2 additions & 0 deletions vendor/github.com/openshift/api/config/v1/register.go

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

5 changes: 5 additions & 0 deletions vendor/github.com/openshift/api/config/v1/types.go

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
Loading