From 9aee1e443ffc893c1ed657cf86e82b3a1fe367e7 Mon Sep 17 00:00:00 2001 From: "Andres D. Molins" Date: Thu, 16 May 2024 20:20:22 +0200 Subject: [PATCH] Problem: A node operator cannot check or add support for confidential computing. Solution: Implemented a setting to allow node operator to enable confidential computing. A check ensure that the system is well configured, and it shows that configuration on the /public/config endpoint. --- src/aleph/vm/conf.py | 14 +++++++++++++- src/aleph/vm/orchestrator/views/__init__.py | 6 ++++++ src/aleph/vm/utils.py | 8 ++++++++ tests/supervisor/test_utils.py | 13 +++++++++++++ 4 files changed, 40 insertions(+), 1 deletion(-) create mode 100644 tests/supervisor/test_utils.py diff --git a/src/aleph/vm/conf.py b/src/aleph/vm/conf.py index 0d22625e8..14f9e4b6c 100644 --- a/src/aleph/vm/conf.py +++ b/src/aleph/vm/conf.py @@ -16,7 +16,7 @@ from pydantic.env_settings import DotenvType, env_file_sentinel from pydantic.typing import StrPath -from aleph.vm.utils import file_hashes_differ, is_command_available +from aleph.vm.utils import check_system_module, file_hashes_differ, is_command_available logger = logging.getLogger(__name__) @@ -261,6 +261,12 @@ class Settings(BaseSettings): description="Default hypervisor to use on running instances, can be Firecracker or QEmu", ) + USE_CONFIDENTIAL_COMPUTING: bool = Field( + default=False, + description="Enable Confidential Computing using AMD-SEV. It will test if the host is compatible " + "with SEV and SEV-ES", + ) + # Tests on programs FAKE_DATA_PROGRAM: Optional[Path] = None @@ -336,6 +342,12 @@ def check(self): int(ipv4_pool_length) <= settings.IPV4_NETWORK_PREFIX_LENGTH ), "The IPv4 address pool prefix must be shorter than an individual VM network prefix" + if self.USE_CONFIDENTIAL_COMPUTING: + assert check_system_module("kvm_amd/parameters/sev") == "Y", "SEV feature isn't enabled, enable it in BIOS." + assert ( + check_system_module("kvm_amd/parameters/sev_es") == "Y" + ), "SEV-ES feature isn't enabled, enable it in BIOS." + if self.FAKE_DATA_PROGRAM: assert self.FAKE_DATA_PROGRAM, "Local fake program directory not specified" assert self.FAKE_DATA_MESSAGE, "Local fake message not specified" diff --git a/src/aleph/vm/orchestrator/views/__init__.py b/src/aleph/vm/orchestrator/views/__init__.py index 8b7702ba4..6f5d8dbc7 100644 --- a/src/aleph/vm/orchestrator/views/__init__.py +++ b/src/aleph/vm/orchestrator/views/__init__.py @@ -331,6 +331,12 @@ async def status_public_config(request: web.Request): "PAYMENT_RECEIVER_ADDRESS": settings.PAYMENT_RECEIVER_ADDRESS, "PAYMENT_SUPER_TOKEN": settings.PAYMENT_SUPER_TOKEN, "PAYMENT_CHAIN_ID": settings.PAYMENT_CHAIN_ID, + "PAYMENT_MONITOR_INTERVAL": settings.PAYMENT_MONITOR_INTERVAL, + }, + "computing": { + "ENABLE_QEMU_SUPPORT": settings.ENABLE_QEMU_SUPPORT, + "INSTANCE_DEFAULT_HYPERVISOR": settings.INSTANCE_DEFAULT_HYPERVISOR, + "USE_CONFIDENTIAL_COMPUTING": settings.USE_CONFIDENTIAL_COMPUTING, }, }, dumps=dumps_for_json, diff --git a/src/aleph/vm/utils.py b/src/aleph/vm/utils.py index 63ce18253..b94f96cc7 100644 --- a/src/aleph/vm/utils.py +++ b/src/aleph/vm/utils.py @@ -130,6 +130,14 @@ def is_command_available(command): return False +def check_system_module(module_path) -> str: + try: + output = subprocess.check_output(["cat", "/sys/module", module_path], stderr=subprocess.STDOUT) + return str(output) + except subprocess.CalledProcessError: + return "" + + def fix_message_validation(message: dict) -> dict: """Patch a fake message program to pass validation.""" message["item_content"] = json.dumps(message["content"]) diff --git a/tests/supervisor/test_utils.py b/tests/supervisor/test_utils.py new file mode 100644 index 000000000..93b1630c5 --- /dev/null +++ b/tests/supervisor/test_utils.py @@ -0,0 +1,13 @@ +from unittest import mock + +from aleph.vm.utils import check_system_module + + +def test_check_system_module_enabled(): + with mock.patch( + "aleph.vm.utils.subprocess.check_output", + return_value="Y", + ): + expected_value = "Y" + output = check_system_module("kvm_amd/parameters/sev_enp") + assert output == expected_value