From 905c035f4522a9f35625cdb50a9898c6217ac5aa Mon Sep 17 00:00:00 2001 From: Martin Gencur Date: Thu, 11 Jun 2026 14:51:31 +0200 Subject: [PATCH] fix(security): read FIPS state from HostedCluster on HyperShift On HyperShift hosted clusters, the install-config ConfigMap in kube-system does not reflect the actual FIPS configuration. Instead, FIPS is set via .spec.fips on the HostedCluster resource in the management cluster. Add helpers to discover the HostedCluster and read its FIPS field via the management cluster API. When the management cluster env vars are not set, the test is skipped. Remove unused installConfigName const. Co-Authored-By: Claude Opus 4.6 --- test/extended/security/fips.go | 73 +++++++++++++++++++++++++++++----- 1 file changed, 62 insertions(+), 11 deletions(-) diff --git a/test/extended/security/fips.go b/test/extended/security/fips.go index 973354101097..e52f048962e2 100644 --- a/test/extended/security/fips.go +++ b/test/extended/security/fips.go @@ -3,6 +3,7 @@ package security import ( "context" "fmt" + "os" "strconv" "strings" @@ -18,10 +19,7 @@ import ( exutil "github.com/openshift/origin/test/extended/util" ) -const ( - installConfigName = "cluster-config-v1" - fipsFile = "/proc/sys/crypto/fips_enabled" -) +const fipsFile = "/proc/sys/crypto/fips_enabled" func validateFIPSOnNode(oc *exutil.CLI, fipsExpected bool, node *corev1.Node) error { // The oc debug output prints a bunch of info messages and possible warnings (the latter can not be disabled). @@ -48,6 +46,53 @@ func validateFIPSOnNode(oc *exutil.CLI, fipsExpected bool, node *corev1.Node) er return nil } +// discoverHostedCluster finds the HostedCluster name and namespace on the +// management cluster that corresponds to the given hosted control plane namespace. +// The HCP namespace follows the convention {hcNS}-{hcName}. +func discoverHostedCluster(mgmtCLI *exutil.CLI, hcpNS string) (string, string, error) { + output, err := mgmtCLI.AsAdmin().WithoutNamespace().Run("get").Args( + "hostedclusters", "-A", + "-o", `jsonpath={range .items[*]}{.metadata.namespace},{.metadata.name}{"\n"}{end}`, + ).Output() + if err != nil { + return "", "", fmt.Errorf("failed to list HostedClusters: %v", err) + } + + for _, line := range strings.Split(strings.TrimSpace(output), "\n") { + parts := strings.SplitN(line, ",", 2) + if len(parts) == 2 { + ns, name := parts[0], parts[1] + if ns+"-"+name == hcpNS { + return name, ns, nil + } + } + } + return "", "", fmt.Errorf("could not find HostedCluster matching HCP namespace %s", hcpNS) +} + +func isHostedClusterFIPS() (bool, error) { + mgmtCLI := exutil.NewHypershiftManagementCLI("fips-mgmt") + _, hcpNamespace, err := exutil.GetHypershiftManagementClusterConfigAndNamespace() + if err != nil { + return false, err + } + + hcName, hcNS, err := discoverHostedCluster(mgmtCLI, hcpNamespace) + if err != nil { + return false, err + } + + fipsValue, err := mgmtCLI.AsAdmin().WithoutNamespace().Run("get").Args( + "hostedcluster", hcName, "-n", hcNS, + "-ojsonpath={.spec.fips}", + ).Output() + if err != nil { + return false, fmt.Errorf("failed to get .spec.fips from HostedCluster %s/%s: %v", hcNS, hcName, err) + } + + return strconv.ParseBool(fipsValue) +} + var _ = g.Describe("[sig-arch] [Conformance] FIPS", func() { defer g.GinkgoRecover() oc := exutil.NewCLIWithPodSecurityLevel("fips", admissionapi.LevelPrivileged) @@ -56,21 +101,27 @@ var _ = g.Describe("[sig-arch] [Conformance] FIPS", func() { controlPlaneTopology, err := exutil.GetControlPlaneTopology(oc) o.Expect(err).NotTo(o.HaveOccurred()) clusterAdminKubeClientset := oc.AdminKubeClient() - isFIPS, err := exutil.IsFIPS(clusterAdminKubeClientset.CoreV1()) - o.Expect(err).NotTo(o.HaveOccurred()) - // fetch one control plane and one worker, and validate FIPS state on it. - // skip the controlplane node verification when external controlPlaneTopology as - // there are no controlplane nodes. - if *controlPlaneTopology != configv1.ExternalTopologyMode { + var isFIPS bool + if *controlPlaneTopology == configv1.ExternalTopologyMode { + if os.Getenv("HYPERSHIFT_MANAGEMENT_CLUSTER_KUBECONFIG") == "" || os.Getenv("HYPERSHIFT_MANAGEMENT_CLUSTER_NAMESPACE") == "" { + g.Skip("HYPERSHIFT_MANAGEMENT_CLUSTER_KUBECONFIG and HYPERSHIFT_MANAGEMENT_CLUSTER_NAMESPACE must be set for FIPS test on HyperShift") + } + isFIPS, err = isHostedClusterFIPS() + o.Expect(err).NotTo(o.HaveOccurred()) + } else { + isFIPS, err = exutil.IsFIPS(clusterAdminKubeClientset.CoreV1()) + o.Expect(err).NotTo(o.HaveOccurred()) + masterNodes, err := clusterAdminKubeClientset.CoreV1().Nodes().List(context.Background(), metav1.ListOptions{ LabelSelector: "node-role.kubernetes.io/master", }) o.Expect(err).NotTo(o.HaveOccurred()) masterNode := &masterNodes.Items[0] err = validateFIPSOnNode(oc, isFIPS, masterNode) + o.Expect(err).NotTo(o.HaveOccurred()) } - o.Expect(err).NotTo(o.HaveOccurred()) + workerNodes, err := clusterAdminKubeClientset.CoreV1().Nodes().List(context.Background(), metav1.ListOptions{ LabelSelector: "node-role.kubernetes.io/worker", })