Move all of NixOS to nixos/ in preparation of the repository merge
This commit is contained in:
@@ -0,0 +1,175 @@
|
||||
{ config, pkgs, ... }:
|
||||
|
||||
with pkgs.lib;
|
||||
|
||||
let
|
||||
|
||||
inherit (pkgs) lsh;
|
||||
|
||||
cfg = config.services.lshd;
|
||||
|
||||
in
|
||||
|
||||
{
|
||||
|
||||
###### interface
|
||||
|
||||
options = {
|
||||
|
||||
services.lshd = {
|
||||
|
||||
enable = mkOption {
|
||||
default = false;
|
||||
description = ''
|
||||
Whether to enable the GNU lshd SSH2 daemon, which allows
|
||||
secure remote login.
|
||||
'';
|
||||
};
|
||||
|
||||
portNumber = mkOption {
|
||||
default = 22;
|
||||
description = ''
|
||||
The port on which to listen for connections.
|
||||
'';
|
||||
};
|
||||
|
||||
interfaces = mkOption {
|
||||
default = [];
|
||||
description = ''
|
||||
List of network interfaces where listening for connections.
|
||||
When providing the empty list, `[]', lshd listens on all
|
||||
network interfaces.
|
||||
'';
|
||||
example = [ "localhost" "1.2.3.4:443" ];
|
||||
};
|
||||
|
||||
hostKey = mkOption {
|
||||
default = "/etc/lsh/host-key";
|
||||
description = ''
|
||||
Path to the server's private key. Note that this key must
|
||||
have been created, e.g., using "lsh-keygen --server |
|
||||
lsh-writekey --server", so that you can run lshd.
|
||||
'';
|
||||
};
|
||||
|
||||
syslog = mkOption {
|
||||
default = true;
|
||||
description = ''Whether to enable syslog output.'';
|
||||
};
|
||||
|
||||
passwordAuthentication = mkOption {
|
||||
default = true;
|
||||
description = ''Whether to enable password authentication.'';
|
||||
};
|
||||
|
||||
publicKeyAuthentication = mkOption {
|
||||
default = true;
|
||||
description = ''Whether to enable public key authentication.'';
|
||||
};
|
||||
|
||||
rootLogin = mkOption {
|
||||
default = false;
|
||||
description = ''Whether to enable remote root login.'';
|
||||
};
|
||||
|
||||
loginShell = mkOption {
|
||||
default = null;
|
||||
description = ''
|
||||
If non-null, override the default login shell with the
|
||||
specified value.
|
||||
'';
|
||||
example = "/nix/store/xyz-bash-10.0/bin/bash10";
|
||||
};
|
||||
|
||||
srpKeyExchange = mkOption {
|
||||
default = false;
|
||||
description = ''
|
||||
Whether to enable SRP key exchange and user authentication.
|
||||
'';
|
||||
};
|
||||
|
||||
tcpForwarding = mkOption {
|
||||
default = true;
|
||||
description = ''Whether to enable TCP/IP forwarding.'';
|
||||
};
|
||||
|
||||
x11Forwarding = mkOption {
|
||||
default = true;
|
||||
description = ''Whether to enable X11 forwarding.'';
|
||||
};
|
||||
|
||||
subsystems = mkOption {
|
||||
default = [ ["sftp" "${pkgs.lsh}/sbin/sftp-server"] ];
|
||||
description = ''
|
||||
List of subsystem-path pairs, where the head of the pair
|
||||
denotes the subsystem name, and the tail denotes the path to
|
||||
an executable implementing it.
|
||||
'';
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
|
||||
###### implementation
|
||||
|
||||
config = mkIf cfg.enable {
|
||||
|
||||
jobs.lshd =
|
||||
{ description = "GNU lshd SSH2 daemon";
|
||||
|
||||
startOn = "started network-interfaces";
|
||||
stopOn = "stopping network-interfaces";
|
||||
|
||||
environment =
|
||||
{ LD_LIBRARY_PATH = config.system.nssModules.path; };
|
||||
|
||||
preStart =
|
||||
''
|
||||
test -d /etc/lsh || mkdir -m 0755 -p /etc/lsh
|
||||
test -d /var/spool/lsh || mkdir -m 0755 -p /var/spool/lsh
|
||||
|
||||
if ! test -f /var/spool/lsh/yarrow-seed-file
|
||||
then
|
||||
# XXX: It would be nice to provide feedback to the
|
||||
# user when this fails, so that they can retry it
|
||||
# manually.
|
||||
${lsh}/bin/lsh-make-seed --sloppy \
|
||||
-o /var/spool/lsh/yarrow-seed-file
|
||||
fi
|
||||
|
||||
if ! test -f "${cfg.hostKey}"
|
||||
then
|
||||
${lsh}/bin/lsh-keygen --server | \
|
||||
${lsh}/bin/lsh-writekey --server -o "${cfg.hostKey}"
|
||||
fi
|
||||
'';
|
||||
|
||||
exec = with cfg;
|
||||
''
|
||||
${lsh}/sbin/lshd --daemonic \
|
||||
--password-helper="${lsh}/sbin/lsh-pam-checkpw" \
|
||||
-p ${toString portNumber} \
|
||||
${if interfaces == [] then ""
|
||||
else (concatStrings (map (i: "--interface=\"${i}\"")
|
||||
interfaces))} \
|
||||
-h "${hostKey}" \
|
||||
${if !syslog then "--no-syslog" else ""} \
|
||||
${if passwordAuthentication then "--password" else "--no-password" } \
|
||||
${if publicKeyAuthentication then "--publickey" else "--no-publickey" } \
|
||||
${if rootLogin then "--root-login" else "--no-root-login" } \
|
||||
${if loginShell != null then "--login-shell=\"${loginShell}\"" else "" } \
|
||||
${if srpKeyExchange then "--srp-keyexchange" else "--no-srp-keyexchange" } \
|
||||
${if !tcpForwarding then "--no-tcpip-forward" else "--tcpip-forward"} \
|
||||
${if x11Forwarding then "--x11-forward" else "--no-x11-forward" } \
|
||||
--subsystems=${concatStringsSep ","
|
||||
(map (pair: (head pair) + "=" +
|
||||
(head (tail pair)))
|
||||
subsystems)}
|
||||
'';
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
@@ -0,0 +1,338 @@
|
||||
{ config, pkgs, ... }:
|
||||
|
||||
with pkgs.lib;
|
||||
|
||||
let
|
||||
|
||||
cfg = config.services.openssh;
|
||||
cfgc = config.programs.ssh;
|
||||
|
||||
nssModulesPath = config.system.nssModules.path;
|
||||
|
||||
permitRootLoginCheck = v:
|
||||
v == "yes" ||
|
||||
v == "without-password" ||
|
||||
v == "forced-commands-only" ||
|
||||
v == "no";
|
||||
|
||||
knownHosts = map (h: getAttr h cfg.knownHosts) (attrNames cfg.knownHosts);
|
||||
|
||||
knownHostsFile = pkgs.writeText "ssh_known_hosts" (
|
||||
flip concatMapStrings knownHosts (h:
|
||||
"${concatStringsSep "," h.hostNames} ${builtins.readFile h.publicKeyFile}"
|
||||
)
|
||||
);
|
||||
|
||||
userOptions = {
|
||||
|
||||
openssh.authorizedKeys = {
|
||||
keys = mkOption {
|
||||
type = types.listOf types.string;
|
||||
default = [];
|
||||
description = ''
|
||||
A list of verbatim OpenSSH public keys that should be added to the
|
||||
user's authorized keys. The keys are added to a file that the SSH
|
||||
daemon reads in addition to the the user's authorized_keys file.
|
||||
You can combine the <literal>keys</literal> and
|
||||
<literal>keyFiles</literal> options.
|
||||
'';
|
||||
};
|
||||
|
||||
keyFiles = mkOption {
|
||||
default = [];
|
||||
description = ''
|
||||
A list of files each containing one OpenSSH public key that should be
|
||||
added to the user's authorized keys. The contents of the files are
|
||||
read at build time and added to a file that the SSH daemon reads in
|
||||
addition to the the user's authorized_keys file. You can combine the
|
||||
<literal>keyFiles</literal> and <literal>keys</literal> options.
|
||||
'';
|
||||
};
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
authKeysFiles = let
|
||||
mkAuthKeyFile = u: {
|
||||
target = "ssh/authorized_keys.d/${u.name}";
|
||||
mode = "0444";
|
||||
source = pkgs.writeText "${u.name}-authorized_keys" ''
|
||||
${concatStringsSep "\n" u.openssh.authorizedKeys.keys}
|
||||
${concatMapStrings (f: builtins.readFile f + "\n") u.openssh.authorizedKeys.keyFiles}
|
||||
'';
|
||||
};
|
||||
usersWithKeys = attrValues (flip filterAttrs config.users.extraUsers (n: u:
|
||||
length u.openssh.authorizedKeys.keys != 0 || length u.openssh.authorizedKeys.keyFiles != 0
|
||||
));
|
||||
in map mkAuthKeyFile usersWithKeys;
|
||||
|
||||
in
|
||||
|
||||
{
|
||||
|
||||
###### interface
|
||||
|
||||
options = {
|
||||
|
||||
services.openssh = {
|
||||
|
||||
enable = mkOption {
|
||||
default = false;
|
||||
description = ''
|
||||
Whether to enable the OpenSSH secure shell daemon, which
|
||||
allows secure remote logins.
|
||||
'';
|
||||
};
|
||||
|
||||
forwardX11 = mkOption {
|
||||
default = cfgc.setXAuthLocation;
|
||||
description = ''
|
||||
Whether to allow X11 connections to be forwarded.
|
||||
'';
|
||||
};
|
||||
|
||||
allowSFTP = mkOption {
|
||||
default = true;
|
||||
description = ''
|
||||
Whether to enable the SFTP subsystem in the SSH daemon. This
|
||||
enables the use of commands such as <command>sftp</command> and
|
||||
<command>sshfs</command>.
|
||||
'';
|
||||
};
|
||||
|
||||
permitRootLogin = mkOption {
|
||||
default = "without-password";
|
||||
check = permitRootLoginCheck;
|
||||
description = ''
|
||||
Whether the root user can login using ssh. Valid values are
|
||||
<literal>yes</literal>, <literal>without-password</literal>,
|
||||
<literal>forced-commands-only</literal> or
|
||||
<literal>no</literal>.
|
||||
'';
|
||||
};
|
||||
|
||||
gatewayPorts = mkOption {
|
||||
default = "no";
|
||||
description = ''
|
||||
Specifies whether remote hosts are allowed to connect to
|
||||
ports forwarded for the client. See
|
||||
<citerefentry><refentrytitle>sshd_config</refentrytitle>
|
||||
<manvolnum>5</manvolnum></citerefentry>.
|
||||
'';
|
||||
};
|
||||
|
||||
ports = mkOption {
|
||||
default = [22];
|
||||
description = ''
|
||||
Specifies on which ports the SSH daemon listens.
|
||||
'';
|
||||
};
|
||||
|
||||
usePAM = mkOption {
|
||||
default = true;
|
||||
description = ''
|
||||
Specifies whether the OpenSSH daemon uses PAM to authenticate
|
||||
login attempts.
|
||||
'';
|
||||
};
|
||||
|
||||
passwordAuthentication = mkOption {
|
||||
default = true;
|
||||
description = ''
|
||||
Specifies whether password authentication is allowed. Note
|
||||
that setting this value to <literal>false</literal> is most
|
||||
probably not going to have the desired effect unless
|
||||
<literal>usePAM</literal> is disabled as well.
|
||||
'';
|
||||
};
|
||||
|
||||
challengeResponseAuthentication = mkOption {
|
||||
default = true;
|
||||
description = ''
|
||||
Specifies whether challenge/response authentication is allowed.
|
||||
'';
|
||||
};
|
||||
|
||||
hostKeys = mkOption {
|
||||
default =
|
||||
[ { path = "/etc/ssh/ssh_host_dsa_key";
|
||||
type = "dsa";
|
||||
bits = 1024;
|
||||
}
|
||||
{ path = "/etc/ssh/ssh_host_ecdsa_key";
|
||||
type = "ecdsa";
|
||||
bits = 521;
|
||||
}
|
||||
];
|
||||
description = ''
|
||||
NixOS can automatically generate SSH host keys. This option
|
||||
specifies the path, type and size of each key. See
|
||||
<citerefentry><refentrytitle>ssh-keygen</refentrytitle>
|
||||
<manvolnum>1</manvolnum></citerefentry> for supported types
|
||||
and sizes.
|
||||
'';
|
||||
};
|
||||
|
||||
authorizedKeysFiles = mkOption {
|
||||
default = [];
|
||||
description = "Files from with authorized keys are read.";
|
||||
};
|
||||
|
||||
extraConfig = mkOption {
|
||||
default = "";
|
||||
description = "Verbatim contents of <filename>sshd_config</filename>.";
|
||||
};
|
||||
|
||||
knownHosts = mkOption {
|
||||
default = {};
|
||||
type = types.loaOf types.optionSet;
|
||||
description = ''
|
||||
The set of system-wide known SSH hosts.
|
||||
'';
|
||||
example = [
|
||||
{
|
||||
hostNames = [ "myhost" "myhost.mydomain.com" "10.10.1.4" ];
|
||||
publicKeyFile = ./pubkeys/myhost_ssh_host_dsa_key.pub;
|
||||
}
|
||||
{
|
||||
hostNames = [ "myhost2" ];
|
||||
publicKeyFile = ./pubkeys/myhost2_ssh_host_dsa_key.pub;
|
||||
}
|
||||
];
|
||||
options = {
|
||||
hostNames = mkOption {
|
||||
type = types.listOf types.string;
|
||||
default = [];
|
||||
description = ''
|
||||
A list of host names and/or IP numbers used for accessing
|
||||
the host's ssh service.
|
||||
'';
|
||||
};
|
||||
publicKeyFile = mkOption {
|
||||
description = ''
|
||||
The path to the public key file for the host. The public
|
||||
key file is read at build time and saved in the Nix store.
|
||||
You can fetch a public key file from a running SSH server
|
||||
with the <literal>ssh-keyscan</literal> command.
|
||||
'';
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
users.extraUsers = mkOption {
|
||||
options = [ userOptions ];
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
|
||||
###### implementation
|
||||
|
||||
config = mkIf cfg.enable {
|
||||
|
||||
users.extraUsers = singleton
|
||||
{ name = "sshd";
|
||||
uid = config.ids.uids.sshd;
|
||||
description = "SSH privilege separation user";
|
||||
home = "/var/empty";
|
||||
};
|
||||
|
||||
environment.etc = authKeysFiles ++ [
|
||||
{ source = "${pkgs.openssh}/etc/ssh/moduli";
|
||||
target = "ssh/moduli";
|
||||
}
|
||||
{ source = knownHostsFile;
|
||||
target = "ssh/ssh_known_hosts";
|
||||
}
|
||||
];
|
||||
|
||||
systemd.services.sshd =
|
||||
{ description = "SSH Daemon";
|
||||
|
||||
wantedBy = [ "multi-user.target" ];
|
||||
|
||||
stopIfChanged = false;
|
||||
|
||||
path = [ pkgs.openssh pkgs.gawk ];
|
||||
|
||||
environment.LD_LIBRARY_PATH = nssModulesPath;
|
||||
environment.LOCALE_ARCHIVE = "/run/current-system/sw/lib/locale/locale-archive";
|
||||
|
||||
preStart =
|
||||
''
|
||||
mkdir -m 0755 -p /etc/ssh
|
||||
|
||||
${flip concatMapStrings cfg.hostKeys (k: ''
|
||||
if ! [ -f "${k.path}" ]; then
|
||||
ssh-keygen -t "${k.type}" -b "${toString k.bits}" -f "${k.path}" -N ""
|
||||
fi
|
||||
'')}
|
||||
'';
|
||||
|
||||
serviceConfig =
|
||||
{ ExecStart =
|
||||
"${pkgs.openssh}/sbin/sshd " +
|
||||
"-f ${pkgs.writeText "sshd_config" cfg.extraConfig}";
|
||||
Restart = "always";
|
||||
Type = "forking";
|
||||
KillMode = "process";
|
||||
PIDFile = "/run/sshd.pid";
|
||||
};
|
||||
};
|
||||
|
||||
networking.firewall.allowedTCPPorts = cfg.ports;
|
||||
|
||||
security.pam.services = optional cfg.usePAM { name = "sshd"; startSession = true; showMotd = true; };
|
||||
|
||||
services.openssh.authorizedKeysFiles =
|
||||
[ ".ssh/authorized_keys" ".ssh/authorized_keys2" "/etc/ssh/authorized_keys.d/%u" ];
|
||||
|
||||
services.openssh.extraConfig =
|
||||
''
|
||||
PidFile /run/sshd.pid
|
||||
|
||||
Protocol 2
|
||||
|
||||
UsePAM ${if cfg.usePAM then "yes" else "no"}
|
||||
|
||||
AddressFamily ${if config.networking.enableIPv6 then "any" else "inet"}
|
||||
${concatMapStrings (port: ''
|
||||
Port ${toString port}
|
||||
'') cfg.ports}
|
||||
|
||||
${optionalString cfgc.setXAuthLocation ''
|
||||
XAuthLocation ${pkgs.xorg.xauth}/bin/xauth
|
||||
''}
|
||||
|
||||
${if cfg.forwardX11 then ''
|
||||
X11Forwarding yes
|
||||
'' else ''
|
||||
X11Forwarding no
|
||||
''}
|
||||
|
||||
${optionalString cfg.allowSFTP ''
|
||||
Subsystem sftp ${pkgs.openssh}/libexec/sftp-server
|
||||
''}
|
||||
|
||||
PermitRootLogin ${cfg.permitRootLogin}
|
||||
GatewayPorts ${cfg.gatewayPorts}
|
||||
PasswordAuthentication ${if cfg.passwordAuthentication then "yes" else "no"}
|
||||
ChallengeResponseAuthentication ${if cfg.challengeResponseAuthentication then "yes" else "no"}
|
||||
|
||||
PrintMotd no # handled by pam_motd
|
||||
|
||||
AuthorizedKeysFile ${toString cfg.authorizedKeysFiles}
|
||||
|
||||
${flip concatMapStrings cfg.hostKeys (k: ''
|
||||
HostKey ${k.path}
|
||||
'')}
|
||||
'';
|
||||
|
||||
assertions = [{ assertion = if cfg.forwardX11 then cfgc.setXAuthLocation else true;
|
||||
message = "cannot enable X11 forwarding without setting xauth location";}];
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user