Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

CVM: add attestation report test for Azure Linux using snpguest tool #3529

Open
wants to merge 4 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 8 additions & 1 deletion lisa/tools/cargo.py
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,8 @@ def __install_dependencies(self) -> None:

def build(
self,
release: bool = True,
features: str = "",
sudo: bool = False,
cwd: Optional[PurePath] = None,
) -> ExecutableResult:
Expand All @@ -132,8 +134,13 @@ def build(
if os.path.dirname(self._command) not in path:
path = f"{os.path.dirname(self._command)}:{path}"

command = "build"
if release:
command = f"{command} --release"
if features:
command = f"{command} --features={features}"
result = self.run(
"build",
command,
expected_exit_code=0,
expected_exit_code_failure_message=err_msg,
sudo=sudo,
Expand Down
21 changes: 13 additions & 8 deletions microsoft/testsuites/cvm/cvm_attestation.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,14 +13,15 @@
features,
)
from lisa.features.security_profile import CvmEnabled
from lisa.operating_system import Ubuntu
from lisa.operating_system import CBLMariner, Ubuntu
trungams marked this conversation as resolved.
Show resolved Hide resolved
from lisa.sut_orchestrator import AZURE
from lisa.testsuite import TestResult, simple_requirement
from lisa.tools import Ls
from lisa.util import SkippedException, UnsupportedDistroException
from microsoft.testsuites.cvm.cvm_attestation_tool import (
AzureCVMAttestationTests,
NestedCVMAttestationTests,
SnpGuest,
)


Expand All @@ -34,10 +35,11 @@
class AzureCVMAttestationTestSuite(TestSuite):
def before_case(self, log: Logger, **kwargs: Any) -> None:
node: Node = kwargs["node"]
if not isinstance(node.os, Ubuntu):
if not isinstance(node.os, Ubuntu) and not isinstance(node.os, CBLMariner):
raise SkippedException(
UnsupportedDistroException(
node.os, "CVM attestation report supports only Ubuntu."
node.os,
"CVM attestation report supports only Ubuntu and Azure Linux.",
)
)

Expand All @@ -61,11 +63,14 @@ def verify_azure_cvm_attestation_report(
result: TestResult,
variables: Dict[str, Any],
) -> None:
node.tools[AzureCVMAttestationTests].run_cvm_attestation(
result,
environment,
log_path,
)
if isinstance(node.os, Ubuntu):
node.tools[AzureCVMAttestationTests].run_cvm_attestation(
result,
environment,
log_path,
)
elif isinstance(node.os, CBLMariner):
node.tools[SnpGuest].run_cvm_attestation()


@TestSuiteMetadata(
Expand Down
146 changes: 144 additions & 2 deletions microsoft/testsuites/cvm/cvm_attestation_tool.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,11 @@
from lisa import Environment
from lisa.executable import Tool
from lisa.features import SerialConsole
from lisa.operating_system import Posix, Ubuntu
from lisa.operating_system import CBLMariner, Posix, Ubuntu
from lisa.testsuite import TestResult
from lisa.tools import Dmesg, Echo, Git, Make
from lisa.tools import Cargo, Dmesg, Echo, Git, Make, Mkdir
from lisa.util import UnsupportedDistroException
from lisa.util.process import ExecutableResult


class AzureCVMAttestationTests(Tool):
Expand Down Expand Up @@ -121,6 +122,147 @@ def _save_attestation_report(self, output: str, log_path: Path) -> None:
f.write(output)


class SnpGuest(Tool):
trungams marked this conversation as resolved.
Show resolved Hide resolved
_snpguest_repo = "https://github.com/virtee/snpguest"
cmd_path: PurePath
repo_root: PurePath

@property
def command(self) -> str:
return str(self.cmd_path)

@property
def can_install(self) -> bool:
return True

@property
def dependencies(self) -> List[Type[Tool]]:
return [Git, Cargo, Mkdir]

def _initialize(self, *args: Any, **kwargs: Any) -> None:
tool_path = self.get_tool_path(use_global=True)

self.repo_root = tool_path / "snpguest"
self.cmd_path = self.repo_root / "target" / "release" / "snpguest"

def _install(self) -> bool:
if isinstance(self.node.os, CBLMariner):
self.node.os.install_packages(["perl", "tpm2-tss-devel"])
tool_path = self.get_tool_path(use_global=True)
git = self.node.tools[Git]
git.clone(self._snpguest_repo, tool_path)

cargo = self.node.tools[Cargo]
cargo.build(release=True, features="hyperv", sudo=False, cwd=self.repo_root)

return self._check_exists()

def _fetch_ca(
self,
certs_dir: str,
encoding: str = "der",
processor_model: str = "milan",
endorser: str = "vcek",
) -> ExecutableResult:
failure_msg = "failed to request CA chain from the KDS"
return self.run(
f"fetch ca {encoding} {processor_model} {certs_dir} --endorser {endorser}",
expected_exit_code=0,
expected_exit_code_failure_message=failure_msg,
shell=True,
sudo=False,
force_run=True,
)

def _fetch_vcek(
self,
certs_dir: str,
attestation_report_path: str,
encoding: str = "der",
processor_model: str = "milan",
) -> ExecutableResult:
failure_msg = "failed to request VCEK from the KDS"
return self.run(
f"fetch vcek {encoding} {processor_model} {certs_dir} "
f"{attestation_report_path}",
expected_exit_code=0,
expected_exit_code_failure_message=failure_msg,
shell=True,
sudo=False,
force_run=True,
)

def _request_attestation_report(
self, attestation_report_path: str, request_file_path: str
) -> ExecutableResult:
failure_msg = "failed to request attestation report from the host"
return self.run(
f"report {attestation_report_path} {request_file_path} --platform --vmpl 0",
expected_exit_code=0,
expected_exit_code_failure_message=failure_msg,
shell=True,
sudo=True,
force_run=True,
)

def _verify_certs(self, certs_dir: str) -> ExecutableResult:
failure_msg = "failed to verify certificates"
return self.run(
f"verify certs {certs_dir}",
expected_exit_code=0,
expected_exit_code_failure_message=failure_msg,
shell=True,
sudo=False,
force_run=True,
)

def _verify_attestation(
self, certs_dir: str, attestation_report_path: str
) -> ExecutableResult:
failure_msg = "failed to verify attestation report"
return self.run(
f"verify attestation {certs_dir} {attestation_report_path}",
expected_exit_code=0,
expected_exit_code_failure_message=failure_msg,
shell=True,
sudo=False,
force_run=True,
)

def run_cvm_attestation(self, processor_model: str = "milan") -> None:
"""Regular attestation workflow

1. Request attestation report
2. Request AMD Root Key (ARK) and AMD SEV Key (ASK) from AMD Key Distribution
Service (KDS)
3. Request the Versioned Chip Endorsement Key (VCEK) from AMD KDS
4. Verify the certificates obtained
5. Verify the attestation report
"""
data_dir = self.repo_root / "data"
certs_dir = data_dir / "certs"
attestation_report_path = data_dir / "attestation-report.bin"
request_file_path = data_dir / "request-file.txt"

mkdir = self.node.tools[Mkdir]
mkdir.create_directory(certs_dir.as_posix())

self._request_attestation_report(
attestation_report_path.as_posix(), request_file_path.as_posix()
)
self._fetch_ca(certs_dir.as_posix(), processor_model=processor_model)
self._fetch_vcek(
certs_dir.as_posix(),
attestation_report_path.as_posix(),
processor_model=processor_model,
)

self._verify_certs(certs_dir.as_posix())
self._verify_attestation(
certs_dir.as_posix(), attestation_report_path.as_posix()
)


class NestedCVMAttestationTests(Tool):
repo = "https://github.com/microsoft/confidential-sidecar-containers.git"
cmd_path: str
Expand Down
Loading