From ca17c52dd75344c710f4eae23a50e13859b46899 Mon Sep 17 00:00:00 2001 From: Hugo Herter Date: Wed, 29 May 2024 20:13:15 +0200 Subject: [PATCH] Fix: CRN API did not expose CPU features for trusted computing Trusted computing requires CPU features such as `sev`, `sev_es` and `sev_snp`. This adds the field `properties.cpu.features` `/about/usage/system` as a list of CPU features. Currently, only SEV related features are present, but more can be added, for example `avx2`, `fma` and `f16c`. Adding them will require ensuring that they are actually active and not just present on the CPU via `/proc/cpuinfo`. This work is based on a proposal to add the relevant field on aleph-message: https://github.com/aleph-im/aleph-message/pull/100 --- pyproject.toml | 2 +- src/aleph/vm/conf.py | 15 +++++++++----- src/aleph/vm/orchestrator/resources.py | 17 +++++++++++++++- src/aleph/vm/utils.py | 28 ++++++++++++++++++++++++++ tests/supervisor/test_utils.py | 22 +++++++++++++++++++- 5 files changed, 76 insertions(+), 8 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 067de413b..6f5f5cedd 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -29,7 +29,7 @@ dependencies = [ "aiodns==3.1.0", "setproctitle==1.3.3", "pyyaml==6.0.1", - "aleph-message==0.4.4", + "aleph-message @ git+https://github.com/aleph-im/aleph-message@hoh-add-cpu-features#egg=aleph-message", "eth-account~=0.10", "sentry-sdk==1.31.0", "aioredis==1.3.1", diff --git a/src/aleph/vm/conf.py b/src/aleph/vm/conf.py index 7743c44da..86f83cca8 100644 --- a/src/aleph/vm/conf.py +++ b/src/aleph/vm/conf.py @@ -16,7 +16,12 @@ from pydantic.env_settings import DotenvType, env_file_sentinel from pydantic.typing import StrPath -from aleph.vm.utils import check_system_module, file_hashes_differ, is_command_available +from aleph.vm.utils import ( + check_amd_sev_es_supported, + check_amd_sev_supported, + file_hashes_differ, + is_command_available, +) logger = logging.getLogger(__name__) @@ -384,11 +389,11 @@ def check(self): ), "Command `qemu-system-x86_64` not found, run `apt install qemu-system-x86`" if self.ENABLE_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" assert self.SEV_CTL_PATH.is_file(), f"File not found {self.SEV_CTL_PATH}" + assert check_amd_sev_supported(), "SEV feature isn't enabled, enable it in BIOS" + assert check_amd_sev_es_supported(), "SEV-ES feature isn't enabled, enable it in BIOS" + # Not available on the test machine yet + # assert check_amd_sev_snp_supported(), "SEV-SNP feature isn't enabled, enable it in BIOS" assert self.ENABLE_QEMU_SUPPORT, "Qemu Support is needed for confidential computing and it's disabled, " "enable it setting the env variable `ENABLE_QEMU_SUPPORT=True` in configuration" diff --git a/src/aleph/vm/orchestrator/resources.py b/src/aleph/vm/orchestrator/resources.py index fe9deab26..0f6ba0966 100644 --- a/src/aleph/vm/orchestrator/resources.py +++ b/src/aleph/vm/orchestrator/resources.py @@ -12,7 +12,12 @@ from aleph.vm.conf import settings from aleph.vm.sevclient import SevClient -from aleph.vm.utils import cors_allow_all +from aleph.vm.utils import ( + check_amd_sev_es_supported, + check_amd_sev_snp_supported, + check_amd_sev_supported, + cors_allow_all, +) class Period(BaseModel): @@ -90,6 +95,16 @@ def get_machine_properties() -> MachineProperties: cpu=CpuProperties( architecture=cpu_info.get("raw_arch_string", cpu_info.get("arch_string_raw")), vendor=cpu_info.get("vendor_id", cpu_info.get("vendor_id_raw")), + features=list( + filter( + None, + ( + "sev" if check_amd_sev_supported() else None, + "sev_es" if check_amd_sev_es_supported() else None, + "sev_snp" if check_amd_sev_snp_supported() else None, + ), + ) + ), ), ) diff --git a/src/aleph/vm/utils.py b/src/aleph/vm/utils.py index 6c114253e..7af5eb855 100644 --- a/src/aleph/vm/utils.py +++ b/src/aleph/vm/utils.py @@ -137,6 +137,34 @@ def check_system_module(module_path: str) -> Optional[str]: return p.read_text().strip() +def check_amd_sev_supported() -> bool: + """Check if AMD SEV is supported on the system. + + AMD Secure Encrypted Virtualization (SEV) + Uses one key per virtual machine to isolate guests and the hypervisor from one another. + """ + return check_system_module("kvm_amd/parameters/sev") == "Y" + + +def check_amd_sev_es_supported() -> bool: + """Check if AMD SEV-ES is supported on the system. + + AMD Secure Encrypted Virtualization-Encrypted State (SEV-ES) + Encrypts all CPU register contents when a VM stops running. + """ + return check_system_module("kvm_amd/parameters/sev_es") == "Y" + + +def check_amd_sev_snp_supported() -> bool: + """Check if AMD SEV-SNP is supported on the system. + + AMD Secure Encrypted Virtualization-Secure Nested Paging (SEV-SNP) + Adds strong memory integrity protection to help prevent malicious hypervisor-based attacks like data replay, + memory re-mapping, and more in order to create an isolated execution environment. + """ + return check_system_module("kvm_amd/parameters/sev_snp") == "Y" + + 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 index 8b67fe1ef..2e66faabb 100644 --- a/tests/supervisor/test_utils.py +++ b/tests/supervisor/test_utils.py @@ -1,6 +1,11 @@ from unittest import mock -from aleph.vm.utils import check_system_module +from aleph.vm.utils import ( + check_amd_sev_es_supported, + check_amd_sev_snp_supported, + check_amd_sev_supported, + check_system_module, +) def test_check_system_module_enabled(): @@ -17,3 +22,18 @@ def test_check_system_module_enabled(): output = check_system_module("kvm_amd/parameters/sev_enp") assert output == expected_value + + assert check_amd_sev_supported() is True + assert check_amd_sev_es_supported() is True + assert check_amd_sev_snp_supported() is True + + with mock.patch( + "pathlib.Path.open", + mock.mock_open(read_data="N"), + ): + output = check_system_module("kvm_amd/parameters/sev_enp") + assert output is None + + assert check_amd_sev_supported() is False + assert check_amd_sev_es_supported() is False + assert check_amd_sev_snp_supported() is False