From 0fbdb0cd87a55ac26df54694386953281850d0a9 Mon Sep 17 00:00:00 2001 From: Gregor Kleen Date: Mon, 28 Sep 2026 10:12:04 +0200 Subject: ... --- accounts/gkleen@skadhi/default.nix | 2 + accounts/gkleen@skadhi/rzm/default.nix | 41 +++++++++++- home-modules/autossh-proxy.nix | 114 +++++++++++++++++++++++++++++++++ 3 files changed, 155 insertions(+), 2 deletions(-) create mode 100644 home-modules/autossh-proxy.nix diff --git a/accounts/gkleen@skadhi/default.nix b/accounts/gkleen@skadhi/default.nix index e4b35a78..1d6381a5 100644 --- a/accounts/gkleen@skadhi/default.nix +++ b/accounts/gkleen@skadhi/default.nix @@ -288,6 +288,8 @@ in { }; programs.chromium.enable = true; + + services.autosshProxy.vidhar.port = 8121; }; }; } diff --git a/accounts/gkleen@skadhi/rzm/default.nix b/accounts/gkleen@skadhi/rzm/default.nix index 11d8af8b..e2a47362 100644 --- a/accounts/gkleen@skadhi/rzm/default.nix +++ b/accounts/gkleen@skadhi/rzm/default.nix @@ -97,7 +97,7 @@ in { ''; }; - home-manager.users.gkleen = { sysConfig, config, ... }: { + home-manager.users.gkleen = { sysConfig, config, lib, ... }: { home.persistence."/persistent" = { files = [ "rz.kdbx" @@ -176,7 +176,36 @@ in { pro = "$HOME/projects/pro"; }; - programs.ssh.matchBlocks = { + programs.ssh.matchBlocks = let + autosshProxy = host: "${lib.getExe pkgs.socat} - SOCKS4A:127.0.0.1:%h:%p,socksport=${toString config.services.autosshProxy.${host}.port}"; + in { + "repo-apt01" = lib.hm.dag.entryBefore ["*.mathinst.loc"] { + user = "root"; + hostname = "repo-apt01.mathinst.loc"; + proxyCommand = autosshProxy "mgmt01"; + }; + "mgmt01" = lib.hm.dag.entryBefore ["*.mathinst.loc"] { + user = "root"; + hostname = "mgmt01.mathinst.loc"; + proxyCommand = autosshProxy "mathw0h"; + }; + "mathw0e" = lib.hm.dag.entryBefore ["*.mathinst.loc"] { + hostname = "mathw0e.mathinst.loc"; + proxyCommand = autosshProxy "mathw0h"; + }; + "cip04" = lib.hm.dag.entryBefore ["*.mathinst.loc"] { + hostname = "cip04.cipmath.loc"; + proxyCommand = autosshProxy "mathw0h"; + }; + "mathw0h" = lib.hm.dag.entryBefore ["*.mathinst.loc"] { + hostname = "mathw0h.mathinst.loc"; + proxyCommand = autosshProxy "ssh.math.lmu.de"; + }; + "math05" = lib.hm.dag.entryBefore ["*.mathinst.loc"] { + hostname = "math05.mathinst.loc"; + proxyCommand = autosshProxy "mathw0h"; + extraOptions.KexAlgorithms = "+diffie-hellman-group1-sha1"; + }; "*.mathinst.loc" = { match = "host *.mathinst.loc,*.cipmath.loc,*.math.lmu.de"; identityFile = "~/.ssh/gkleen@mathinst.loc"; @@ -191,6 +220,14 @@ in { }; }; + services.autosshProxy = { + "mgmt01" = { port = 8129; sshpassSecret = "root@mgmt01.mathinst.loc"; }; + "mathw0e" = { port = 8125; sshpassSecret = "gkleen@mathw0e.mathinst.loc"; }; + "mathw0h" = { port = 8123; sshpassSecret = "gkleen@mathw0h.mathinst.loc"; }; + "cip04" = { port = 8127; sshpassSecret = "gkleen@cip04.cipmath.loc"; }; + "ssh.math.lmu.de" = { port = 8119; sshpassSecret = "gkleen@ssh.math.lmu.de"; }; + }; + home.file = { ".cups/client.conf".text = '' ServerName cups.mathinst.loc diff --git a/home-modules/autossh-proxy.nix b/home-modules/autossh-proxy.nix new file mode 100644 index 00000000..e3179096 --- /dev/null +++ b/home-modules/autossh-proxy.nix @@ -0,0 +1,114 @@ +{ lib, sysConfig, config, pkgs, ... }: + +let + cfg = config.services.autosshProxy; +in { + options = { + services.autosshProxy = lib.mkOption { + type = lib.types.attrsOf (lib.types.submodule ({ name, config, ... }: { + options = { + port = lib.mkOption { + type = lib.types.port; + }; + + socksPort = lib.mkOption { + type = lib.types.port; + default = config.port - 1; + }; + + host = lib.mkOption { + type = lib.types.str; + default = name; + }; + + sshpassSecret = lib.mkOption { + type = lib.types.nullOr lib.types.str; + }; + }; + })); + }; + }; + + config = { + assertions = [ + { + assertion = builtins.length (lib.unique (lib.concatMap (cfg: [cfg.port cfg.socksPort]) (builtins.attrValues cfg))) == builtins.length (builtins.attrValues cfg) * 2; + message = "autosshProxy ports are not unique"; + } + ]; + + systemd.user.services = lib.mkMerge (map (cfg: { + "autossh-socks@${cfg.host}:${toString cfg.socksPort}" = { + Service = { + Type = "notify"; + NotifyAccess = "all"; + WorkingDirectory = "~"; + Restart = "always"; + RestartSec = "23s"; + ExecStart = "${pkgs.writeScript "autossh" '' + #!${lib.getExe config.programs.zsh.package} -xe + + host="''${1%:*}" + port="''${1#*:}" + + typeset -a cmd + cmd=() + + if [[ -n "''${SSHPASS_SECRET}" ]]; then + cmd+=(${lib.getExe' pkgs.sshpassSecret "sshpass-secret"}) + cmd+=("''${(@s/:/)SSHPASS_SECRET}") + cmd+=(--) + fi + + cmd+=(${lib.getExe' pkgs.openssh "ssh"} -vN -D 127.0.0.1:''${port} -o ControlPath=none -o ExitOnForwardFailure=yes -o ServerAliveCountMax=15 -o ServerAliveInterval=2 "''${host}") + + ( exec -a "''${cmd[1]}" -- ''${cmd} ) & + pid=$! + + newpid="" + i=200 + while ! { newpid=$(${lib.getExe' pkgs.iproute2 "ss"} -HO -pln "src localhost sport ''${port}" | ${lib.getExe pkgs.gnused} -r 's/^.*pid=([0-9]+).*$/\1/'); [[ -n $newpid ]] }; do + if ! kill -0 "''${pid}"; then + wait "''${pid}" + exit $? + fi + [[ "''${i}" -gt 0 ]] || exit 1 + i=$((''${i} - 1)) + ${lib.getExe' pkgs.coreutils "sleep"} 0.1 + done + + ${lib.getExe' sysConfig.systemd.package "systemd-notify"} --pid=''${newpid} --ready + ''} \"%I\""; + Environment = lib.optional (cfg.sshpassSecret != null) "SSHPASS_SECRET=${cfg.sshpassSecret}"; + }; + Unit = { + StopWhenUnneeded = true; + StartLimitInterval = "180s"; + StartLimitBurst = 7; + }; + }; + "proxy-to-autossh-socks@${toString cfg.port}" = { + Unit = { + BindsTo = ["autossh-socks@${cfg.host}:${toString cfg.socksPort}.service" "proxy-to-autossh-socks@${toString cfg.port}.socket"]; + After = ["autossh-socks@${cfg.host}:${toString cfg.socksPort}.service" "proxy-to-autossh-socks@${toString cfg.port}.socket"]; + }; + Service = { + ExecStart = "${sysConfig.systemd.package}/lib/systemd/systemd-socket-proxyd --exit-idle-time=60s 127.0.0.1:${toString cfg.socksPort}"; + Restart = "always"; + RestartSec = "23s"; + }; + }; + }) (builtins.attrValues cfg)); + systemd.user.sockets = builtins.listToAttrs (map (cfg: lib.nameValuePair "proxy-to-autossh-socks@${toString cfg.port}" { + Socket = { + ListenStream = "%I"; + TriggerLimitIntervalSec = 0; + PollLimitIntervalSec = "180s"; + PollLimitBurst = 6; + }; + Install = { + WantedBy = ["sockets.target"]; + }; + }) (builtins.attrValues cfg)); + }; +} -- cgit v1.2.3