diff --git a/assets/components/openshift-router/deployment.yaml b/assets/components/openshift-router/deployment.yaml index af1f48f67f..cb2c7b5f31 100644 --- a/assets/components/openshift-router/deployment.yaml +++ b/assets/components/openshift-router/deployment.yaml @@ -58,6 +58,8 @@ spec: value: '{{ .ThreadCount }}' - name: SSL_MIN_VERSION value: '{{ .RouterSSLMinVersion }}' + - name: ROUTER_CURVES + value: '{{ .RouterTLSCurves }}' - name: ROUTER_USE_PROXY_PROTOCOL value: "false" - name: GRACEFUL_SHUTDOWN_DELAY diff --git a/pkg/components/controllers.go b/pkg/components/controllers.go index e9bdf7af50..290b7a16b2 100644 --- a/pkg/components/controllers.go +++ b/pkg/components/controllers.go @@ -27,6 +27,9 @@ const ( haproxyMaxTimeoutMilliseconds = 2147483647 * time.Millisecond ) +// isFIPSEnabled reports whether the cluster has FIPS enabled. +var isFIPSEnabled = detectFIPS() + var ( tlsVersion13Ciphers = sets.NewString( "TLS_AES_128_GCM_SHA256", @@ -35,8 +38,41 @@ var ( "TLS_AES_128_CCM_SHA256", "TLS_AES_128_CCM_8_SHA256", ) + + fipsApprovedTLS13Ciphers = sets.NewString( + "TLS_AES_128_GCM_SHA256", + "TLS_AES_256_GCM_SHA384", + ) ) +// detectFIPS reports whether the cluster is operating in FIPS +// mode by checking the FIPS_ENABLED environment variable if set or +// the /proc/sys/crypto/fips_enabled file otherwise. +func detectFIPS() bool { + if v, ok := os.LookupEnv("FIPS_ENABLED"); ok { + if result, err := strconv.ParseBool(v); err != nil { + klog.Warningf("Failed to parse FIPS_ENABLED environment variable: %v; falling back to procfs", err) + } else { + klog.Infof("Found FIPS_ENABLED environment variable: value=%s, result=%v", v, result) + return result + } + } + + result := false + data, err := os.ReadFile("/proc/sys/crypto/fips_enabled") + if err != nil { + klog.Warningf("Failed to read /proc/sys/crypto/fips_enabled: %v; assuming FIPS is not enabled", err) + return result + } + if len(data) == 0 { + klog.Warningf("Got empty /proc/sys/crypto/fips_enabled; assuming FIPS is not enabled") + return result + } + result = data[0] == '1' + klog.Infof("Read /proc/sys/crypto/fips_enabled: data=%s, result=%v", string(data), result) + return result +} + func startServiceCAController(ctx context.Context, cfg *config.Config, kubeconfigPath string) error { var ( //TODO: fix the rolebinding and sa @@ -472,12 +508,34 @@ func generateIngressParams(cfg *config.Config) (assets.RenderParams, error) { } } + // On FIPS-enabled clusters, remove non-FIPS-compliant TLS 1.3 cipher + // suites (e.g. TLS_CHACHA20_POLY1305_SHA256). HAProxy would fail TLS + // handshakes when a client offers a non-FIPS cipher first if that cipher + // is listed in ssl-default-bind-ciphersuites but excluded by the OS FIPS policy. + if isFIPSEnabled { + fipsCiphers := tls13Ciphers[:0] + for _, c := range tls13Ciphers { + if fipsApprovedTLS13Ciphers.Has(c) { + fipsCiphers = append(fipsCiphers, c) + } + } + tls13Ciphers = fipsCiphers + } + RouterCiphers := strings.Join(otherCiphers, ":") RouterCiphersSuites := "" if len(tls13Ciphers) != 0 { RouterCiphersSuites = strings.Join(tls13Ciphers, ":") } + // Default TLS supportedGroups (curves) include X25519MLKEM768 for + // post-quantum readiness. In FIPS mode, ML-KEM and X25519 are not + // supported by OpenSSL FIPS 140-3. + tlsCurves := "X25519MLKEM768:X25519:P-256:P-384:P-521" + if isFIPSEnabled { + tlsCurves = "P-256:P-384:P-521" + } + var RouterSSLMinVersion string switch tlsProfileSpec.MinTLSVersion { // TLS 1.0 is not supported, convert to TLS 1.1. @@ -569,6 +627,7 @@ func generateIngressParams(cfg *config.Config) (assets.RenderParams, error) { "RouterCiphers": RouterCiphers, "RouterCiphersSuites": RouterCiphersSuites, "RouterSSLMinVersion": RouterSSLMinVersion, + "RouterTLSCurves": tlsCurves, "RouterAllowWildcardRoutes": RouterAllowWildcardRoutes, "ClientCAMapName": clientCAMapName, "ClientAuthPolicy": clientAuthPolicy,