diff --git a/ci-operator/config/openshift/release/openshift-release-main__nightly-4.22.yaml b/ci-operator/config/openshift/release/openshift-release-main__nightly-4.22.yaml index f4ebd3499f0f2..2fb153f5d04ba 100644 --- a/ci-operator/config/openshift/release/openshift-release-main__nightly-4.22.yaml +++ b/ci-operator/config/openshift/release/openshift-release-main__nightly-4.22.yaml @@ -87,6 +87,10 @@ base_images: name: tests-private namespace: ci tag: "4.22" + tls-scanner-tool: + name: tls-scanner + namespace: tls-scanner + tag: tls-scanner-tool upi-installer: name: "4.22" namespace: ocp diff --git a/ci-operator/step-registry/fips-check/node-scan/fips-check-node-scan-commands.sh b/ci-operator/step-registry/fips-check/node-scan/fips-check-node-scan-commands.sh index b1fb84f60a872..43050d3cfff6b 100755 --- a/ci-operator/step-registry/fips-check/node-scan/fips-check-node-scan-commands.sh +++ b/ci-operator/step-registry/fips-check/node-scan/fips-check-node-scan-commands.sh @@ -19,9 +19,172 @@ function run_command() { eval "${CMD}" } +# --- TLS Scanner (parallel) --------------------------------------------------- +# Launch the TLS scanner early so it runs in parallel with the FIPS node scan. +# The scanner image is provided by the PULL_SPEC_TLS_SCANNER_TOOL dependency. +# Its exit code is intentionally ignored — it produces informational artifacts only. + +TLS_SCANNER_NS="tls-scanner" +TLS_SCANNER_IMAGE="${PULL_SPEC_TLS_SCANNER_TOOL:-}" +TLS_SCANNER_ARTIFACT_DIR="${ARTIFACT_DIR}/tls-scanner" +TLS_SCANNER_NS_CREATED=false +TLS_SCANNER_STARTED=false + +# Always clean up the TLS scanner namespace on exit, regardless of whether the +# scanner pod became Ready or artifacts were collected. +function cleanup_tls_scanner() { + if [[ "${TLS_SCANNER_NS_CREATED}" == "true" ]]; then + echo "[tls-scanner] Cleaning up namespace ${TLS_SCANNER_NS}..." + oc delete namespace "${TLS_SCANNER_NS}" --ignore-not-found --wait=false || true + fi +} +trap cleanup_tls_scanner EXIT + +function start_tls_scanner() { + if [[ -z "${TLS_SCANNER_IMAGE}" ]]; then + echo "[tls-scanner] PULL_SPEC_TLS_SCANNER_TOOL not set — skipping TLS scan." + return + fi + + echo "=== Starting TLS Scanner (parallel) ===" + echo "[tls-scanner] Image: ${TLS_SCANNER_IMAGE}" + mkdir -p "${TLS_SCANNER_ARTIFACT_DIR}" + + # Create namespace (best-effort — failures here must not abort the step) + if oc create namespace "${TLS_SCANNER_NS}" --dry-run=client -o yaml | oc apply -f -; then + TLS_SCANNER_NS_CREATED=true + else + echo "[tls-scanner] WARNING: Failed to create namespace — skipping TLS scan." + return + fi + + # Grant cluster-admin and privileged SCC (best-effort) + if ! oc adm policy add-cluster-role-to-user cluster-admin -z default -n "${TLS_SCANNER_NS}"; then + echo "[tls-scanner] WARNING: Failed to grant cluster-admin — skipping TLS scan." + return + fi + if ! oc adm policy add-scc-to-user privileged -z default -n "${TLS_SCANNER_NS}"; then + echo "[tls-scanner] WARNING: Failed to grant privileged SCC — skipping TLS scan." + return + fi + + # Wait for RBAC/SCC changes to propagate + sleep 10 + + # Deploy the scanner pod. + # The pod keeps running indefinitely (tail -f /dev/null) after the scan + # finishes so that oc cp can always exec into it to collect artifacts. + # The collector signals completion by writing /results/collect.done, which + # terminates the wait loop and lets the container exit cleanly. + cat <&1 | tee /results/output.log + SCAN_EXIT_CODE=\${PIPESTATUS[0]} + echo "Scan complete. Exit code: \${SCAN_EXIT_CODE}" | tee -a /results/output.log + touch /results/scan.done + # Keep pod alive until the collector copies artifacts and signals completion. + while [ ! -f /results/collect.done ]; do sleep 5; done + resources: + requests: + cpu: "4" + memory: 4Gi + limits: + cpu: "4" + memory: 4Gi + securityContext: + privileged: true + runAsUser: 0 + volumeMounts: + - name: results + mountPath: /results + volumes: + - name: results + emptyDir: {} +EOF + + echo "[tls-scanner] Waiting for scanner pod to start..." + if oc wait --for=condition=Ready pod/tls-scanner -n "${TLS_SCANNER_NS}" --timeout=5m; then + TLS_SCANNER_STARTED=true + echo "[tls-scanner] Pod is running — scan will proceed in parallel." + else + echo "[tls-scanner] WARNING: Pod failed to start. Continuing without TLS scan." + oc describe pod/tls-scanner -n "${TLS_SCANNER_NS}" || true + fi +} + +function collect_tls_scanner_results() { + if [[ "${TLS_SCANNER_STARTED}" != "true" ]]; then + return + fi + + echo "=== Collecting TLS Scanner Results ===" + + # Wait for scan.done marker or pod exit (up to 4 hours) + local max_wait=14400 + local elapsed=0 + while (( elapsed < max_wait )); do + if oc exec pod/tls-scanner -n "${TLS_SCANNER_NS}" -- test -f /results/scan.done 2>/dev/null; then + echo "[tls-scanner] scan.done found — collecting artifacts" + break + fi + local phase + phase=$(oc get pod/tls-scanner -n "${TLS_SCANNER_NS}" -o jsonpath='{.status.phase}' 2>/dev/null || echo "Unknown") + if [[ "$phase" == "Succeeded" || "$phase" == "Failed" ]]; then + echo "[tls-scanner] Pod ${phase} — attempting artifact collection" + break + fi + sleep 15 + elapsed=$((elapsed + 15)) + done + + # Copy artifacts (pod is still running, waiting for collect.done signal) + oc cp "${TLS_SCANNER_NS}/tls-scanner:/results/." "${TLS_SCANNER_ARTIFACT_DIR}/" || echo "[tls-scanner] WARNING: Failed to copy some artifacts" + + if [[ -f "${TLS_SCANNER_ARTIFACT_DIR}/junit_tls_scan.xml" ]]; then + cp "${TLS_SCANNER_ARTIFACT_DIR}/junit_tls_scan.xml" "${ARTIFACT_DIR}/junit_tls_scan.xml" + echo "[tls-scanner] JUnit results copied to ${ARTIFACT_DIR}/junit_tls_scan.xml" + fi + + # Signal the scanner pod that collection is complete so it can exit + oc exec pod/tls-scanner -n "${TLS_SCANNER_NS}" -- touch /results/collect.done 2>/dev/null || true + + echo "[tls-scanner] Artifacts saved to: ${TLS_SCANNER_ARTIFACT_DIR}" + ls -la "${TLS_SCANNER_ARTIFACT_DIR}" || true + + # Namespace cleanup is handled by the EXIT trap (cleanup_tls_scanner) + echo "=== TLS Scanner Complete ===" +} + +# --- Main: start TLS scanner, then run FIPS node scan ------------------------- + set_proxy run_command "oc whoami" run_command "oc version -o yaml" + +# Launch TLS scanner in the background (non-blocking) +start_tls_scanner + pass=true # skip for ARM64 @@ -31,6 +194,7 @@ NON_SUPPORTED_ARCHES=(arm64) for arch in "${node_archs[@]}"; do if [[ "${NON_SUPPORTED_ARCHES[*]}" =~ $arch ]]; then echo "Skip this test since it doesn't support $arch." + collect_tls_scanner_results exit 0 fi done @@ -56,6 +220,7 @@ if [[ $ret -eq 0 ]]; then auths=`cat /tmp/.dockerconfigjson` if [[ $auths =~ "5000" ]]; then echo "This is a disconnected env, skip it." + collect_tls_scanner_results exit 0 fi fi @@ -75,6 +240,9 @@ if [[ -n $res ]];then pass=false fi +# --- Collect TLS scanner results (waits for completion) ----------------------- +collect_tls_scanner_results + # generate report echo "Generating the Junit for fips check node scan" filename="junit_fips-check-node-scan" diff --git a/ci-operator/step-registry/fips-check/node-scan/fips-check-node-scan-ref.yaml b/ci-operator/step-registry/fips-check/node-scan/fips-check-node-scan-ref.yaml index 11577d7a90056..cfe5556de85ea 100644 --- a/ci-operator/step-registry/fips-check/node-scan/fips-check-node-scan-ref.yaml +++ b/ci-operator/step-registry/fips-check/node-scan/fips-check-node-scan-ref.yaml @@ -2,10 +2,17 @@ ref: as: fips-check-node-scan from: cli commands: fips-check-node-scan-commands.sh + dependencies: + - env: PULL_SPEC_TLS_SCANNER_TOOL + name: tls-scanner-tool resources: requests: cpu: 10m memory: 100Mi grace_period: 180s + timeout: 4h30m0s documentation: >- This step checks if the rpms on nodes are built correctly. + It also launches the TLS scanner in parallel to scan all cluster + pod TLS ports for cipher suite and protocol version compliance. + The TLS scanner image is provided via the tls-scanner-tool dependency.