1# Global configuration for the SSH client.
2
3{ config, lib, pkgs, ... }:
4
5with lib;
6
7let
8
9 cfg = config.programs.ssh;
10 cfgd = config.services.openssh;
11
12 askPassword = cfg.askPassword;
13
14 askPasswordWrapper = pkgs.writeScript "ssh-askpass-wrapper"
15 ''
16 #! ${pkgs.stdenv.shell} -e
17 export DISPLAY="$(systemctl --user show-environment | ${pkgs.gnused}/bin/sed 's/^DISPLAY=\(.*\)/\1/; t; d')"
18 exec ${askPassword}
19 '';
20
21in
22{
23 ###### interface
24
25 options = {
26
27 programs.ssh = {
28
29 askPassword = mkOption {
30 type = types.str;
31 default = "${pkgs.x11_ssh_askpass}/libexec/x11-ssh-askpass";
32 description = ''Program used by SSH to ask for passwords.'';
33 };
34
35 forwardX11 = mkOption {
36 type = types.bool;
37 default = false;
38 description = ''
39 Whether to request X11 forwarding on outgoing connections by default.
40 This is useful for running graphical programs on the remote machine and have them display to your local X11 server.
41 Historically, this value has depended on the value used by the local sshd daemon, but there really isn't a relation between the two.
42 Note: there are some security risks to forwarding an X11 connection.
43 NixOS's X server is built with the SECURITY extension, which prevents some obvious attacks.
44 To enable or disable forwarding on a per-connection basis, see the -X and -x options to ssh.
45 The -Y option to ssh enables trusted forwarding, which bypasses the SECURITY extension.
46 '';
47 };
48
49 setXAuthLocation = mkOption {
50 type = types.bool;
51 default = config.services.xserver.enable;
52 description = ''
53 Whether to set the path to <command>xauth</command> for X11-forwarded connections.
54 This causes a dependency on X11 packages.
55 '';
56 };
57
58 extraConfig = mkOption {
59 type = types.lines;
60 default = "";
61 description = ''
62 Extra configuration text appended to <filename>ssh_config</filename>.
63 See <citerefentry><refentrytitle>ssh_config</refentrytitle><manvolnum>5</manvolnum></citerefentry>
64 for help.
65 '';
66 };
67
68 startAgent = mkOption {
69 type = types.bool;
70 default = true;
71 description = ''
72 Whether to start the OpenSSH agent when you log in. The OpenSSH agent
73 remembers private keys for you so that you don't have to type in
74 passphrases every time you make an SSH connection. Use
75 <command>ssh-add</command> to add a key to the agent.
76 '';
77 };
78
79 agentTimeout = mkOption {
80 type = types.nullOr types.str;
81 default = null;
82 example = "1h";
83 description = ''
84 How long to keep the private keys in memory. Use null to keep them forever.
85 '';
86 };
87
88 package = mkOption {
89 default = pkgs.openssh;
90 description = ''
91 The package used for the openssh client and daemon.
92 '';
93 };
94
95 };
96
97 };
98
99 config = {
100
101 assertions = singleton
102 { assertion = cfg.forwardX11 -> cfg.setXAuthLocation;
103 message = "cannot enable X11 forwarding without setting XAuth location";
104 };
105
106 # SSH configuration. Slight duplication of the sshd_config
107 # generation in the sshd service.
108 environment.etc."ssh/ssh_config".text =
109 ''
110 AddressFamily ${if config.networking.enableIPv6 then "any" else "inet"}
111
112 ${optionalString cfg.setXAuthLocation ''
113 XAuthLocation ${pkgs.xorg.xauth}/bin/xauth
114 ''}
115
116 ForwardX11 ${if cfg.forwardX11 then "yes" else "no"}
117
118 ${cfg.extraConfig}
119 '';
120
121 # FIXME: this should really be socket-activated for über-awesomeness.
122 systemd.user.services.ssh-agent =
123 { enable = cfg.startAgent;
124 description = "SSH Agent";
125 wantedBy = [ "default.target" ];
126 serviceConfig =
127 { ExecStartPre = "${pkgs.coreutils}/bin/rm -f %t/ssh-agent";
128 ExecStart =
129 "${cfg.package}/bin/ssh-agent " +
130 optionalString (cfg.agentTimeout != null) ("-t ${cfg.agentTimeout} ") +
131 "-a %t/ssh-agent";
132 StandardOutput = "null";
133 Type = "forking";
134 Restart = "on-failure";
135 SuccessExitStatus = "0 2";
136 };
137 # Allow ssh-agent to ask for confirmation. This requires the
138 # unit to know about the user's $DISPLAY (via ‘systemctl
139 # import-environment’).
140 environment.SSH_ASKPASS = optionalString config.services.xserver.enable askPasswordWrapper;
141 environment.DISPLAY = "fake"; # required to make ssh-agent start $SSH_ASKPASS
142 };
143
144 environment.extraInit = optionalString cfg.startAgent
145 ''
146 if [ -z "$SSH_AUTH_SOCK" -a -n "$XDG_RUNTIME_DIR" ]; then
147 export SSH_AUTH_SOCK="$XDG_RUNTIME_DIR/ssh-agent"
148 fi
149 '';
150
151 environment.interactiveShellInit = optionalString config.services.xserver.enable
152 ''
153 export SSH_ASKPASS=${askPassword}
154 '';
155
156 };
157}