From f0eb32fe1985853035acb5ffed0d6368d6967d27 Mon Sep 17 00:00:00 2001 From: Cesar Wong Date: Wed, 29 Apr 2026 16:40:53 -0400 Subject: [PATCH 1/2] fix(ingress): set FIPS_ENABLED env var on ingress operator The ingress operator determines FIPS mode by reading /proc/sys/crypto/fips_enabled on the node where it runs. In hosted clusters the ingress operator runs on the management cluster, which may have a different FIPS state than the hosted cluster. This causes the operator to deploy routers with incorrect cipher configuration when the FIPS states differ. Set FIPS_ENABLED=true on the ingress operator container when the hosted cluster has FIPS enabled, so the operator uses the correct cipher suite regardless of the management cluster's FIPS state. Co-Authored-By: Claude Opus 4.6 --- .../v2/ingressoperator/deployment.go | 6 ++ .../v2/ingressoperator/deployment_test.go | 79 +++++++++++++++++++ 2 files changed, 85 insertions(+) create mode 100644 control-plane-operator/controllers/hostedcontrolplane/v2/ingressoperator/deployment_test.go diff --git a/control-plane-operator/controllers/hostedcontrolplane/v2/ingressoperator/deployment.go b/control-plane-operator/controllers/hostedcontrolplane/v2/ingressoperator/deployment.go index 6b38575d2b3c..55b869228b4b 100644 --- a/control-plane-operator/controllers/hostedcontrolplane/v2/ingressoperator/deployment.go +++ b/control-plane-operator/controllers/hostedcontrolplane/v2/ingressoperator/deployment.go @@ -22,6 +22,12 @@ func adaptDeployment(cpContext component.WorkloadContext, deployment *appsv1.Dep Name: "CANARY_IMAGE", Value: cpContext.UserReleaseImageProvider.GetImage("cluster-ingress-operator"), }) + if cpContext.HCP.Spec.FIPS { + podspec.UpsertEnvVar(c, corev1.EnvVar{ + Name: "FIPS_ENABLED", Value: "true", + }) + } + // For managed Azure deployments, we pass an environment variable, MANAGED_AZURE_HCP_CREDENTIALS_FILE_PATH, so // we authenticate with Azure API through UserAssignedCredential authentication. We also mount the // SecretProviderClass for the Secrets Store CSI driver to use; it will grab the JSON object stored in the diff --git a/control-plane-operator/controllers/hostedcontrolplane/v2/ingressoperator/deployment_test.go b/control-plane-operator/controllers/hostedcontrolplane/v2/ingressoperator/deployment_test.go new file mode 100644 index 000000000000..c5f206efc68c --- /dev/null +++ b/control-plane-operator/controllers/hostedcontrolplane/v2/ingressoperator/deployment_test.go @@ -0,0 +1,79 @@ +package ingressoperator + +import ( + "testing" + + . "github.com/onsi/gomega" + + hyperv1 "github.com/openshift/hypershift/api/hypershift/v1beta1" + assets "github.com/openshift/hypershift/control-plane-operator/controllers/hostedcontrolplane/v2/assets" + component "github.com/openshift/hypershift/support/controlplane-component" + "github.com/openshift/hypershift/support/podspec" + "github.com/openshift/hypershift/support/testutil" + + corev1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" +) + +func TestAdaptDeployment(t *testing.T) { + t.Parallel() + + testCases := []struct { + name string + fips bool + validate func(*WithT, *corev1.Container) + }{ + { + name: "When FIPS is enabled, it should set FIPS_ENABLED env var to true", + fips: true, + validate: func(g *WithT, container *corev1.Container) { + g.Expect(container.Env).To(ContainElement(corev1.EnvVar{ + Name: "FIPS_ENABLED", + Value: "true", + })) + }, + }, + { + name: "When FIPS is not enabled, it should not set FIPS_ENABLED env var", + fips: false, + validate: func(g *WithT, container *corev1.Container) { + for _, env := range container.Env { + g.Expect(env.Name).ToNot(Equal("FIPS_ENABLED")) + } + }, + }, + } + + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + t.Parallel() + g := NewWithT(t) + + hcp := &hyperv1.HostedControlPlane{ + ObjectMeta: metav1.ObjectMeta{ + Name: "test-hcp", + Namespace: "test-namespace", + }, + Spec: hyperv1.HostedControlPlaneSpec{ + FIPS: tc.fips, + }, + } + + cpContext := component.WorkloadContext{ + HCP: hcp, + UserReleaseImageProvider: testutil.FakeImageProvider(), + } + + deployment, err := assets.LoadDeploymentManifest(ComponentName) + g.Expect(err).ToNot(HaveOccurred()) + + err = adaptDeployment(cpContext, deployment) + g.Expect(err).ToNot(HaveOccurred()) + + container := podspec.FindContainer(ComponentName, deployment.Spec.Template.Spec.Containers) + g.Expect(container).ToNot(BeNil(), "ingress-operator container should exist") + + tc.validate(g, container) + }) + } +} From a59e691c1984eaaea4050ace45be445e9ae30dae Mon Sep 17 00:00:00 2001 From: Cesar Wong Date: Tue, 5 May 2026 14:12:03 -0400 Subject: [PATCH 2/2] fix(ingress): adjust cherry-pick for release-4.22 branch Use util.UpsertEnvVar and util.FindContainer instead of podspec.UpsertEnvVar and podspec.FindContainer, since the support/podspec package does not exist in the release-4.22 branch. Co-Authored-By: Claude Opus 4.6 --- .../hostedcontrolplane/v2/ingressoperator/deployment.go | 2 +- .../hostedcontrolplane/v2/ingressoperator/deployment_test.go | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/control-plane-operator/controllers/hostedcontrolplane/v2/ingressoperator/deployment.go b/control-plane-operator/controllers/hostedcontrolplane/v2/ingressoperator/deployment.go index 55b869228b4b..22a47e4fc74f 100644 --- a/control-plane-operator/controllers/hostedcontrolplane/v2/ingressoperator/deployment.go +++ b/control-plane-operator/controllers/hostedcontrolplane/v2/ingressoperator/deployment.go @@ -23,7 +23,7 @@ func adaptDeployment(cpContext component.WorkloadContext, deployment *appsv1.Dep }) if cpContext.HCP.Spec.FIPS { - podspec.UpsertEnvVar(c, corev1.EnvVar{ + util.UpsertEnvVar(c, corev1.EnvVar{ Name: "FIPS_ENABLED", Value: "true", }) } diff --git a/control-plane-operator/controllers/hostedcontrolplane/v2/ingressoperator/deployment_test.go b/control-plane-operator/controllers/hostedcontrolplane/v2/ingressoperator/deployment_test.go index c5f206efc68c..1e2e56c02288 100644 --- a/control-plane-operator/controllers/hostedcontrolplane/v2/ingressoperator/deployment_test.go +++ b/control-plane-operator/controllers/hostedcontrolplane/v2/ingressoperator/deployment_test.go @@ -8,8 +8,8 @@ import ( hyperv1 "github.com/openshift/hypershift/api/hypershift/v1beta1" assets "github.com/openshift/hypershift/control-plane-operator/controllers/hostedcontrolplane/v2/assets" component "github.com/openshift/hypershift/support/controlplane-component" - "github.com/openshift/hypershift/support/podspec" "github.com/openshift/hypershift/support/testutil" + "github.com/openshift/hypershift/support/util" corev1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" @@ -70,7 +70,7 @@ func TestAdaptDeployment(t *testing.T) { err = adaptDeployment(cpContext, deployment) g.Expect(err).ToNot(HaveOccurred()) - container := podspec.FindContainer(ComponentName, deployment.Spec.Template.Spec.Containers) + container := util.FindContainer(ComponentName, deployment.Spec.Template.Spec.Containers) g.Expect(container).ToNot(BeNil(), "ingress-operator container should exist") tc.validate(g, container)