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