diff --git a/packages/os/os.spec b/packages/os/os.spec index e30f5b1b4..e274632e1 100644 --- a/packages/os/os.spec +++ b/packages/os/os.spec @@ -399,7 +399,6 @@ Conflicts: %{_cross_os}image-feature(no-host-containers) Summary: Compliance check framework Requires: (%{_cross_os}bloodhound-k8s if %{_cross_os}variant-runtime(k8s)) Requires: (%{_cross_os}bloodhound-k8s-overrides if %{_cross_os}variant-runtime(k8s)) -Requires: (%{_cross_os}bloodhound-fips if %{_cross_os}image-feature(fips)) %description -n %{_cross_os}bloodhound %{summary}. @@ -415,12 +414,6 @@ Requires: (%{_cross_os}bloodhound and %{_cross_os}variant-runtime(k8s)) %description -n %{_cross_os}bloodhound-k8s-overrides %{summary}. -%package -n %{_cross_os}bloodhound-fips -Summary: Compliance checks for FIPS -Requires: (%{_cross_os}bloodhound and %{_cross_os}image-feature(fips)) -%description -n %{_cross_os}bloodhound-fips -%{summary}. - %package -n %{_cross_os}xfscli Summary: XFS progs cli %description -n %{_cross_os}xfscli @@ -977,7 +970,9 @@ install -p -m 0644 %{S:400} %{S:401} %{S:402} %{buildroot}%{_cross_licensedir} %files -n %{_cross_os}bloodhound %{_cross_bindir}/bloodhound %{_cross_bindir}/bottlerocket-cis-checks +%{_cross_bindir}/bottlerocket-fips-checks %{_cross_libexecdir}/cis-checks/bottlerocket +%{_cross_libexecdir}/fips-checks/bottlerocket %exclude %{_cross_libexecdir}/cis-checks/bottlerocket/br03040101.json %files -n %{_cross_os}bloodhound-k8s @@ -988,10 +983,6 @@ install -p -m 0644 %{S:400} %{S:401} %{S:402} %{buildroot}%{_cross_licensedir} %{_cross_libexecdir}/cis-checks/bottlerocket/br03040101.json %{_cross_libexecdir}/cis-checks/kubernetes/k8s04021000.json -%files -n %{_cross_os}bloodhound-fips -%{_cross_bindir}/bottlerocket-fips-checks -%{_cross_libexecdir}/fips-checks/bottlerocket - %files -n %{_cross_os}xfscli %{_cross_sbindir}/xfs_admin %{_cross_sbindir}/xfs_info diff --git a/sources/bloodhound/src/bin/bottlerocket-fips-checks/checks.rs b/sources/bloodhound/src/bin/bottlerocket-fips-checks/checks.rs index 5d0fc809a..d62d2f271 100644 --- a/sources/bloodhound/src/bin/bottlerocket-fips-checks/checks.rs +++ b/sources/bloodhound/src/bin/bottlerocket-fips-checks/checks.rs @@ -11,19 +11,34 @@ const EXPECTED_FIPS_NAME: &str = "Amazon Linux 2023 Kernel Cryptographic API"; const FIPS_KERNEL_CHECK_MARKER: &str = "/etc/.fips-kernel-check-passed"; const FIPS_MODULE_CHECK_MARKER: &str = "/etc/.fips-module-check-passed"; +/// Checks whether kernel FIPS mode is active by reading /proc/sys/crypto/fips_enabled. +fn is_fips_enabled(sac: &dyn SystemAccess) -> bool { + look_for_strings_in_file(sac, CRYPTO_FIPS_ENABLED, &[EXPECTED_FIPS_ENABLED]).unwrap_or(false) +} + +/// Returns a SKIP result indicating FIPS is not enabled on this system. +fn skip_fips_not_enabled() -> CheckerResult { + CheckerResult { + status: CheckStatus::SKIP, + error: "FIPS mode is not enabled on this system".to_string(), + ..Default::default() + } +} + // =>o.o<= =>o.o<= =>o.o<= =>o.o<= =>o.o<= =>o.o<= =>o.o<= =>o.o<= =>o.o<= =>o.o<= pub struct FIPS01000000Checker {} impl Checker for FIPS01000000Checker { fn execute(&self, sac: &dyn SystemAccess) -> CheckerResult { - check_file_contains!( - sac, - CRYPTO_FIPS_ENABLED, - &[EXPECTED_FIPS_ENABLED], - format!("{CRYPTO_FIPS_ENABLED} != {EXPECTED_FIPS_ENABLED}"), - format!("{CRYPTO_FIPS_ENABLED} not found") - ) + if is_fips_enabled(sac) { + CheckerResult { + status: CheckStatus::PASS, + ..Default::default() + } + } else { + skip_fips_not_enabled() + } } fn metadata(&self) -> CheckerMetadata { @@ -43,6 +58,9 @@ pub struct FIPS01010000Checker {} impl Checker for FIPS01010000Checker { fn execute(&self, sac: &dyn SystemAccess) -> CheckerResult { + if !is_fips_enabled(sac) { + return skip_fips_not_enabled(); + } check_file_contains!( sac, CRYPTO_FIPS_NAME, @@ -54,7 +72,7 @@ impl Checker for FIPS01010000Checker { fn metadata(&self) -> CheckerMetadata { CheckerMetadata { - title: format!("FIPS module is {EXPECTED_FIPS_NAME}.").to_string(), + title: format!("FIPS module is {EXPECTED_FIPS_NAME}."), id: "1.1".to_string(), level: 0, name: "fips01010000".to_string(), @@ -69,13 +87,16 @@ pub struct FIPS01020000Checker {} impl Checker for FIPS01020000Checker { fn execute(&self, sac: &dyn SystemAccess) -> CheckerResult { + if !is_fips_enabled(sac) { + return skip_fips_not_enabled(); + } + let result = check_file_exists!( sac, FIPS_KERNEL_CHECK_MARKER, format!("{FIPS_KERNEL_CHECK_MARKER} not found") ); - // Check if we need to continue if result.status == CheckStatus::FAIL { return result; } @@ -118,7 +139,7 @@ mod tests { usac.register_file(CRYPTO_FIPS_ENABLED, "0"); let checker = FIPS01000000Checker {}; let result = checker.execute(&usac); - assert_eq!(result.status, CheckStatus::FAIL); + assert_eq!(result.status, CheckStatus::SKIP); } #[test] pub fn test_fips01000000checker_fips_enabled() { @@ -140,6 +161,7 @@ mod tests { #[test] pub fn test_fips01010000checker_wrong_fips_name() { let mut usac = UnitTestSystemAccess::default(); + usac.register_file(CRYPTO_FIPS_ENABLED, EXPECTED_FIPS_ENABLED); usac.register_file(CRYPTO_FIPS_NAME, "some wrong name"); let checker = FIPS01010000Checker {}; let result = checker.execute(&usac); @@ -149,6 +171,7 @@ mod tests { #[test] pub fn test_fips01010000checker_passing() { let mut usac = UnitTestSystemAccess::default(); + usac.register_file(CRYPTO_FIPS_ENABLED, EXPECTED_FIPS_ENABLED); usac.register_file(CRYPTO_FIPS_NAME, EXPECTED_FIPS_NAME); let checker = FIPS01010000Checker {}; let result = checker.execute(&usac); @@ -158,6 +181,7 @@ mod tests { #[test] pub fn test_fips01020000checker_missing_module_check_marker() { let mut usac = UnitTestSystemAccess::default(); + usac.register_file(CRYPTO_FIPS_ENABLED, EXPECTED_FIPS_ENABLED); usac.register_file(FIPS_KERNEL_CHECK_MARKER, "1"); let checker = FIPS01020000Checker {}; let result = checker.execute(&usac); @@ -166,6 +190,7 @@ mod tests { #[test] pub fn test_fips01020000checker_missing_kernel_check_marker() { let mut usac = UnitTestSystemAccess::default(); + usac.register_file(CRYPTO_FIPS_ENABLED, EXPECTED_FIPS_ENABLED); usac.register_file(FIPS_MODULE_CHECK_MARKER, "1"); let checker = FIPS01020000Checker {}; let result = checker.execute(&usac); @@ -174,10 +199,38 @@ mod tests { #[test] pub fn test_fips01020000checker_passing() { let mut usac = UnitTestSystemAccess::default(); + usac.register_file(CRYPTO_FIPS_ENABLED, EXPECTED_FIPS_ENABLED); usac.register_file(FIPS_KERNEL_CHECK_MARKER, "1"); usac.register_file(FIPS_MODULE_CHECK_MARKER, "1"); let checker = FIPS01020000Checker {}; let result = checker.execute(&usac); assert_eq!(result.status, CheckStatus::PASS); } + + #[test] + pub fn test_is_fips_enabled_true() { + let mut usac = UnitTestSystemAccess::default(); + usac.register_file(CRYPTO_FIPS_ENABLED, EXPECTED_FIPS_ENABLED); + assert!(is_fips_enabled(&usac)); + } + + #[test] + pub fn test_is_fips_enabled_false() { + let mut usac = UnitTestSystemAccess::default(); + usac.register_file(CRYPTO_FIPS_ENABLED, "0"); + assert!(!is_fips_enabled(&usac)); + } + + #[test] + pub fn test_is_fips_enabled_missing_file() { + let usac = UnitTestSystemAccess::default(); + assert!(!is_fips_enabled(&usac)); + } + + #[test] + pub fn test_skip_fips_not_enabled() { + let result = skip_fips_not_enabled(); + assert_eq!(result.status, CheckStatus::SKIP); + assert!(!result.error.is_empty()); + } }