Enhance security by ensuring unique SSH host keys for VMs and protecting registry credentials. Update documentation to reflect changes in SSH key management and improve state file permissions.

This commit is contained in:
kstyagi@brahmai.in
2026-09-04 21:31:54 +00:00
parent 1022f24c34
commit a8dbc704e9
7 changed files with 147 additions and 16 deletions
+56 -3
View File
@@ -4,6 +4,7 @@ import hashlib
import tempfile
import unittest
from pathlib import Path
from unittest.mock import patch
from uvm.config import Settings
from uvm.errors import UvmError
@@ -21,12 +22,15 @@ from uvm.system import CommandResult
class PasswordHashRunner:
def __init__(self) -> None:
self.command: tuple[str, ...] | None = None
self.calls: list[tuple[str, ...]] = []
self.options: dict[str, object] = {}
def run(self, command, **options) -> CommandResult:
self.command = tuple(str(part) for part in command)
self.calls.append(self.command)
self.options = options
return CommandResult(self.command, 0, stdout="$6$salt$password-hash\n")
stdout = "$6$salt$password-hash\n" if self.command[0] == "openssl" else ""
return CommandResult(self.command, 0, stdout=stdout)
class ImageStoreTests(unittest.TestCase):
@@ -79,15 +83,27 @@ class ImageStoreTests(unittest.TestCase):
def test_enables_root_password_login_before_existing_sshd_settings(self) -> None:
updated = _enable_ssh_password_authentication(
"PasswordAuthentication no\nPermitRootLogin prohibit-password\n",
"HostKey /insecure/shared-key\n"
"PasswordAuthentication no\n"
"PermitRootLogin prohibit-password\n",
"root",
)
self.assertTrue(
updated.startswith(
"# Managed by uvm\nPasswordAuthentication yes\nPermitRootLogin yes\n"
"# Managed by uvm\n"
"HostKey /etc/ssh/ssh_host_rsa_key\n"
"HostKey /etc/ssh/ssh_host_ecdsa_key\n"
"HostKey /etc/ssh/ssh_host_ed25519_key\n"
"PasswordAuthentication no\n"
"PermitRootLogin yes\n"
"Match User root\n"
" PasswordAuthentication yes\n"
"Match all\n"
)
)
self.assertNotIn("/insecure/shared-key", updated)
self.assertNotIn("PermitRootLogin prohibit-password", updated)
def test_removes_only_the_public_firecracker_demo_key(self) -> None:
own_key = "ssh-ed25519 AAAA-own-key developer@example"
@@ -97,3 +113,40 @@ class ImageStoreTests(unittest.TestCase):
)
self.assertEqual(updated, f"{own_key}\n")
def test_generates_three_unique_guest_host_key_types(self) -> None:
runner = PasswordHashRunner()
store = ImageStore(Settings(), runner=runner) # type: ignore[arg-type]
with (
tempfile.TemporaryDirectory() as temporary_directory,
patch.object(store, "_read_guest_file", return_value=None),
patch.object(store, "_write_guest_file") as write_guest_file,
):
store._replace_guest_host_keys(
Path("/tmp/rootfs.ext4"),
Path(temporary_directory),
)
keygen_calls = [call for call in runner.calls if call[0] == "ssh-keygen"]
self.assertEqual([call[3] for call in keygen_calls], ["rsa", "ecdsa", "ed25519"])
self.assertEqual(write_guest_file.call_count, 6)
def test_optional_guest_file_inspection_fails_closed_on_debugfs_errors(self) -> None:
class FailedRunner:
@staticmethod
def run(_command, **_options) -> CommandResult:
return CommandResult(
args=("debugfs",),
returncode=0,
stderr="filesystem checksum failure",
)
store = ImageStore(Settings(), runner=FailedRunner()) # type: ignore[arg-type]
with tempfile.TemporaryDirectory() as temporary_directory:
with self.assertRaises(UvmError):
store._read_guest_file(
Path("/tmp/rootfs.ext4"),
"/root/.ssh/authorized_keys",
Path(temporary_directory) / "authorized_keys",
required=False,
)
+9
View File
@@ -88,3 +88,12 @@ class StateStoreTests(unittest.TestCase):
self.store.initialize()
self.assertEqual(stat.S_IMODE(self.settings.state_path.stat().st_mode), 0o600)
def test_load_protects_registry_credentials_without_initialization(self) -> None:
self.base.mkdir(parents=True)
self.settings.state_path.write_text('{"vms": {}}', encoding="utf-8")
self.settings.state_path.chmod(0o644)
self.store.load()
self.assertEqual(stat.S_IMODE(self.settings.state_path.stat().st_mode), 0o600)