Kieran's opinionated (and probably slightly dumb) nix config
at main 5.3 kB view raw
1{ 2 config, 3 lib, 4 pkgs, 5 inputs, 6 ... 7}: 8with lib; 9let 10 cfg = config.atelier.ssh; 11in 12{ 13 options.atelier.ssh = { 14 enable = mkEnableOption "SSH configuration"; 15 16 zmx = { 17 enable = mkEnableOption "zmx integration for persistent sessions"; 18 hosts = mkOption { 19 type = types.listOf types.str; 20 default = [ ]; 21 description = "List of host patterns to enable zmx auto-attach (e.g., 'd.*')"; 22 }; 23 }; 24 25 extraConfig = mkOption { 26 type = types.lines; 27 default = ""; 28 description = "Extra SSH configuration"; 29 }; 30 31 hosts = mkOption { 32 type = types.attrsOf ( 33 types.submodule { 34 options = { 35 hostname = mkOption { 36 type = types.nullOr types.str; 37 default = null; 38 description = "Hostname or IP address"; 39 }; 40 41 port = mkOption { 42 type = types.nullOr types.int; 43 default = null; 44 description = "SSH port"; 45 }; 46 47 user = mkOption { 48 type = types.nullOr types.str; 49 default = null; 50 description = "Username for SSH connection"; 51 }; 52 53 identityFile = mkOption { 54 type = types.nullOr types.str; 55 default = null; 56 description = "Path to SSH identity file"; 57 }; 58 59 forwardAgent = mkOption { 60 type = types.nullOr types.bool; 61 default = null; 62 description = "Enable SSH agent forwarding"; 63 }; 64 65 extraOptions = mkOption { 66 type = types.attrsOf types.str; 67 default = { }; 68 description = "Additional SSH options for this host"; 69 }; 70 71 zmx = mkOption { 72 type = types.bool; 73 default = false; 74 description = "Enable zmx persistent sessions for this host"; 75 }; 76 }; 77 } 78 ); 79 default = { }; 80 description = "SSH host configurations"; 81 }; 82 }; 83 84 config = mkIf cfg.enable { 85 # zmx provides pre-built binaries that we download instead of building from source 86 # This avoids the zig2nix dependency which causes issues in CI 87 home.packages = 88 (optionals cfg.zmx.enable [ 89 pkgs.zmx-binary 90 pkgs.autossh 91 ]); 92 93 programs.ssh = { 94 enable = true; 95 enableDefaultConfig = false; 96 97 matchBlocks = 98 let 99 # Convert atelier.ssh.hosts to SSH matchBlocks 100 hostConfigs = mapAttrs ( 101 name: hostCfg: 102 { 103 hostname = mkIf (hostCfg.hostname != null) hostCfg.hostname; 104 port = mkIf (hostCfg.port != null) hostCfg.port; 105 user = mkIf (hostCfg.user != null) hostCfg.user; 106 identityFile = mkIf (hostCfg.identityFile != null) hostCfg.identityFile; 107 forwardAgent = mkIf (hostCfg.forwardAgent != null) hostCfg.forwardAgent; 108 extraOptions = hostCfg.extraOptions // ( 109 if hostCfg.zmx then 110 { 111 RemoteCommand = "export PATH=$HOME/.nix-profile/bin:$PATH; zmx attach %n"; 112 RequestTTY = "yes"; 113 ControlPath = "~/.ssh/cm-%r@%h:%p"; 114 ControlMaster = "auto"; 115 ControlPersist = "10m"; 116 } 117 else 118 { } 119 ); 120 } 121 ) cfg.hosts; 122 123 # Create zmx pattern hosts if enabled 124 zmxPatternHosts = if cfg.zmx.enable then 125 listToAttrs ( 126 map (pattern: 127 let 128 patternHost = cfg.hosts.${pattern} or {}; 129 in { 130 name = pattern; 131 value = { 132 hostname = mkIf (patternHost.hostname or null != null) patternHost.hostname; 133 port = mkIf (patternHost.port or null != null) patternHost.port; 134 user = mkIf (patternHost.user or null != null) patternHost.user; 135 extraOptions = { 136 RemoteCommand = "export PATH=$HOME/.nix-profile/bin:$PATH; zmx attach %k"; 137 RequestTTY = "yes"; 138 ControlPath = "~/.ssh/cm-%r@%h:%p"; 139 ControlMaster = "auto"; 140 ControlPersist = "10m"; 141 }; 142 }; 143 }) cfg.zmx.hosts 144 ) 145 else 146 { }; 147 148 # Default match block for extraConfig 149 defaultBlock = if cfg.extraConfig != "" then 150 { 151 "*" = { }; 152 } 153 else 154 { }; 155 in 156 defaultBlock // hostConfigs // zmxPatternHosts; 157 158 extraConfig = cfg.extraConfig; 159 }; 160 161 # Add shell aliases for easier zmx usage 162 programs.zsh.shellAliases = mkIf cfg.zmx.enable { 163 zmls = "zmx list"; 164 zmk = "zmx kill"; 165 zma = "zmx attach"; 166 ash = "autossh -M 0 -q"; 167 }; 168 169 programs.bash.shellAliases = mkIf cfg.zmx.enable { 170 zmls = "zmx list"; 171 zmk = "zmx kill"; 172 zma = "zmx attach"; 173 ash = "autossh -M 0 -q"; 174 }; 175 176 programs.fish.shellAliases = mkIf cfg.zmx.enable { 177 zmls = "zmx list"; 178 zmk = "zmx kill"; 179 zma = "zmx attach"; 180 ash = "autossh -M 0 -q"; 181 }; 182 }; 183}