diff --git a/tests_e2e/test_suites/fips.yml b/tests_e2e/test_suites/fips.yml index 785671d0c1..bdff00098a 100644 --- a/tests_e2e/test_suites/fips.yml +++ b/tests_e2e/test_suites/fips.yml @@ -1,10 +1,16 @@ # # FIPS should not affect extension processing. The test enables FIPS and then executes an extension. # -# NOTE: Enabling FIPS is very specific to the distro. This test is only executed on RHEL 9.0. +# NOTE: Enabling FIPS is very specific to the distro. This test is only executed on Mariner 2. +# +# TODO: Add other distros. +# +# NOTE: FIPS can be enabled on RHEL9 using these instructions: see https://access.redhat.com/solutions/137833#rhel9), +# but extensions with protected settings do not work end-to-end, since the Agent can't decrypt the tenant +# certificate. # name: "FIPS" tests: - source: "fips/fips.py" -images: "rhel_90" +images: "mariner_2" owns_vm: true diff --git a/tests_e2e/tests/fips/fips.py b/tests_e2e/tests/fips/fips.py index f8c27b900b..9f490de4ca 100755 --- a/tests_e2e/tests/fips/fips.py +++ b/tests_e2e/tests/fips/fips.py @@ -19,7 +19,6 @@ import uuid from assertpy import fail -from typing import Any, Dict, List from tests_e2e.tests.lib.agent_test import AgentTest from tests_e2e.tests.lib.logging import log @@ -32,18 +31,15 @@ class Fips(AgentTest): """ - Enables FIPS on the test VM, which is a RHEL 9 VM (see https://access.redhat.com/solutions/137833#rhel9), then executes the CustomScript extension. - - TODO: Investigate whether extensions with protected settings are supported on FIPS-enabled systems. The Agent has issues handling the tenant - certificate on those systems (additional configuration on FIPS may be needed). + Enables FIPS on the test VM, which is Mariner 2 VM, and verifies that extensions with protected settings are handled correctly under FIPS. """ def run(self): ssh_client: SshClient = self._context.create_ssh_client() try: - command = "fips-mode-setup --enable" + command = "fips-enable_fips_mariner" log.info("Enabling FIPS on the test VM [%s]", command) - output = ssh_client.run_command(command, use_sudo=True) + output = ssh_client.run_command(command) log.info("Enable FIPS completed\n%s", output) except CommandError as e: raise Exception(f"Failed to enable FIPS: {e}") @@ -53,34 +49,25 @@ def run(self): vm.restart(wait_for_boot=True, ssh_client=ssh_client) try: - command = "fips-mode-setup --check" + command = "fips-check_fips_mariner" log.info("Verifying that FIPS is enabled [%s]", command) output = ssh_client.run_command(command).rstrip() if output != "FIPS mode is enabled.": - fail(f"FIPS i not enabled - '{command}' returned '{output}'") + fail(f"FIPS is not enabled - '{command}' returned '{output}'") log.info(output) except CommandError as e: raise Exception(f"Failed to verify that FIPS is enabled: {e}") + # Execute an extension with protected settings to ensure the tenant certificate can be decrypted under FIPS custom_script = VirtualMachineExtensionClient(self._context.vm, VmExtensionIds.CustomScript, resource_name="CustomScript") - log.info("Installing %s", custom_script) message = f"Hello {uuid.uuid4()}!" custom_script.enable( - settings={ + protected_settings={ 'commandToExecute': f"echo \'{message}\'" - }, - auto_upgrade_minor_version=False + } ) - custom_script.assert_instance_view(expected_version="2.0", expected_message=message) - - def get_ignore_error_rules(self) -> List[Dict[str, Any]]: - """ - Some extensions added by policy on the test subscription use protected settings, which produce this error. - """ - return [ - {'message': r'Failed to decrypt /var/lib/waagent/Certificates.p7m'} - ] + custom_script.assert_instance_view(expected_message=message) if __name__ == "__main__": diff --git a/tests_e2e/tests/scripts/fips-check_fips_mariner b/tests_e2e/tests/scripts/fips-check_fips_mariner new file mode 100755 index 0000000000..e5a7730be7 --- /dev/null +++ b/tests_e2e/tests/scripts/fips-check_fips_mariner @@ -0,0 +1,56 @@ +#!/usr/bin/env bash + +# Microsoft Azure Linux Agent +# +# Copyright 2018 Microsoft Corporation +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# +# Verifies whether FIPS is enabled on Mariner 2.0 +# + +set -euo pipefail + +# Check if FIPS mode is enabled by the kernel (returns 1 if enabled) +fips_enabled=$(sudo cat /proc/sys/crypto/fips_enabled) +if [ "$fips_enabled" != "1" ]; then + echo "FIPS is not enabled by the kernel: $fips_enabled" + exit 1 +fi + +# Check if sysctl is configured (returns crypto.fips_enabled = 1 if enabled) +sysctl_configured=$(sudo sysctl crypto.fips_enabled) +if [ "$sysctl_configured" != "crypto.fips_enabled = 1" ]; then + echo "sysctl is not configured for FIPS: $sysctl_configured" + exit 1 +fi + +# Check if openssl library is running in FIPS mode +# MD5 should fail; the command's output should be similar to: +# Error setting digest +# 131590634539840:error:060800C8:digital envelope routines:EVP_DigestInit_ex:disabled for FIPS:crypto/evp/digest.c:135: +openssl=$(openssl md5 < /dev/null 2>&1 || true) +if [[ "$openssl" != *"disabled for FIPS"* ]]; then + echo "openssl is not running in FIPS mode: $openssl" + exit 1 +fi + +# Check if dracut-fips is installed (returns dracut-fips-) +dracut_fips=$( (rpm -qa | grep dracut-fips) || true ) +if [[ "$dracut_fips" != *"dracut-fips"* ]]; then + echo "dracut-fips is not installed: $dracut_fips" + exit 1 +fi + +echo "FIPS mode is enabled." \ No newline at end of file diff --git a/tests_e2e/tests/scripts/fips-enable_fips_mariner b/tests_e2e/tests/scripts/fips-enable_fips_mariner new file mode 100755 index 0000000000..8259b8d6c2 --- /dev/null +++ b/tests_e2e/tests/scripts/fips-enable_fips_mariner @@ -0,0 +1,53 @@ +#!/usr/bin/env bash + +# Microsoft Azure Linux Agent +# +# Copyright 2018 Microsoft Corporation +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# +# Enables FIPS on Mariner 2.0 +# + +set -euo pipefail + +echo "Installing packages required packages to enable FIPS..." +sudo tdnf install -y grubby dracut-fips + +# +# Set boot_uuid variable for the boot partition if different from the root +# +boot_dev="$(df /boot/ | tail -1 | cut -d' ' -f1)" +echo "Boot partition: $boot_dev" + +root_dev="$(df / | tail -1 | cut -d' ' -f1)" +echo "Root partition: $root_dev" + +boot_uuid="" +if [ "$boot_dev" != "$root_dev" ]; then + boot_uuid="boot=UUID=$(blkid $boot_dev -s UUID -o value)" + echo "Boot UUID: $boot_uuid" +fi + +# +# Enable FIPS and set boot= parameter +# +echo "Enabling FIPS..." +if sudo grub2-editenv - list | grep -q kernelopts; then + set -x + sudo grub2-editenv - set "$(sudo grub2-editenv - list | grep kernelopts) fips=1 $boot_uuid" +else + set -x + sudo grubby --update-kernel=ALL --args="fips=1 $boot_uuid" +fi \ No newline at end of file