uboot: (firmwareOdroidC2/C4) don't invoke patch tool, use patches = [] instead
https://github.com/NixOS/nixpkgs/blob/master/pkgs/stdenv/generic/setup.sh#L948 this can do it nicely. Signed-off-by: Anton Arapov <anton@deadbeef.mx>
This commit is contained in:
commit
56de2bcd43
30691 changed files with 3076956 additions and 0 deletions
573
nixos/modules/services/networking/ssh/sshd.nix
Normal file
573
nixos/modules/services/networking/ssh/sshd.nix
Normal file
|
|
@ -0,0 +1,573 @@
|
|||
{ config, lib, pkgs, ... }:
|
||||
|
||||
with lib;
|
||||
|
||||
let
|
||||
|
||||
# The splicing information needed for nativeBuildInputs isn't available
|
||||
# on the derivations likely to be used as `cfgc.package`.
|
||||
# This middle-ground solution ensures *an* sshd can do their basic validation
|
||||
# on the configuration.
|
||||
validationPackage = if pkgs.stdenv.buildPlatform == pkgs.stdenv.hostPlatform
|
||||
then cfgc.package
|
||||
else pkgs.buildPackages.openssh;
|
||||
|
||||
sshconf = pkgs.runCommand "sshd.conf-validated" { nativeBuildInputs = [ validationPackage ]; } ''
|
||||
cat >$out <<EOL
|
||||
${cfg.extraConfig}
|
||||
EOL
|
||||
|
||||
ssh-keygen -q -f mock-hostkey -N ""
|
||||
sshd -t -f $out -h mock-hostkey
|
||||
'';
|
||||
|
||||
cfg = config.services.openssh;
|
||||
cfgc = config.programs.ssh;
|
||||
|
||||
nssModulesPath = config.system.nssModules.path;
|
||||
|
||||
userOptions = {
|
||||
|
||||
options.openssh.authorizedKeys = {
|
||||
keys = mkOption {
|
||||
type = types.listOf types.singleLineStr;
|
||||
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.
|
||||
Warning: If you are using <literal>NixOps</literal> then don't use this
|
||||
option since it will replace the key required for deployment via ssh.
|
||||
'';
|
||||
example = [
|
||||
"ssh-rsa AAAAB3NzaC1yc2etc/etc/etcjwrsh8e596z6J0l7 example@host"
|
||||
"ssh-ed25519 AAAAC3NzaCetcetera/etceteraJZMfk3QPfQ foo@bar"
|
||||
];
|
||||
};
|
||||
|
||||
keyFiles = mkOption {
|
||||
type = types.listOf types.path;
|
||||
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: nameValuePair "ssh/authorized_keys.d/${u.name}" {
|
||||
mode = "0444";
|
||||
source = pkgs.writeText "${u.name}-authorized_keys" ''
|
||||
${concatStringsSep "\n" u.openssh.authorizedKeys.keys}
|
||||
${concatMapStrings (f: readFile f + "\n") u.openssh.authorizedKeys.keyFiles}
|
||||
'';
|
||||
};
|
||||
usersWithKeys = attrValues (flip filterAttrs config.users.users (n: u:
|
||||
length u.openssh.authorizedKeys.keys != 0 || length u.openssh.authorizedKeys.keyFiles != 0
|
||||
));
|
||||
in listToAttrs (map mkAuthKeyFile usersWithKeys);
|
||||
|
||||
in
|
||||
|
||||
{
|
||||
imports = [
|
||||
(mkAliasOptionModule [ "services" "sshd" "enable" ] [ "services" "openssh" "enable" ])
|
||||
(mkAliasOptionModule [ "services" "openssh" "knownHosts" ] [ "programs" "ssh" "knownHosts" ])
|
||||
(mkRenamedOptionModule [ "services" "openssh" "challengeResponseAuthentication" ] [ "services" "openssh" "kbdInteractiveAuthentication" ])
|
||||
];
|
||||
|
||||
###### interface
|
||||
|
||||
options = {
|
||||
|
||||
services.openssh = {
|
||||
|
||||
enable = mkOption {
|
||||
type = types.bool;
|
||||
default = false;
|
||||
description = ''
|
||||
Whether to enable the OpenSSH secure shell daemon, which
|
||||
allows secure remote logins.
|
||||
'';
|
||||
};
|
||||
|
||||
startWhenNeeded = mkOption {
|
||||
type = types.bool;
|
||||
default = false;
|
||||
description = ''
|
||||
If set, <command>sshd</command> is socket-activated; that
|
||||
is, instead of having it permanently running as a daemon,
|
||||
systemd will start an instance for each incoming connection.
|
||||
'';
|
||||
};
|
||||
|
||||
forwardX11 = mkOption {
|
||||
type = types.bool;
|
||||
default = false;
|
||||
description = ''
|
||||
Whether to allow X11 connections to be forwarded.
|
||||
'';
|
||||
};
|
||||
|
||||
allowSFTP = mkOption {
|
||||
type = types.bool;
|
||||
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>.
|
||||
'';
|
||||
};
|
||||
|
||||
sftpServerExecutable = mkOption {
|
||||
type = types.str;
|
||||
example = "internal-sftp";
|
||||
description = ''
|
||||
The sftp server executable. Can be a path or "internal-sftp" to use
|
||||
the sftp server built into the sshd binary.
|
||||
'';
|
||||
};
|
||||
|
||||
sftpFlags = mkOption {
|
||||
type = with types; listOf str;
|
||||
default = [];
|
||||
example = [ "-f AUTHPRIV" "-l INFO" ];
|
||||
description = ''
|
||||
Commandline flags to add to sftp-server.
|
||||
'';
|
||||
};
|
||||
|
||||
permitRootLogin = mkOption {
|
||||
default = "prohibit-password";
|
||||
type = types.enum ["yes" "without-password" "prohibit-password" "forced-commands-only" "no"];
|
||||
description = ''
|
||||
Whether the root user can login using ssh.
|
||||
'';
|
||||
};
|
||||
|
||||
gatewayPorts = mkOption {
|
||||
type = types.str;
|
||||
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 {
|
||||
type = types.listOf types.port;
|
||||
default = [22];
|
||||
description = ''
|
||||
Specifies on which ports the SSH daemon listens.
|
||||
'';
|
||||
};
|
||||
|
||||
openFirewall = mkOption {
|
||||
type = types.bool;
|
||||
default = true;
|
||||
description = ''
|
||||
Whether to automatically open the specified ports in the firewall.
|
||||
'';
|
||||
};
|
||||
|
||||
listenAddresses = mkOption {
|
||||
type = with types; listOf (submodule {
|
||||
options = {
|
||||
addr = mkOption {
|
||||
type = types.nullOr types.str;
|
||||
default = null;
|
||||
description = ''
|
||||
Host, IPv4 or IPv6 address to listen to.
|
||||
'';
|
||||
};
|
||||
port = mkOption {
|
||||
type = types.nullOr types.int;
|
||||
default = null;
|
||||
description = ''
|
||||
Port to listen to.
|
||||
'';
|
||||
};
|
||||
};
|
||||
});
|
||||
default = [];
|
||||
example = [ { addr = "192.168.3.1"; port = 22; } { addr = "0.0.0.0"; port = 64022; } ];
|
||||
description = ''
|
||||
List of addresses and ports to listen on (ListenAddress directive
|
||||
in config). If port is not specified for address sshd will listen
|
||||
on all ports specified by <literal>ports</literal> option.
|
||||
NOTE: this will override default listening on all local addresses and port 22.
|
||||
NOTE: setting this option won't automatically enable given ports
|
||||
in firewall configuration.
|
||||
'';
|
||||
};
|
||||
|
||||
passwordAuthentication = mkOption {
|
||||
type = types.bool;
|
||||
default = true;
|
||||
description = ''
|
||||
Specifies whether password authentication is allowed.
|
||||
'';
|
||||
};
|
||||
|
||||
kbdInteractiveAuthentication = mkOption {
|
||||
type = types.bool;
|
||||
default = true;
|
||||
description = ''
|
||||
Specifies whether keyboard-interactive authentication is allowed.
|
||||
'';
|
||||
};
|
||||
|
||||
hostKeys = mkOption {
|
||||
type = types.listOf types.attrs;
|
||||
default =
|
||||
[ { type = "rsa"; bits = 4096; path = "/etc/ssh/ssh_host_rsa_key"; }
|
||||
{ type = "ed25519"; path = "/etc/ssh/ssh_host_ed25519_key"; }
|
||||
];
|
||||
example =
|
||||
[ { type = "rsa"; bits = 4096; path = "/etc/ssh/ssh_host_rsa_key"; rounds = 100; openSSHFormat = true; }
|
||||
{ type = "ed25519"; path = "/etc/ssh/ssh_host_ed25519_key"; rounds = 100; comment = "key comment"; }
|
||||
];
|
||||
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.
|
||||
'';
|
||||
};
|
||||
|
||||
banner = mkOption {
|
||||
type = types.nullOr types.lines;
|
||||
default = null;
|
||||
description = ''
|
||||
Message to display to the remote user before authentication is allowed.
|
||||
'';
|
||||
};
|
||||
|
||||
authorizedKeysFiles = mkOption {
|
||||
type = types.listOf types.str;
|
||||
default = [];
|
||||
description = ''
|
||||
Specify the rules for which files to read on the host.
|
||||
|
||||
This is an advanced option. If you're looking to configure user
|
||||
keys, you can generally use <xref linkend="opt-users.users._name_.openssh.authorizedKeys.keys"/>
|
||||
or <xref linkend="opt-users.users._name_.openssh.authorizedKeys.keyFiles"/>.
|
||||
|
||||
These are paths relative to the host root file system or home
|
||||
directories and they are subject to certain token expansion rules.
|
||||
See AuthorizedKeysFile in man sshd_config for details.
|
||||
'';
|
||||
};
|
||||
|
||||
authorizedKeysCommand = mkOption {
|
||||
type = types.str;
|
||||
default = "none";
|
||||
description = ''
|
||||
Specifies a program to be used to look up the user's public
|
||||
keys. The program must be owned by root, not writable by group
|
||||
or others and specified by an absolute path.
|
||||
'';
|
||||
};
|
||||
|
||||
authorizedKeysCommandUser = mkOption {
|
||||
type = types.str;
|
||||
default = "nobody";
|
||||
description = ''
|
||||
Specifies the user under whose account the AuthorizedKeysCommand
|
||||
is run. It is recommended to use a dedicated user that has no
|
||||
other role on the host than running authorized keys commands.
|
||||
'';
|
||||
};
|
||||
|
||||
kexAlgorithms = mkOption {
|
||||
type = types.listOf types.str;
|
||||
default = [
|
||||
"sntrup761x25519-sha512@openssh.com"
|
||||
"curve25519-sha256"
|
||||
"curve25519-sha256@libssh.org"
|
||||
"diffie-hellman-group-exchange-sha256"
|
||||
];
|
||||
description = ''
|
||||
Allowed key exchange algorithms
|
||||
</para>
|
||||
<para>
|
||||
Uses the lower bound recommended in both
|
||||
<link xlink:href="https://stribika.github.io/2015/01/04/secure-secure-shell.html" />
|
||||
and
|
||||
<link xlink:href="https://infosec.mozilla.org/guidelines/openssh#modern-openssh-67" />
|
||||
'';
|
||||
};
|
||||
|
||||
ciphers = mkOption {
|
||||
type = types.listOf types.str;
|
||||
default = [
|
||||
"chacha20-poly1305@openssh.com"
|
||||
"aes256-gcm@openssh.com"
|
||||
"aes128-gcm@openssh.com"
|
||||
"aes256-ctr"
|
||||
"aes192-ctr"
|
||||
"aes128-ctr"
|
||||
];
|
||||
description = ''
|
||||
Allowed ciphers
|
||||
</para>
|
||||
<para>
|
||||
Defaults to recommended settings from both
|
||||
<link xlink:href="https://stribika.github.io/2015/01/04/secure-secure-shell.html" />
|
||||
and
|
||||
<link xlink:href="https://infosec.mozilla.org/guidelines/openssh#modern-openssh-67" />
|
||||
'';
|
||||
};
|
||||
|
||||
macs = mkOption {
|
||||
type = types.listOf types.str;
|
||||
default = [
|
||||
"hmac-sha2-512-etm@openssh.com"
|
||||
"hmac-sha2-256-etm@openssh.com"
|
||||
"umac-128-etm@openssh.com"
|
||||
"hmac-sha2-512"
|
||||
"hmac-sha2-256"
|
||||
"umac-128@openssh.com"
|
||||
];
|
||||
description = ''
|
||||
Allowed MACs
|
||||
</para>
|
||||
<para>
|
||||
Defaults to recommended settings from both
|
||||
<link xlink:href="https://stribika.github.io/2015/01/04/secure-secure-shell.html" />
|
||||
and
|
||||
<link xlink:href="https://infosec.mozilla.org/guidelines/openssh#modern-openssh-67" />
|
||||
'';
|
||||
};
|
||||
|
||||
logLevel = mkOption {
|
||||
type = types.enum [ "QUIET" "FATAL" "ERROR" "INFO" "VERBOSE" "DEBUG" "DEBUG1" "DEBUG2" "DEBUG3" ];
|
||||
default = "INFO"; # upstream default
|
||||
description = ''
|
||||
Gives the verbosity level that is used when logging messages from sshd(8). The possible values are:
|
||||
QUIET, FATAL, ERROR, INFO, VERBOSE, DEBUG, DEBUG1, DEBUG2, and DEBUG3. The default is INFO. DEBUG and DEBUG1
|
||||
are equivalent. DEBUG2 and DEBUG3 each specify higher levels of debugging output. Logging with a DEBUG level
|
||||
violates the privacy of users and is not recommended.
|
||||
'';
|
||||
};
|
||||
|
||||
useDns = mkOption {
|
||||
type = types.bool;
|
||||
default = false;
|
||||
description = ''
|
||||
Specifies whether sshd(8) should look up the remote host name, and to check that the resolved host name for
|
||||
the remote IP address maps back to the very same IP address.
|
||||
If this option is set to no (the default) then only addresses and not host names may be used in
|
||||
~/.ssh/authorized_keys from and sshd_config Match Host directives.
|
||||
'';
|
||||
};
|
||||
|
||||
extraConfig = mkOption {
|
||||
type = types.lines;
|
||||
default = "";
|
||||
description = "Verbatim contents of <filename>sshd_config</filename>.";
|
||||
};
|
||||
|
||||
moduliFile = mkOption {
|
||||
example = "/etc/my-local-ssh-moduli;";
|
||||
type = types.path;
|
||||
description = ''
|
||||
Path to <literal>moduli</literal> file to install in
|
||||
<literal>/etc/ssh/moduli</literal>. If this option is unset, then
|
||||
the <literal>moduli</literal> file shipped with OpenSSH will be used.
|
||||
'';
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
users.users = mkOption {
|
||||
type = with types; attrsOf (submodule userOptions);
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
|
||||
###### implementation
|
||||
|
||||
config = mkIf cfg.enable {
|
||||
|
||||
users.users.sshd =
|
||||
{
|
||||
isSystemUser = true;
|
||||
group = "sshd";
|
||||
description = "SSH privilege separation user";
|
||||
};
|
||||
users.groups.sshd = {};
|
||||
|
||||
services.openssh.moduliFile = mkDefault "${cfgc.package}/etc/ssh/moduli";
|
||||
services.openssh.sftpServerExecutable = mkDefault "${cfgc.package}/libexec/sftp-server";
|
||||
|
||||
environment.etc = authKeysFiles //
|
||||
{ "ssh/moduli".source = cfg.moduliFile;
|
||||
"ssh/sshd_config".source = sshconf;
|
||||
};
|
||||
|
||||
systemd =
|
||||
let
|
||||
service =
|
||||
{ description = "SSH Daemon";
|
||||
wantedBy = optional (!cfg.startWhenNeeded) "multi-user.target";
|
||||
after = [ "network.target" ];
|
||||
stopIfChanged = false;
|
||||
path = [ cfgc.package pkgs.gawk ];
|
||||
environment.LD_LIBRARY_PATH = nssModulesPath;
|
||||
|
||||
restartTriggers = optionals (!cfg.startWhenNeeded) [
|
||||
config.environment.etc."ssh/sshd_config".source
|
||||
];
|
||||
|
||||
preStart =
|
||||
''
|
||||
# Make sure we don't write to stdout, since in case of
|
||||
# socket activation, it goes to the remote side (#19589).
|
||||
exec >&2
|
||||
|
||||
mkdir -m 0755 -p /etc/ssh
|
||||
|
||||
${flip concatMapStrings cfg.hostKeys (k: ''
|
||||
if ! [ -s "${k.path}" ]; then
|
||||
rm -f "${k.path}"
|
||||
ssh-keygen \
|
||||
-t "${k.type}" \
|
||||
${if k ? bits then "-b ${toString k.bits}" else ""} \
|
||||
${if k ? rounds then "-a ${toString k.rounds}" else ""} \
|
||||
${if k ? comment then "-C '${k.comment}'" else ""} \
|
||||
${if k ? openSSHFormat && k.openSSHFormat then "-o" else ""} \
|
||||
-f "${k.path}" \
|
||||
-N ""
|
||||
fi
|
||||
'')}
|
||||
'';
|
||||
|
||||
serviceConfig =
|
||||
{ ExecStart =
|
||||
(optionalString cfg.startWhenNeeded "-") +
|
||||
"${cfgc.package}/bin/sshd " + (optionalString cfg.startWhenNeeded "-i ") +
|
||||
"-D " + # don't detach into a daemon process
|
||||
"-f /etc/ssh/sshd_config";
|
||||
KillMode = "process";
|
||||
} // (if cfg.startWhenNeeded then {
|
||||
StandardInput = "socket";
|
||||
StandardError = "journal";
|
||||
} else {
|
||||
Restart = "always";
|
||||
Type = "simple";
|
||||
});
|
||||
|
||||
};
|
||||
in
|
||||
|
||||
if cfg.startWhenNeeded then {
|
||||
|
||||
sockets.sshd =
|
||||
{ description = "SSH Socket";
|
||||
wantedBy = [ "sockets.target" ];
|
||||
socketConfig.ListenStream = if cfg.listenAddresses != [] then
|
||||
map (l: "${l.addr}:${toString (if l.port != null then l.port else 22)}") cfg.listenAddresses
|
||||
else
|
||||
cfg.ports;
|
||||
socketConfig.Accept = true;
|
||||
# Prevent brute-force attacks from shutting down socket
|
||||
socketConfig.TriggerLimitIntervalSec = 0;
|
||||
};
|
||||
|
||||
services."sshd@" = service;
|
||||
|
||||
} else {
|
||||
|
||||
services.sshd = service;
|
||||
|
||||
};
|
||||
|
||||
networking.firewall.allowedTCPPorts = if cfg.openFirewall then cfg.ports else [];
|
||||
|
||||
security.pam.services.sshd =
|
||||
{ startSession = true;
|
||||
showMotd = true;
|
||||
unixAuth = cfg.passwordAuthentication;
|
||||
};
|
||||
|
||||
# These values are merged with the ones defined externally, see:
|
||||
# https://github.com/NixOS/nixpkgs/pull/10155
|
||||
# https://github.com/NixOS/nixpkgs/pull/41745
|
||||
services.openssh.authorizedKeysFiles =
|
||||
[ "%h/.ssh/authorized_keys" "%h/.ssh/authorized_keys2" "/etc/ssh/authorized_keys.d/%u" ];
|
||||
|
||||
services.openssh.extraConfig = mkOrder 0
|
||||
''
|
||||
UsePAM yes
|
||||
|
||||
Banner ${if cfg.banner == null then "none" else pkgs.writeText "ssh_banner" cfg.banner}
|
||||
|
||||
AddressFamily ${if config.networking.enableIPv6 then "any" else "inet"}
|
||||
${concatMapStrings (port: ''
|
||||
Port ${toString port}
|
||||
'') cfg.ports}
|
||||
|
||||
${concatMapStrings ({ port, addr, ... }: ''
|
||||
ListenAddress ${addr}${if port != null then ":" + toString port else ""}
|
||||
'') cfg.listenAddresses}
|
||||
|
||||
${optionalString cfgc.setXAuthLocation ''
|
||||
XAuthLocation ${pkgs.xorg.xauth}/bin/xauth
|
||||
''}
|
||||
|
||||
X11Forwarding ${if cfg.forwardX11 then "yes" else "no"}
|
||||
|
||||
${optionalString cfg.allowSFTP ''
|
||||
Subsystem sftp ${cfg.sftpServerExecutable} ${concatStringsSep " " cfg.sftpFlags}
|
||||
''}
|
||||
|
||||
PermitRootLogin ${cfg.permitRootLogin}
|
||||
GatewayPorts ${cfg.gatewayPorts}
|
||||
PasswordAuthentication ${if cfg.passwordAuthentication then "yes" else "no"}
|
||||
KbdInteractiveAuthentication ${if cfg.kbdInteractiveAuthentication then "yes" else "no"}
|
||||
|
||||
PrintMotd no # handled by pam_motd
|
||||
|
||||
AuthorizedKeysFile ${toString cfg.authorizedKeysFiles}
|
||||
${optionalString (cfg.authorizedKeysCommand != "none") ''
|
||||
AuthorizedKeysCommand ${cfg.authorizedKeysCommand}
|
||||
AuthorizedKeysCommandUser ${cfg.authorizedKeysCommandUser}
|
||||
''}
|
||||
|
||||
${flip concatMapStrings cfg.hostKeys (k: ''
|
||||
HostKey ${k.path}
|
||||
'')}
|
||||
|
||||
KexAlgorithms ${concatStringsSep "," cfg.kexAlgorithms}
|
||||
Ciphers ${concatStringsSep "," cfg.ciphers}
|
||||
MACs ${concatStringsSep "," cfg.macs}
|
||||
|
||||
LogLevel ${cfg.logLevel}
|
||||
|
||||
UseDNS ${if cfg.useDns then "yes" else "no"}
|
||||
|
||||
'';
|
||||
|
||||
assertions = [{ assertion = if cfg.forwardX11 then cfgc.setXAuthLocation else true;
|
||||
message = "cannot enable X11 forwarding without setting xauth location";}]
|
||||
++ forEach cfg.listenAddresses ({ addr, ... }: {
|
||||
assertion = addr != null;
|
||||
message = "addr must be specified in each listenAddresses entry";
|
||||
});
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue