diff --git a/doc/release-notes/rl-2605.section.md b/doc/release-notes/rl-2605.section.md index 610dcb5d42bb..7e8754e63483 100644 --- a/doc/release-notes/rl-2605.section.md +++ b/doc/release-notes/rl-2605.section.md @@ -238,6 +238,8 @@ - We now use the upstream wrapper script for Gradle, supporting both the `JAVA_HOME` and `GRADLE_OPTS` environment variables. +- the `autossh-ng` NixOS module was introduced as a simpler alternative to the existing `autossh` module. + - `gnuradio`: Overriding the `.pkgs` package set is now possible with a `packageOverrides` function, like with `python.pkgs` and other language-specific package sets. Example: diff --git a/nixos/modules/module-list.nix b/nixos/modules/module-list.nix index 532ce6340f05..d4e2f14853fc 100644 --- a/nixos/modules/module-list.nix +++ b/nixos/modules/module-list.nix @@ -1118,6 +1118,7 @@ ./services/networking/atalkd.nix ./services/networking/atftpd.nix ./services/networking/atticd.nix + ./services/networking/autossh-ng.nix ./services/networking/autossh.nix ./services/networking/avahi-daemon.nix ./services/networking/ax25/axlisten.nix diff --git a/nixos/modules/services/networking/autossh-ng.nix b/nixos/modules/services/networking/autossh-ng.nix new file mode 100644 index 000000000000..3eca98b2e25d --- /dev/null +++ b/nixos/modules/services/networking/autossh-ng.nix @@ -0,0 +1,135 @@ +{ + config, + lib, + pkgs, + ... +}: +let + + cfg = config.services.autossh-ng; + +in + +{ + + ###### interface + + options = { + + services.autossh-ng = { + + sessions = lib.mkOption { + type = lib.types.attrsOf ( + lib.types.submodule ( + { name, config, ... }: + { + options = { + user = lib.mkOption { + type = lib.types.str; + example = "bill"; + description = "Name of the user the local session should run as"; + }; + destination = lib.mkOption { + type = lib.types.str; + example = "billremote@socks.host.net"; + description = "Destination to connect to"; + }; + hostKeyChecking = lib.mkOption { + type = lib.types.bool; + description = '' + Whether to enable host key checking. The advantage of enabling + host key checking is that it protects against AitM attacks, on + the other hand disabling host key checking makes the autossh + connection resilient against host key rotations of the destination + machine. + ''; + }; + knownHostsFile = lib.mkOption { + type = lib.types.path; + example = "/home/bill/.ssh/known_hosts"; + description = '' + If you enabled host key checking, use this file to verify + destination host keys against. + ''; + }; + extraArguments = lib.mkOption { + type = lib.types.separatedString " "; + example = "-L2222:localhost:22 -i \${config.age.secrets.privatekey.path}"; + description = '' + Arguments to be passed to the ssh process process. + Some meaningful options include + -D (open SOCKS proxy on local port), + -R (forward remote port), + -L (forward local port), + -v (Enable debug), + -i (identity file to use). + Check ssh manual for the complete list. + ''; + }; + }; + } + ) + ); + + default = { }; + description = '' + Set of SSH sessions to start as systemd services. Each service is + named 'autossh-ng-{session.name}'. + ''; + + example = { + "socket-peer" = { + user = "bill"; + destination = "billremote@socks.host.net"; + extraArguments = "-L2222:localhost:22 -i \${config.age.secrets.privatekey.path}"; + }; + }; + + }; + }; + + }; + + ###### implementation + + config = lib.mkIf (cfg.sessions != { }) { + + systemd.services = + + lib.attrsets.mapAttrs' (name: s: { + name = "autossh-ng-${name}"; + value = { + description = "Automatic SSH session (" + name + ")"; + + after = [ "network.target" ]; + wantedBy = [ "multi-user.target" ]; + + serviceConfig = { + User = "${s.user}"; + # backoff would be nice, but doesn't automatically + # get reset on successful start yet, so static 10s restart for now: + Restart = "always"; + RestartSec = "10s"; + ExecStart = + let + hostKeyCheckOption = + if s.hostKeyChecking then + "-o \"UserKnownHostsFile=${s.knownHostsFile}\"" + else + "-o \"UserKnownHostsFile=/dev/null\" -o \"StrictHostKeyChecking=no\""; + in + '' + ${pkgs.openssh}/bin/ssh \ + -o "ServerAliveInterval 30" \ + -o "ServerAliveCountMax 3" \ + -o ExitOnForwardFailure=yes \ + ${hostKeyCheckOption} \ + -N \ + ${s.extraArguments} \ + ${s.destination} + ''; + }; + }; + }) cfg.sessions; + }; +} diff --git a/nixos/tests/nixos-rebuild-target-host-interrupted.nix b/nixos/tests/nixos-rebuild-target-host-interrupted.nix index e780019cc68d..7ddb660c3199 100644 --- a/nixos/tests/nixos-rebuild-target-host-interrupted.nix +++ b/nixos/tests/nixos-rebuild-target-host-interrupted.nix @@ -100,17 +100,12 @@ nix.settings.trusted-users = [ "@wheel" ]; - systemd.services."autossh-ng" = { - after = [ "network.target" ]; - wantedBy = [ "multi-user.target" ]; - serviceConfig = { - User = "root"; - Restart = "always"; - RestartSec = "10s"; - ExecStart = "${pkgs.openssh}/bin/ssh -o \"ServerAliveInterval 30\" -o \"ServerAliveCountMax 3\" -o ExitOnForwardFailure=yes -N -R2222:localhost:22 deployer"; - }; + services.autossh-ng.sessions.will-be-interrupted-by-rebuild = { + user = "root"; + destination = "deployer"; + extraArguments = "-R2222:localhost:22"; + hostKeyChecking = false; }; - }; in { @@ -167,6 +162,8 @@ }; # needed to make NIX_SSHOPTS work for nix-copy-closure + # 2.31.3 (current default) break, 2.32.6 and 2.33.3 (current latest) work + # let's use the default here again once the fix has made it there. nix.package = pkgs.nixVersions.latest; # We're changing the '-E' parameter to the new hostname here, @@ -174,8 +171,7 @@ # force the scenario where the connection is broken during the # deployment (because the autossh-ng service is stopped and # started): - systemd.services."autossh-ng".serviceConfig.ExecStart = - lib.mkForce "''${pkgs.openssh}/bin/ssh -o \"ServerAliveInterval 30\" -o \"ServerAliveCountMax 3\" -o ExitOnForwardFailure=yes -N -R2222:localhost:22 -E ${hostname} deployer"; + services.autossh-ng.sessions.will-be-interrupted-by-rebuild.extraArguments = "-R2222:localhost:22 -E ${hostname}"; # this will be asserted to validate the switch happened: networking.hostName = "${hostname}"; @@ -193,9 +189,8 @@ target.succeed("nixos-generate-config") target.succeed("install -Dm 600 ${nodes.target.system.build.privateKey} ~root/.ssh/id_ecdsa") - target.succeed("install ${sshConfig} ~root/.ssh/config") deployer.succeed("scp alice@target:/etc/nixos/hardware-configuration.nix /root/hardware-configuration.nix") - target.wait_for_unit("autossh-ng.service") + target.wait_for_unit("autossh-ng-will-be-interrupted-by-rebuild.service") deployer.copy_from_host("${configFile "config-1-deployed"}", "/root/configuration-1.nix") deployer.copy_from_host("${configFile "config-2-deployed"}", "/root/configuration-2.nix")