]> git.ipfire.org Git - thirdparty/mkosi.git/commitdiff
Add new Ssh=auto and Ssh=runtime options
authorSeptatrix <24257556+Septatrix@users.noreply.github.com>
Mon, 7 Apr 2025 15:33:54 +0000 (17:33 +0200)
committerSeptatrix <24257556+Septatrix@users.noreply.github.com>
Mon, 14 Apr 2025 17:06:07 +0000 (19:06 +0200)
Fixes #3654

mkosi/__init__.py
mkosi/config.py
mkosi/qemu.py
mkosi/resources/man/mkosi.1.md
tests/test_json.py

index 9a7650848cdfe8908385fe67806935f6654734ed..90f64f322c73d352ea3a28bb51abbc4104dddf6a 100644 (file)
@@ -65,6 +65,7 @@ from mkosi.config import (
     OutputFormat,
     SecureBootSignTool,
     ShimBootloader,
+    Ssh,
     Verb,
     Verity,
     Vmm,
@@ -2879,7 +2880,14 @@ def check_tools(config: Config, verb: Verb) -> None:
 
 
 def configure_ssh(context: Context) -> None:
-    if not context.config.ssh:
+    if context.config.ssh in (Ssh.never, Ssh.runtime):
+        return
+
+    if (
+        context.config.ssh == Ssh.auto
+        and (context.root / "usr/lib/systemd/system-generators/systemd-ssh-generator").exists()
+    ):
+        # systemd-ssh-generator is installed, so we don't need to configure SSH.
         return
 
     unitdir = context.root / "usr/lib/systemd/system"
index c0613847acdfde7e7db0a310f15a94b13d2d9d4f..956e29bc94863691a264f0daddb078b69b629394 100644 (file)
@@ -365,6 +365,13 @@ class Vmm(StrEnum):
     vmspawn = enum.auto()
 
 
+class Ssh(StrEnum):
+    always = enum.auto()
+    auto = enum.auto()
+    runtime = enum.auto()
+    never = enum.auto()
+
+
 class Incremental(StrEnum):
     yes = enum.auto()
     no = enum.auto()
@@ -1979,7 +1986,7 @@ class Config:
 
     autologin: bool
     make_initrd: bool
-    ssh: bool
+    ssh: Ssh
     selinux_relabel: ConfigFeature
 
     secure_boot: bool
@@ -3296,9 +3303,10 @@ SETTINGS: list[ConfigSetting[Any]] = [
     ),
     ConfigSetting(
         dest="ssh",
-        metavar="BOOL",
         section="Content",
-        parse=config_parse_boolean,
+        parse=config_make_enum_parser_with_boolean(Ssh, yes=Ssh.always, no=Ssh.never),
+        default=Ssh.auto,
+        choices=Ssh.choices(),
         help="Set up SSH access from the host to the final image via 'mkosi ssh'",
     ),
     ConfigSetting(
@@ -5344,7 +5352,7 @@ def summary(config: Config) -> str:
 
                           Autologin: {yes_no(config.autologin)}
                         Make Initrd: {yes_no(config.make_initrd)}
-                                SSH: {yes_no(config.ssh)}
+                                SSH: {config.ssh}
                     SELinux Relabel: {config.selinux_relabel}
 """
 
@@ -5593,6 +5601,7 @@ def json_type_transformer(refcls: Union[type[Args], type[Config]]) -> Callable[[
         Architecture: enum_transformer,
         BiosBootloader: enum_transformer,
         ShimBootloader: enum_transformer,
+        Ssh: enum_transformer,
         Bootloader: enum_transformer,
         Compression: enum_transformer,
         ConfigFeature: enum_transformer,
index 0c60148dd0845e0f04762458d69aed98ae305a10..3e5280d0e7178b880694fa9e5b8c360350d19dd3 100644 (file)
@@ -36,6 +36,7 @@ from mkosi.config import (
     Firmware,
     Network,
     OutputFormat,
+    Ssh,
     VsockCID,
     finalize_term,
     format_bytes,
@@ -946,7 +947,7 @@ def finalize_credentials(config: Config) -> dict[str, str]:
                 sandbox=config.sandbox(options=["--become-root", "--ro-bind", "/etc/passwd", "/etc/passwd"]),
             ).stdout.strip()
             creds["ssh.authorized_keys.root"] = sshpubkey
-        elif config.ssh:
+        elif config.ssh in (Ssh.always, Ssh.runtime):
             die(
                 "Ssh= is enabled but no SSH certificate was found",
                 hint="Run 'mkosi genkey' to automatically create one",
index ad6bfd78b9f7521630d81b9dd1cacfb34667e364..32329ea14a99f9eacadbf5f5f92d8eb5d716df6e 100644 (file)
@@ -1154,8 +1154,14 @@ boolean argument: either `1`, `yes`, or `true` to enable, or `0`, `no`,
     used as an initramfs.
 
 `Ssh=`, `--ssh=`
-:   If specified, an **sshd** socket unit and matching service are installed
-    in the final image that expose SSH over VSock. When building with this
+:   Specifies whether to install an **sshd** socket unit and matching service
+    in the final image. Takes one of `always`, `never`, `auto` or `runtime`.
+    Defaults to `auto`. If set to `auto` and `systemd-ssh-generator`
+    is not preset in the image, or set to `always`, mkosi will install **sshd** units
+    in the final image that expose SSH over VSock. If set to `never`,
+    mkosi will not install the **sshd* units. If the `runtime` value is used,
+    mkosi will also not install any units but abort starting `mkosi vm` if no
+    SSH credentials are configured. When building with this
     option and running the image using `mkosi vm`, the `mkosi ssh`
     command can be used to connect to the container/VM via SSH. Note that
     you still have to make sure openssh is installed in the image to make
@@ -1941,10 +1947,10 @@ boolean argument: either `1`, `yes`, or `true` to enable, or `0`, `no`,
 `SshKey=`, `--ssh-key=`
 :   Path to the X.509 private key in PEM format to use to connect to a
     virtual machine started with `mkosi vm` and built with the `Ssh=`
-    option enabled via the `mkosi ssh` command. If not configured and
-    `mkosi.key` exists in the working directory, it will automatically be
-    used for this purpose. Run `mkosi genkey` to automatically generate
-    a key in `mkosi.key`.
+    option enabled (or **systemd-ssh-generator** installed) via the `mkosi ssh` command.
+    If not configured and `mkosi.key` exists in the working directory,
+    it will automatically be used for this purpose.
+    Run `mkosi genkey` to automatically generate a key in `mkosi.key`.
 
 `SshCertificate=`, `--ssh-certificate=`
 :   Path to the X.509 certificate in PEM format to provision as the SSH
index 11cd2d7efb67283287e26a291d6b69874bd78cc0..41edd7becf4b1c587da70fe266be6cb7e0814e5a 100644 (file)
@@ -36,6 +36,7 @@ from mkosi.config import (
     OutputFormat,
     SecureBootSignTool,
     ShimBootloader,
+    Ssh,
     UKIProfile,
     Verb,
     Verity,
@@ -374,7 +375,7 @@ def test_config() -> None:
                 "uki",
                 "kernel"
             ],
-            "Ssh": false,
+            "Ssh": "auto",
             "SshCertificate": "/path/to/cert",
             "SshKey": null,
             "StorageTargetMode": "enabled",
@@ -580,7 +581,7 @@ def test_config() -> None:
         split_artifacts=[ArtifactOutput.uki, ArtifactOutput.kernel],
         ssh_certificate=Path("/path/to/cert"),
         ssh_key=None,
-        ssh=False,
+        ssh=Ssh.auto,
         storage_target_mode=ConfigFeature.enabled,
         sync_scripts=[Path("/sync")],
         sysupdate_dir=Path("/sysupdate"),