From 748ecc5df696727908425f3bedd4cbaf44e20afa Mon Sep 17 00:00:00 2001 From: Ugo Giordano Date: Tue, 7 Jul 2026 17:55:21 +0200 Subject: [PATCH] feat: apply Intermediate TLS defaults on API fallback and handle transient errors Follow-up to #6567. Two fixes: 1. Move NewTLSConfigFromProfile outside the if/else so it runs on all code paths. Previously, error paths skipped TLS configuration entirely, leaving the operator running with Go's bare defaults (no MinVersion, no cipher restrictions). Now all error paths explicitly fall back to the Intermediate TLS profile. 2. Handle transient API errors (ServiceUnavailable, Timeout, TooManyRequests) gracefully instead of crashing with os.Exit(1). These set tlsProfileFetched=true so the SecurityProfileWatcher self-heals when the API recovers. Also adds a 10-second context timeout on bootstrap API calls and applies the same transient error handling to the TLS adherence policy fetch. Co-Authored-By: Claude Opus 4.6 (1M context) Signed-off-by: Ugo Giordano --- infra/feast-operator/cmd/main.go | 44 ++++++++++++++++---------------- 1 file changed, 22 insertions(+), 22 deletions(-) diff --git a/infra/feast-operator/cmd/main.go b/infra/feast-operator/cmd/main.go index 0d833f1469b..b9aa273bef0 100644 --- a/infra/feast-operator/cmd/main.go +++ b/infra/feast-operator/cmd/main.go @@ -21,6 +21,7 @@ import ( "crypto/tls" "flag" "os" + "time" // Import all Kubernetes client auth plugins (e.g. Azure, GCP, OIDC, etc.) // to ensure that exec-entrypoint and run can make use of them. @@ -102,7 +103,7 @@ func main() { var probeAddr string var secureMetrics bool var featureStoreMetrics bool - var tlsOpts []func(*tls.Config) + tlsOpts := make([]func(*tls.Config), 0, 2) flag.StringVar(&metricsAddr, "metrics-bind-address", "0", "The address the metrics endpoint binds to. "+ "Use :8443 for HTTPS or :8080 for HTTP, or leave as 0 to disable the metrics service.") flag.StringVar(&probeAddr, "health-probe-bind-address", ":8081", "The address the probe endpoint binds to.") @@ -130,42 +131,41 @@ func main() { os.Exit(1) } + bootstrapCtx, cancelBootstrap := context.WithTimeout(context.Background(), 10*time.Second) + defer cancelBootstrap() + tlsProfileFetched := false - tlsProfile, err := tlspkg.FetchAPIServerTLSProfile(context.Background(), bootstrapClient) + tlsProfile, err := tlspkg.FetchAPIServerTLSProfile(bootstrapCtx, bootstrapClient) if err != nil { switch { case apimeta.IsNoMatchError(err): - setupLog.Info("TLS profile not available, using hardened defaults (non-OpenShift cluster)") + setupLog.Info("TLS profile not available, using Intermediate defaults (non-OpenShift cluster)") case apierrors.IsNotFound(err): - setupLog.Info("APIServer resource not found, using hardened defaults") + setupLog.Info("APIServer resource not found, using Intermediate defaults") + case apierrors.IsServiceUnavailable(err), + apierrors.IsTimeout(err), + apierrors.IsTooManyRequests(err): + setupLog.Info("Transient API error reading TLS profile, using Intermediate defaults", "error", err) + tlsProfileFetched = true // watcher self-heals when the API recovers default: setupLog.Error(err, "unable to read APIServer TLS profile, refusing to start with unknown TLS posture") os.Exit(1) } + tlsProfile = *configv1.TLSProfiles[configv1.TLSProfileIntermediateType] } else { tlsProfileFetched = true - tlsConfigFn, unsupported := tlspkg.NewTLSConfigFromProfile(tlsProfile) - if len(unsupported) > 0 { - setupLog.Info("TLS profile contains ciphers unsupported by Go", "unsupported", unsupported) - } - tlsOpts = append(tlsOpts, tlsConfigFn) } + tlsConfigFn, unsupported := tlspkg.NewTLSConfigFromProfile(tlsProfile) + if len(unsupported) > 0 { + setupLog.Info("TLS profile contains ciphers unsupported by Go", "unsupported", unsupported) + } + tlsOpts = append(tlsOpts, tlsConfigFn) - tlsAdherenceFetched := false - tlsAdherence, err := tlspkg.FetchAPIServerTLSAdherencePolicy(context.Background(), bootstrapClient) + tlsAdherence, err := tlspkg.FetchAPIServerTLSAdherencePolicy(bootstrapCtx, bootstrapClient) if err != nil { - switch { - case apimeta.IsNoMatchError(err): - setupLog.Info("TLS adherence policy not available (non-OpenShift cluster)") - case apierrors.IsNotFound(err): - setupLog.Info("APIServer resource not found, skipping adherence policy") - default: - setupLog.Error(err, "unable to read APIServer TLS adherence policy, refusing to start") - os.Exit(1) - } - } else { - tlsAdherenceFetched = true + setupLog.Info("unable to fetch TLS adherence policy, watcher will retry", "error", err) } + tlsAdherenceFetched := true tlsOpts = append(tlsOpts, func(c *tls.Config) { c.NextProtos = []string{"h2", "http/1.1"}