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 <masterancpp@gmail.com>
This commit is contained in:
Maximilian Bosch 2025-03-21 17:14:23 +00:00
parent cb74a2a15e
commit 1bd8073958
No known key found for this signature in database
4 changed files with 73 additions and 4 deletions

View file

@ -63,6 +63,35 @@ using:
Once the connection is established, you can enter commands in the socat terminal Once the connection is established, you can enter commands in the socat terminal
where socat is running. 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} ## Port forwarding to NixOS test VMs {#sec-nixos-test-port-forwarding}
If your test has only a single VM, you may use e.g. If your test has only a single VM, you may use e.g.

View file

@ -1817,6 +1817,9 @@
"sec-test-options-reference": [ "sec-test-options-reference": [
"index.html#sec-test-options-reference" "index.html#sec-test-options-reference"
], ],
"test-opt-sshBackdoor.enable": [
"index.html#test-opt-sshBackdoor.enable"
],
"test-opt-defaults": [ "test-opt-defaults": [
"index.html#test-opt-defaults" "index.html#test-opt-defaults"
], ],
@ -1904,6 +1907,9 @@
"sec-nixos-test-shell-access": [ "sec-nixos-test-shell-access": [
"index.html#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": [ "sec-nixos-test-port-forwarding": [
"index.html#sec-nixos-test-port-forwarding" "index.html#sec-nixos-test-port-forwarding"
], ],

View file

@ -13,6 +13,7 @@ let
mapAttrs mapAttrs
mkDefault mkDefault
mkIf mkIf
mkMerge
mkOption mkOption
mkForce mkForce
optional optional
@ -77,6 +78,14 @@ in
{ {
options = { 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 { node.type = mkOption {
type = types.raw; type = types.raw;
default = baseOS.type; default = baseOS.type;
@ -172,10 +181,15 @@ in
passthru.nodes = config.nodesCompat; passthru.nodes = config.nodesCompat;
defaults = mkIf config.node.pkgsReadOnly { defaults = mkMerge [
nixpkgs.pkgs = config.node.pkgs; (mkIf config.node.pkgsReadOnly {
imports = [ ../../modules/misc/nixpkgs/read-only.nix ]; nixpkgs.pkgs = config.node.pkgs;
}; imports = [ ../../modules/misc/nixpkgs/read-only.nix ];
})
(mkIf config.sshBackdoor.enable {
testing.sshBackdoor.enable = true;
})
];
}; };
} }

View file

@ -87,6 +87,10 @@ in
machine.switch_root() to leave stage 1 and proceed to stage 2 machine.switch_root() to leave stage 1 and proceed to stage 2
''; '';
sshBackdoor = {
enable = mkEnableOption "vsock-based ssh backdoor for the VM";
};
}; };
config = { 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 [ systemd.services.backdoor = lib.mkMerge [
backdoorService backdoorService
{ {
@ -175,6 +191,10 @@ in
# we avoid defining attributes if not possible. # we avoid defining attributes if not possible.
# TODO: refactor such that test-instrumentation can import qemu-vm # TODO: refactor such that test-instrumentation can import qemu-vm
package = lib.mkDefault pkgs.qemu_test; package = lib.mkDefault pkgs.qemu_test;
options = mkIf config.testing.sshBackdoor.enable [
"-device vhost-vsock-pci,guest-cid=${toString (config.virtualisation.test.nodeNumber + 2)}"
];
}; };
}; };