diff --git a/cmd/main.go b/cmd/main.go index eddcfa67a..74b180870 100644 --- a/cmd/main.go +++ b/cmd/main.go @@ -17,11 +17,15 @@ limitations under the License. package main import ( + "context" "crypto/tls" "flag" + "fmt" "os" "time" + "github.com/go-logr/logr" + ostls "github.com/openshift/controller-runtime-common/pkg/tls" appconfig "github.com/securesign/operator/internal/config" "github.com/securesign/operator/internal/constants" "github.com/securesign/operator/internal/controller" @@ -34,6 +38,8 @@ import ( batchv1 "k8s.io/api/batch/v1" corev1 "k8s.io/api/core/v1" networkingv1 "k8s.io/api/networking/v1" + apiErrors "k8s.io/apimachinery/pkg/api/errors" + apimeta "k8s.io/apimachinery/pkg/api/meta" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/fields" "k8s.io/klog/v2" @@ -93,6 +99,11 @@ func init() { } func main() { + // Create a cancellable context from the signal handler. The TLS profile watcher + // uses cancel() to trigger a graceful restart when the cluster policy changes. + ctx, cancel := context.WithCancel(ctrl.SetupSignalHandler()) + defer cancel() + var ( metricsAddr string enableLeaderElection bool @@ -119,6 +130,10 @@ func main() { utils.BoolFlagOrEnv(&appconfig.Openshift, "openshift", "OPENSHIFT", false, "Enable to ensures the operator applies OpenShift specific configurations.") utils.StringFlagOrEnv(&appconfig.OpenshiftAPIServerName, "openshift-apiserver-name", "OPENSHIFT_APISERVER_NAME", "openshift-apiserver", "The OpenShift API Server name.") utils.DurationFlagOrEnv(&appconfig.APIServerTimeout, "apiserver-timeout", "APISERVER_TIMEOUT", 30*time.Second, "The initial timeout for contacting the API Server, defaults to 30 seconds.") + utils.BoolFlagOrEnv(&appconfig.DisableClusterTLSProfile, "disable-cluster-tls-profile", "DISABLE_CLUSTER_TLS_PROFILE", false, + "Disable reading the cluster-wide TLS security profile from configv1.APIServer. "+ + "When set, the operator uses Intermediate TLS profile defaults (TLS 1.2 minimum). "+ + "Use this as an escape hatch if the cluster profile causes compatibility issues.") utils.StringFlagOrEnv(&appconfig.IngressHostTemplate, "ingress-host-template", "INGRESS_HOST_TEMPLATE", appconfig.IngressHostTemplate, "Default hostname template for non-OpenShift Ingress resources when ExternalAccess.Host is not set. "+ "Uses Go fmt.Sprintf with %[1]s=service name, %[2]s=namespace. Ignored on OpenShift.") @@ -162,6 +177,38 @@ func main() { setupLog.Info("Platform explicitly configured via flag/env", "openshift", appconfig.Openshift) } + // Resolve the cluster TLS security profile once at startup, before the webhook and metrics + // servers are configured. A dedicated bootstrap client is used because the manager has not + // started yet. On vanilla Kubernetes (no configv1.APIServer) or when the flag is set, + // this falls back to the Intermediate profile. + var bootstrapClient client.Client + if appconfig.Openshift && !appconfig.DisableClusterTLSProfile { + var bootErr error + bootstrapClient, bootErr = client.New(ctrl.GetConfigOrDie(), client.Options{Scheme: scheme}) + if bootErr != nil { + setupLog.Error(bootErr, "unable to create bootstrap client for TLS profile resolution") + os.Exit(1) + } + } + + // Bound the profile resolution by the same timeout used for OpenShift auto-detection and + // derive it from the cancellable startup context, so a SIGTERM or a network partition during + // a slow bootstrap API call aborts startup instead of hanging indefinitely. + resolveCtx, resolveCancel := context.WithTimeout(ctx, appconfig.APIServerTimeout) + tlsProfileSpec, tlsAdherence, resolveErr := resolveClusterTLSProfile( + resolveCtx, bootstrapClient, appconfig.Openshift, appconfig.DisableClusterTLSProfile, setupLog) + resolveCancel() + if resolveErr != nil { + setupLog.Error(resolveErr, "unable to resolve cluster TLS security profile") + os.Exit(1) + } + + tlsConfigFn, unsupportedCiphers := ostls.NewTLSConfigFromProfile(tlsProfileSpec) + if len(unsupportedCiphers) > 0 { + setupLog.Info("cluster TLS profile contains ciphers unsupported by Go TLS", + "ciphers", unsupportedCiphers) + } + // if the enable-http2 flag is false (the default), http/2 should be disabled // due to its vulnerabilities. More specifically, disabling http/2 will // prevent from being vulnerable to the HTTP/2 Stream Cancelation and @@ -177,7 +224,7 @@ func main() { if !enableHTTP2 { tlsOpts = append(tlsOpts, disableHTTP2) } - + tlsOpts = append(tlsOpts, tlsConfigFn) webhookServer := webhook.NewServer(webhook.Options{ TLSOpts: tlsOpts, }) @@ -221,6 +268,16 @@ func main() { "metadata.name": "cluster", }), } + if !appconfig.DisableClusterTLSProfile { + // Restrict the APIServer cache to the single "cluster" object. + // The ClusterRole only grants access to this named resource, so a + // full cluster-wide list would be forbidden. + cacheOpts.ByObject[&configv1.APIServer{}] = cache.ByObject{ + Field: fields.SelectorFromSet(fields.Set{ + "metadata.name": "cluster", + }), + } + } } metricsOpts := metricsserver.Options{ @@ -264,6 +321,30 @@ func main() { os.Exit(1) } + // Watch the cluster TLS security profile for changes. When the profile or adherence + // policy changes, cancel() triggers a graceful shutdown so the operator restarts + // and picks up the new configuration. + if appconfig.Openshift && !appconfig.DisableClusterTLSProfile { + if err := (&ostls.SecurityProfileWatcher{ + Client: mgr.GetClient(), + InitialTLSProfileSpec: tlsProfileSpec, + InitialTLSAdherencePolicy: tlsAdherence, + OnProfileChange: func(_ context.Context, old, new configv1.TLSProfileSpec) { + setupLog.Info("cluster TLS profile changed; restarting to apply new configuration", + "old", old, "new", new) + cancel() + }, + OnAdherencePolicyChange: func(_ context.Context, old, new configv1.TLSAdherencePolicy) { + setupLog.Info("cluster TLS adherence policy changed; restarting to apply new configuration", + "old", old, "new", new) + cancel() + }, + }).SetupWithManager(mgr); err != nil { + setupLog.Error(err, "unable to set up TLS security profile watcher") + os.Exit(1) + } + } + setupController("securesign", securesign.NewReconciler, mgr) setupController("fulcio", fulcio.NewReconciler, mgr) setupController("trillian", trillian.NewReconciler, mgr) @@ -314,12 +395,56 @@ func main() { } setupLog.Info("starting manager") - if err := mgr.Start(ctrl.SetupSignalHandler()); err != nil { + if err := mgr.Start(ctx); err != nil { setupLog.Error(err, "problem running manager") os.Exit(1) } } +// resolveClusterTLSProfile determines the cluster TLS security profile and adherence policy to +// apply to the operator's webhook and metrics servers. +// +// On vanilla Kubernetes or when disabled is set, it returns the Intermediate profile defaults +// (TLS 1.2 minimum) without contacting the API server. On OpenShift it fetches the cluster-wide +// profile from the config.openshift.io APIServer, falling back to Intermediate defaults when the +// resource or API is unavailable. A non-nil error is returned only for unexpected failures that +// should abort startup. +func resolveClusterTLSProfile(ctx context.Context, cli client.Client, openshift, disabled bool, log logr.Logger) (configv1.TLSProfileSpec, configv1.TLSAdherencePolicy, error) { + intermediateSpec := *configv1.TLSProfiles[configv1.TLSProfileIntermediateType] + + if !openshift || disabled { + if !openshift { + log.Info("not running on OpenShift; using Intermediate TLS defaults") + } else { + log.Info("cluster TLS profile resolution disabled via flag; using Intermediate defaults") + } + return intermediateSpec, configv1.TLSAdherencePolicyNoOpinion, nil + } + + tlsProfileSpec, err := ostls.FetchAPIServerTLSProfile(ctx, cli) + if err != nil { + if apiErrors.IsNotFound(err) || apimeta.IsNoMatchError(err) { + log.Info("config.openshift.io APIServer not available; using Intermediate TLS defaults") + tlsProfileSpec = intermediateSpec + } else { + return configv1.TLSProfileSpec{}, "", fmt.Errorf("unable to fetch cluster TLS security profile: %w", err) + } + } + + tlsAdherence, err := ostls.FetchAPIServerTLSAdherencePolicy(ctx, cli) + if err != nil { + if apiErrors.IsNotFound(err) || apimeta.IsNoMatchError(err) { + log.Info("TLSAdherencePolicy API not available; defaulting to NoOpinion") + } else { + log.Error(err, "unable to fetch cluster TLS adherence policy; defaulting to NoOpinion") + } + tlsAdherence = configv1.TLSAdherencePolicyNoOpinion + } + + log.Info("cluster TLS security profile resolved") + return tlsProfileSpec, tlsAdherence, nil +} + func setupController(name string, constructor controller.Constructor, manager ctrl.Manager) { if err := constructor( manager.GetClient(), diff --git a/cmd/main_test.go b/cmd/main_test.go new file mode 100644 index 000000000..4e0774e5a --- /dev/null +++ b/cmd/main_test.go @@ -0,0 +1,195 @@ +/* +Copyright 2023. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package main + +import ( + "context" + "errors" + "testing" + + "github.com/go-logr/logr" + "github.com/onsi/gomega" + configv1 "github.com/openshift/api/config/v1" + apierrors "k8s.io/apimachinery/pkg/api/errors" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" + "sigs.k8s.io/controller-runtime/pkg/client" + "sigs.k8s.io/controller-runtime/pkg/client/fake" + "sigs.k8s.io/controller-runtime/pkg/client/interceptor" +) + +func tlsTestScheme(t *testing.T) *runtime.Scheme { + t.Helper() + s := runtime.NewScheme() + if err := configv1.AddToScheme(s); err != nil { + t.Fatalf("failed to add configv1 to scheme: %v", err) + } + return s +} + +func apiServerWith(profile *configv1.TLSSecurityProfile, adherence configv1.TLSAdherencePolicy) *configv1.APIServer { + return &configv1.APIServer{ + ObjectMeta: metav1.ObjectMeta{Name: "cluster"}, + Spec: configv1.APIServerSpec{ + TLSSecurityProfile: profile, + TLSAdherence: adherence, + }, + } +} + +// resolveClusterTLSProfile: non-OpenShift and disabled paths return Intermediate defaults +// without touching the client. +func TestResolveClusterTLSProfile_Defaults(t *testing.T) { + t.Parallel() + g := gomega.NewWithT(t) + intermediate := *configv1.TLSProfiles[configv1.TLSProfileIntermediateType] + + tests := []struct { + name string + openshift bool + disabled bool + }{ + {"vanilla kubernetes", false, false}, + {"openshift with resolution disabled", true, true}, + {"non-openshift with disable flag set", false, true}, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + // A nil client must never be dereferenced on these paths. + profile, adherence, err := resolveClusterTLSProfile( + context.Background(), nil, tt.openshift, tt.disabled, logr.Discard()) + + g.Expect(err).ToNot(gomega.HaveOccurred()) + g.Expect(profile.MinTLSVersion).To(gomega.Equal(intermediate.MinTLSVersion)) + g.Expect(adherence).To(gomega.Equal(configv1.TLSAdherencePolicyNoOpinion)) + }) + } +} + +// resolveClusterTLSProfile: on OpenShift the configured cluster profile and adherence policy +// are returned. +func TestResolveClusterTLSProfile_FetchesConfiguredProfile(t *testing.T) { + t.Parallel() + g := gomega.NewWithT(t) + modern := *configv1.TLSProfiles[configv1.TLSProfileModernType] + + cli := fake.NewClientBuilder(). + WithScheme(tlsTestScheme(t)). + WithObjects(apiServerWith( + &configv1.TLSSecurityProfile{Type: configv1.TLSProfileModernType}, + configv1.TLSAdherencePolicyStrictAllComponents, + )). + Build() + + profile, adherence, err := resolveClusterTLSProfile( + context.Background(), cli, true, false, logr.Discard()) + + g.Expect(err).ToNot(gomega.HaveOccurred()) + g.Expect(profile.MinTLSVersion).To(gomega.Equal(modern.MinTLSVersion)) + g.Expect(adherence).To(gomega.Equal(configv1.TLSAdherencePolicyStrictAllComponents)) +} + +// resolveClusterTLSProfile: when the APIServer resource is absent the resolver falls back to +// Intermediate defaults and NoOpinion adherence without erroring. +func TestResolveClusterTLSProfile_APIServerNotFound(t *testing.T) { + t.Parallel() + g := gomega.NewWithT(t) + intermediate := *configv1.TLSProfiles[configv1.TLSProfileIntermediateType] + + cli := fake.NewClientBuilder().WithScheme(tlsTestScheme(t)).Build() + + profile, adherence, err := resolveClusterTLSProfile( + context.Background(), cli, true, false, logr.Discard()) + + g.Expect(err).ToNot(gomega.HaveOccurred()) + g.Expect(profile.MinTLSVersion).To(gomega.Equal(intermediate.MinTLSVersion)) + g.Expect(adherence).To(gomega.Equal(configv1.TLSAdherencePolicyNoOpinion)) +} + +// resolveClusterTLSProfile: an unexpected error fetching the profile aborts startup. +func TestResolveClusterTLSProfile_ProfileFetchError(t *testing.T) { + t.Parallel() + g := gomega.NewWithT(t) + + boom := errors.New("connection refused") + cli := fake.NewClientBuilder(). + WithScheme(tlsTestScheme(t)). + WithInterceptorFuncs(interceptor.Funcs{ + Get: func(context.Context, client.WithWatch, client.ObjectKey, client.Object, ...client.GetOption) error { + return boom + }, + }). + Build() + + _, _, err := resolveClusterTLSProfile( + context.Background(), cli, true, false, logr.Discard()) + + g.Expect(err).To(gomega.HaveOccurred()) + g.Expect(err.Error()).To(gomega.ContainSubstring("unable to fetch cluster TLS security profile")) +} + +// resolveClusterTLSProfile: an unexpected error fetching only the adherence policy is tolerated; +// the resolver keeps the profile and defaults adherence to NoOpinion. +func TestResolveClusterTLSProfile_AdherenceFetchError(t *testing.T) { + t.Parallel() + g := gomega.NewWithT(t) + modern := *configv1.TLSProfiles[configv1.TLSProfileModernType] + + apiServer := apiServerWith( + &configv1.TLSSecurityProfile{Type: configv1.TLSProfileModernType}, + configv1.TLSAdherencePolicyStrictAllComponents, + ) + + // Succeed on the first Get (profile) and fail on the second (adherence). + // NOTE: this assumes controller-runtime-common's FetchAPIServerTLSProfile and + // FetchAPIServerTLSAdherencePolicy each issue exactly one Get, in that order. That holds for the + // pinned version; if the dependency changes its internal call count/order, revisit this counter. + var calls int + cli := fake.NewClientBuilder(). + WithScheme(tlsTestScheme(t)). + WithObjects(apiServer). + WithInterceptorFuncs(interceptor.Funcs{ + Get: func(ctx context.Context, c client.WithWatch, key client.ObjectKey, obj client.Object, opts ...client.GetOption) error { + calls++ + if calls >= 2 { + return errors.New("connection refused") + } + return c.Get(ctx, key, obj, opts...) + }, + }). + Build() + + profile, adherence, err := resolveClusterTLSProfile( + context.Background(), cli, true, false, logr.Discard()) + + g.Expect(err).ToNot(gomega.HaveOccurred()) + g.Expect(profile.MinTLSVersion).To(gomega.Equal(modern.MinTLSVersion)) + g.Expect(adherence).To(gomega.Equal(configv1.TLSAdherencePolicyNoOpinion)) +} + +// Guard: the NotFound classification the resolver relies on must hold for the fake client so the +// fallback path stays correct if dependencies change. +func TestResolveClusterTLSProfile_NotFoundClassification(t *testing.T) { + t.Parallel() + g := gomega.NewWithT(t) + + cli := fake.NewClientBuilder().WithScheme(tlsTestScheme(t)).Build() + err := cli.Get(context.Background(), client.ObjectKey{Name: "cluster"}, &configv1.APIServer{}) + + g.Expect(apierrors.IsNotFound(err)).To(gomega.BeTrue()) +} diff --git a/config/rbac/role.yaml b/config/rbac/role.yaml index afb620a21..83f6b6d00 100644 --- a/config/rbac/role.yaml +++ b/config/rbac/role.yaml @@ -116,6 +116,7 @@ rules: resourceNames: - cluster resources: + - apiservers - ingresses verbs: - get diff --git a/go.mod b/go.mod index 5d030f668..54bcdc8a3 100644 --- a/go.mod +++ b/go.mod @@ -15,6 +15,7 @@ require ( github.com/onsi/ginkgo/v2 v2.32.0 github.com/onsi/gomega v1.42.1 github.com/openshift/api v0.0.0-20260528061300-9f553042f9ae + github.com/openshift/controller-runtime-common v0.0.0-20260428152732-64ee174f5e2e github.com/operator-framework/api v0.44.0 github.com/operator-framework/operator-lib v0.19.0 github.com/robfig/cron/v3 v3.0.1 @@ -40,6 +41,11 @@ require ( github.com/cenkalti/backoff/v5 v5.0.3 // indirect github.com/cespare/xxhash/v2 v2.3.0 // indirect github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect + // Pinned to v3.1.1 (enforced via the replace directive at the bottom of this file): the + // version selected transitively via library-go (v3.0.0) is vulnerable, so we force the + // patched release. + github.com/distribution/distribution/v3 v3.1.1 // indirect + github.com/distribution/reference v0.6.0 // indirect github.com/docker/cli v29.6.2+incompatible // indirect github.com/docker/docker-credential-helpers v0.9.8 // indirect github.com/emicklei/go-restful/v3 v3.13.0 // indirect @@ -77,6 +83,10 @@ require ( github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect github.com/opencontainers/go-digest v1.0.0 // indirect github.com/opencontainers/image-spec v1.1.1 // indirect + // Snyk flags CVE-2026-32952 (go-ntlmssp) reached transitively through library-go's Azure + // authentication path. The package is not reachable from our binary and has no upstream fix, + // so it is handled via a Snyk ignore rather than a version bump. + github.com/openshift/library-go v0.0.0-20260213153706-03f1709971c5 // indirect github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect github.com/prometheus/client_golang v1.23.2 // indirect github.com/prometheus/client_model v0.6.2 // indirect @@ -122,3 +132,10 @@ require ( sigs.k8s.io/json v0.0.0-20250730193827-2d320260d730 // indirect sigs.k8s.io/structured-merge-diff/v6 v6.4.2 // indirect ) + +// Why we pinned to v3.1.1: library-go still requires the vulnerable distribution v3.0.0. A replace +// directive is used instead of a plain require bump because `go mod tidy` recomputes indirect +// requires via MVS (which would downgrade back to v3.0.0) but does not touch replace directives. +// Remove this once library-go is upgraded to a version requiring distribution >= v3.1.1. +replace github.com/distribution/distribution/v3 => github.com/distribution/distribution/v3 v3.1.1 + diff --git a/go.sum b/go.sum index 2693cb08c..6717b2bc8 100644 --- a/go.sum +++ b/go.sum @@ -21,6 +21,14 @@ github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSs 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= github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/distribution/distribution/v3 v3.1.0 h1:u1v788HreKTLGdNY6s7px8Exgrs9mZ9UrCDjSrpCM8g= +github.com/distribution/distribution/v3 v3.1.0/go.mod h1:73BuF5/ziMHNVt7nnL1roYpH4Eg/FgUlKZm3WryIx/o= +github.com/distribution/distribution/v3 v3.1.1 h1:KUbk7C8CfaLXy8kbf/hGq9cad/wCoLB6dbWH6DMbmX0= +github.com/distribution/distribution/v3 v3.1.1/go.mod h1:d7lXwZpph0bVcOj4Aqn0nMrWHIwRQGdiV5TLeI+/w6Y= +github.com/distribution/reference v0.6.0 h1:0IXCQ5g4/QMHHkarYzh5l+u8T3t73zM5QvfrDyIgxBk= +github.com/distribution/reference v0.6.0/go.mod h1:BbU0aIcezP1/5jX/8MP0YiH4SdvB5Y4f/wlDRiLyi3E= +github.com/docker/cli v29.6.1+incompatible h1:oO7F4nn3Ovr/5TlfTUWFbMwBSS/B7Xs6Epv26gBrUP8= +github.com/docker/cli v29.6.1+incompatible/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8= github.com/docker/cli v29.6.2+incompatible h1:/bjePvcbbFTnRrMfWJBY7AjfICdsiLVgHn6LwTVOcqw= github.com/docker/cli v29.6.2+incompatible/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8= github.com/docker/docker-credential-helpers v0.9.8 h1:bIREROb7So6PRlq6KTtdS9MPEjC29OQRkFNlvK2OX8Q= @@ -153,6 +161,10 @@ 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/openshift/api v0.0.0-20260528061300-9f553042f9ae h1:qTKrQWkXujGSQy+seJkUEOLfBEiw0xy+yJG/YViBABU= github.com/openshift/api v0.0.0-20260528061300-9f553042f9ae/go.mod h1:pyVjK0nZ4sRs4fuQVQ4rubsJdahI1PB94LnQ8sGdvxo= +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-20260213153706-03f1709971c5 h1:9Pe6iVOMjt9CdA/vaKBNUSoEIjIe1po5Ha3ABRYXLJI= +github.com/openshift/library-go v0.0.0-20260213153706-03f1709971c5/go.mod h1:K3FoNLgNBFYbFuG+Kr8usAnQxj1w84XogyUp2M8rK8k= github.com/operator-framework/api v0.44.0 h1:UPPNVVI2HJyfH17cnL/8PADV4DCaNLqfL08e+AyYrO8= github.com/operator-framework/api v0.44.0/go.mod h1:H46wpymo4j3kJZraarbuBUPLF5OzTCw4u0n2xb9sMNQ= github.com/operator-framework/operator-lib v0.19.0 h1:az6ogYj21rtU0SF9uYctRLyKp2dtlqTsmpfehFy6Ce8= diff --git a/internal/config/config.go b/internal/config/config.go index 8f2374e55..55033812c 100644 --- a/internal/config/config.go +++ b/internal/config/config.go @@ -3,9 +3,10 @@ package config import "time" var ( - CreateTreeDeadline int64 = 1200 - Openshift bool - OpenshiftAPIServerName string - APIServerTimeout time.Duration - IngressHostTemplate = "%[1]s.local" + CreateTreeDeadline int64 = 1200 + Openshift bool + OpenshiftAPIServerName string + APIServerTimeout time.Duration + IngressHostTemplate = "%[1]s.local" + DisableClusterTLSProfile bool ) diff --git a/internal/controller/types.go b/internal/controller/types.go index 7d31795ba..ce76f0775 100644 --- a/internal/controller/types.go +++ b/internal/controller/types.go @@ -31,6 +31,7 @@ import ( //+kubebuilder:rbac:groups=rbac.authorization.k8s.io,resources=roles,verbs=get;list;watch;create;update;patch;delete;deletecollection //+kubebuilder:rbac:groups=rbac.authorization.k8s.io,resources=rolebindings,verbs=get;list;watch;create;update;patch;delete;deletecollection +//+kubebuilder:rbac:groups="config.openshift.io",resources=apiservers,resourceNames=cluster,verbs=get;list;watch //+kubebuilder:rbac:groups="config.openshift.io",resources=ingresses,resourceNames=cluster,verbs=get;list;watch //+kubebuilder:rbac:groups=events.k8s.io,resources=events,verbs=create;get;list;watch;update;patch