From 1bd8073958723e38bbb7d51aab1fe7b37c2e5236 Mon Sep 17 00:00:00 2001 From: Maximilian Bosch Date: Fri, 21 Mar 2025 17:14:23 +0000 Subject: [PATCH] nixos/test-driver: add backdoor based on systemd-ssh-proxy & AF_VSOCK With this it's possible to trivially SSH into running machines from the test-driver. This is especially useful when running VM tests interactively on a remote system. This is based on `systemd-ssh-proxy(1)`, so there's no need to configure any additional networking on the host-side. Suggested-by: Ryan Lahfa --- ...nning-nixos-tests-interactively.section.md | 29 +++++++++++++++++++ nixos/doc/manual/redirects.json | 6 ++++ nixos/lib/testing/nodes.nix | 22 +++++++++++--- .../modules/testing/test-instrumentation.nix | 20 +++++++++++++ 4 files changed, 73 insertions(+), 4 deletions(-) diff --git a/nixos/doc/manual/development/running-nixos-tests-interactively.section.md b/nixos/doc/manual/development/running-nixos-tests-interactively.section.md index b65cab992253..2b0f44a04e44 100644 --- a/nixos/doc/manual/development/running-nixos-tests-interactively.section.md +++ b/nixos/doc/manual/development/running-nixos-tests-interactively.section.md @@ -63,6 +63,35 @@ using: Once the connection is established, you can enter commands in the socat terminal where socat is running. +## SSH Access for test machines {#sec-nixos-test-ssh-access} + +An SSH-based backdoor to log into machines can be enabled with + +```nix +{ + name = "…"; + nodes.machines = { /* … */ }; + sshBackdoor.enable = true; +} +``` + +This creates a [vsock socket](https://man7.org/linux/man-pages/man7/vsock.7.html) +for each VM to log in with SSH. This configures root login with an empty password. + +When the VMs get started interactively with the test-driver, it's possible to +connect to `machine` with + +``` +$ ssh vsock/3 -o User=root +``` + +The socket numbers correspond to the node number of the test VM, but start +at three instead of one because that's the lowest possible +vsock number. + +On non-NixOS systems you'll probably need to enable +the SSH config from {manpage}`systemd-ssh-proxy(1)` yourself. + ## Port forwarding to NixOS test VMs {#sec-nixos-test-port-forwarding} If your test has only a single VM, you may use e.g. diff --git a/nixos/doc/manual/redirects.json b/nixos/doc/manual/redirects.json index be29c7ca049a..b493295b9908 100644 --- a/nixos/doc/manual/redirects.json +++ b/nixos/doc/manual/redirects.json @@ -1817,6 +1817,9 @@ "sec-test-options-reference": [ "index.html#sec-test-options-reference" ], + "test-opt-sshBackdoor.enable": [ + "index.html#test-opt-sshBackdoor.enable" + ], "test-opt-defaults": [ "index.html#test-opt-defaults" ], @@ -1904,6 +1907,9 @@ "sec-nixos-test-shell-access": [ "index.html#sec-nixos-test-shell-access" ], + "sec-nixos-test-ssh-access": [ + "index.html#sec-nixos-test-ssh-access" + ], "sec-nixos-test-port-forwarding": [ "index.html#sec-nixos-test-port-forwarding" ], diff --git a/nixos/lib/testing/nodes.nix b/nixos/lib/testing/nodes.nix index caefac6c748c..ee9e7ebeae68 100644 --- a/nixos/lib/testing/nodes.nix +++ b/nixos/lib/testing/nodes.nix @@ -13,6 +13,7 @@ let mapAttrs mkDefault mkIf + mkMerge mkOption mkForce optional @@ -77,6 +78,14 @@ in { options = { + sshBackdoor = { + enable = mkOption { + default = false; + type = types.bool; + description = "Whether to turn on the vsock-based SSH backdoor for all VMs."; + }; + }; + node.type = mkOption { type = types.raw; default = baseOS.type; @@ -172,10 +181,15 @@ in passthru.nodes = config.nodesCompat; - defaults = mkIf config.node.pkgsReadOnly { - nixpkgs.pkgs = config.node.pkgs; - imports = [ ../../modules/misc/nixpkgs/read-only.nix ]; - }; + defaults = mkMerge [ + (mkIf config.node.pkgsReadOnly { + nixpkgs.pkgs = config.node.pkgs; + imports = [ ../../modules/misc/nixpkgs/read-only.nix ]; + }) + (mkIf config.sshBackdoor.enable { + testing.sshBackdoor.enable = true; + }) + ]; }; } diff --git a/nixos/modules/testing/test-instrumentation.nix b/nixos/modules/testing/test-instrumentation.nix index 49594964ed5f..8ace4ab30abf 100644 --- a/nixos/modules/testing/test-instrumentation.nix +++ b/nixos/modules/testing/test-instrumentation.nix @@ -87,6 +87,10 @@ in machine.switch_root() to leave stage 1 and proceed to stage 2 ''; + sshBackdoor = { + enable = mkEnableOption "vsock-based ssh backdoor for the VM"; + }; + }; config = { @@ -100,6 +104,18 @@ in } ]; + services.openssh = mkIf config.testing.sshBackdoor.enable { + enable = true; + settings = { + PermitRootLogin = "yes"; + PermitEmptyPasswords = "yes"; + }; + }; + + security.pam.services.sshd = mkIf config.testing.sshBackdoor.enable { + allowNullPassword = true; + }; + systemd.services.backdoor = lib.mkMerge [ backdoorService { @@ -175,6 +191,10 @@ in # we avoid defining attributes if not possible. # TODO: refactor such that test-instrumentation can import qemu-vm package = lib.mkDefault pkgs.qemu_test; + + options = mkIf config.testing.sshBackdoor.enable [ + "-device vhost-vsock-pci,guest-cid=${toString (config.virtualisation.test.nodeNumber + 2)}" + ]; }; };