Merge pull request #10460 from abbradar/remote-askpass
Support network in initrd and entering LUKS passphrase via SSH
This commit is contained in:
commit
d4c27381dc
|
@ -441,6 +441,7 @@
|
||||||
./system/activation/top-level.nix
|
./system/activation/top-level.nix
|
||||||
./system/boot/coredump.nix
|
./system/boot/coredump.nix
|
||||||
./system/boot/emergency-mode.nix
|
./system/boot/emergency-mode.nix
|
||||||
|
./system/boot/initrd-network.nix
|
||||||
./system/boot/kernel.nix
|
./system/boot/kernel.nix
|
||||||
./system/boot/kexec.nix
|
./system/boot/kexec.nix
|
||||||
./system/boot/loader/efi.nix
|
./system/boot/loader/efi.nix
|
||||||
|
|
|
@ -0,0 +1,149 @@
|
||||||
|
{ config, lib, pkgs, ... }:
|
||||||
|
|
||||||
|
with lib;
|
||||||
|
|
||||||
|
let
|
||||||
|
cfg = config.boot.initrd.network;
|
||||||
|
|
||||||
|
in
|
||||||
|
{
|
||||||
|
|
||||||
|
options = {
|
||||||
|
|
||||||
|
boot.initrd.network.enable = mkOption {
|
||||||
|
type = types.bool;
|
||||||
|
default = false;
|
||||||
|
description = ''
|
||||||
|
Add network connectivity support to initrd.
|
||||||
|
|
||||||
|
Network options are configured via <literal>ip</literal> kernel
|
||||||
|
option, according to the kernel documentation.
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
boot.initrd.network.ssh.enable = mkOption {
|
||||||
|
type = types.bool;
|
||||||
|
default = false;
|
||||||
|
description = ''
|
||||||
|
Start SSH service during initrd boot. It can be used to debug failing
|
||||||
|
boot on a remote server, enter pasphrase for an encrypted partition etc.
|
||||||
|
Service is killed when stage-1 boot is finished.
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
boot.initrd.network.ssh.port = mkOption {
|
||||||
|
type = types.int;
|
||||||
|
default = 22;
|
||||||
|
description = ''
|
||||||
|
Port on which SSH initrd service should listen.
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
boot.initrd.network.ssh.shell = mkOption {
|
||||||
|
type = types.str;
|
||||||
|
default = "/bin/ash";
|
||||||
|
description = ''
|
||||||
|
Login shell of the remote user. Can be used to limit actions user can do.
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
boot.initrd.network.ssh.hostRSAKey = mkOption {
|
||||||
|
type = types.nullOr types.path;
|
||||||
|
default = null;
|
||||||
|
description = ''
|
||||||
|
RSA SSH private key file in the Dropbear format.
|
||||||
|
|
||||||
|
WARNING: This key is contained insecurely in the global Nix store. Do NOT
|
||||||
|
use your regular SSH host private keys for this purpose or you'll expose
|
||||||
|
them to regular users!
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
boot.initrd.network.ssh.hostDSSKey = mkOption {
|
||||||
|
type = types.nullOr types.path;
|
||||||
|
default = null;
|
||||||
|
description = ''
|
||||||
|
DSS SSH private key file in the Dropbear format.
|
||||||
|
|
||||||
|
WARNING: This key is contained insecurely in the global Nix store. Do NOT
|
||||||
|
use your regular SSH host private keys for this purpose or you'll expose
|
||||||
|
them to regular users!
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
boot.initrd.network.ssh.hostECDSAKey = mkOption {
|
||||||
|
type = types.nullOr types.path;
|
||||||
|
default = null;
|
||||||
|
description = ''
|
||||||
|
ECDSA SSH private key file in the Dropbear format.
|
||||||
|
|
||||||
|
WARNING: This key is contained insecurely in the global Nix store. Do NOT
|
||||||
|
use your regular SSH host private keys for this purpose or you'll expose
|
||||||
|
them to regular users!
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
boot.initrd.network.ssh.authorizedKeys = mkOption {
|
||||||
|
type = types.listOf types.str;
|
||||||
|
default = config.users.extraUsers.root.openssh.authorizedKeys.keys;
|
||||||
|
description = ''
|
||||||
|
Authorized keys for the root user on initrd.
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
config = mkIf cfg.enable {
|
||||||
|
|
||||||
|
boot.initrd.kernelModules = [ "af_packet" ];
|
||||||
|
|
||||||
|
boot.initrd.extraUtilsCommands = ''
|
||||||
|
copy_bin_and_libs ${pkgs.mkinitcpio-nfs-utils}/bin/ipconfig
|
||||||
|
'' + optionalString cfg.ssh.enable ''
|
||||||
|
copy_bin_and_libs ${pkgs.dropbear}/bin/dropbear
|
||||||
|
|
||||||
|
cp -pv ${pkgs.glibc}/lib/libnss_files.so.* $out/lib
|
||||||
|
'';
|
||||||
|
|
||||||
|
boot.initrd.extraUtilsCommandsTest = optionalString cfg.ssh.enable ''
|
||||||
|
$out/bin/dropbear -V
|
||||||
|
'';
|
||||||
|
|
||||||
|
boot.initrd.postEarlyDeviceCommands = ''
|
||||||
|
# Search for interface definitions in command line
|
||||||
|
for o in $(cat /proc/cmdline); do
|
||||||
|
case $o in
|
||||||
|
ip=*)
|
||||||
|
ipconfig $o && hasNetwork=1
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
'' + optionalString cfg.ssh.enable ''
|
||||||
|
if [ -n "$hasNetwork" ]; then
|
||||||
|
mkdir /dev/pts
|
||||||
|
mount -t devpts devpts /dev/pts
|
||||||
|
|
||||||
|
mkdir -p /etc
|
||||||
|
echo 'root:x:0:0:root:/root:${cfg.ssh.shell}' > /etc/passwd
|
||||||
|
echo '${cfg.ssh.shell}' > /etc/shells
|
||||||
|
echo 'passwd: files' > /etc/nsswitch.conf
|
||||||
|
|
||||||
|
mkdir -p /var/log
|
||||||
|
touch /var/log/lastlog
|
||||||
|
|
||||||
|
mkdir -p /etc/dropbear
|
||||||
|
${optionalString (cfg.ssh.hostRSAKey != null) "ln -s ${cfg.ssh.hostRSAKey} /etc/dropbear/dropbear_rsa_host_key"}
|
||||||
|
${optionalString (cfg.ssh.hostDSSKey != null) "ln -s ${cfg.ssh.hostDSSKey} /etc/dropbear/dropbear_dss_host_key"}
|
||||||
|
${optionalString (cfg.ssh.hostECDSAKey != null) "ln -s ${cfg.ssh.hostECDSAKey} /etc/dropbear/dropbear_ecdsa_host_key"}
|
||||||
|
|
||||||
|
mkdir -p /root/.ssh
|
||||||
|
${concatStrings (map (key: ''
|
||||||
|
echo -n ${escapeShellArg key} >> /root/.ssh/authorized_keys
|
||||||
|
'') cfg.ssh.authorizedKeys)}
|
||||||
|
|
||||||
|
dropbear -s -j -k -E -m -p ${toString cfg.ssh.port}
|
||||||
|
fi
|
||||||
|
'';
|
||||||
|
|
||||||
|
};
|
||||||
|
}
|
|
@ -32,9 +32,12 @@ let
|
||||||
''}
|
''}
|
||||||
|
|
||||||
open_normally() {
|
open_normally() {
|
||||||
cryptsetup luksOpen ${device} ${name} ${optionalString allowDiscards "--allow-discards"} \
|
echo luksOpen ${device} ${name} ${optionalString allowDiscards "--allow-discards"} \
|
||||||
${optionalString (header != null) "--header=${header}"} \
|
${optionalString (header != null) "--header=${header}"} \
|
||||||
${optionalString (keyFile != null) "--key-file=${keyFile} ${optionalString (keyFileSize != null) "--keyfile-size=${toString keyFileSize}"}"}
|
${optionalString (keyFile != null) "--key-file=${keyFile} ${optionalString (keyFileSize != null) "--keyfile-size=${toString keyFileSize}"}"} \
|
||||||
|
> /.luksopen_args
|
||||||
|
cryptsetup-askpass
|
||||||
|
rm /.luksopen_args
|
||||||
}
|
}
|
||||||
|
|
||||||
${optionalString (luks.yubikeySupport && (yubikey != null)) ''
|
${optionalString (luks.yubikeySupport && (yubikey != null)) ''
|
||||||
|
@ -418,6 +421,18 @@ in
|
||||||
boot.initrd.extraUtilsCommands = ''
|
boot.initrd.extraUtilsCommands = ''
|
||||||
copy_bin_and_libs ${pkgs.cryptsetup}/bin/cryptsetup
|
copy_bin_and_libs ${pkgs.cryptsetup}/bin/cryptsetup
|
||||||
|
|
||||||
|
cat > $out/bin/cryptsetup-askpass <<EOF
|
||||||
|
#!$out/bin/sh -e
|
||||||
|
if [ -e /.luksopen_args ]; then
|
||||||
|
cryptsetup \$(cat /.luksopen_args)
|
||||||
|
killall cryptsetup
|
||||||
|
else
|
||||||
|
echo "Passphrase is not requested now"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
EOF
|
||||||
|
chmod +x $out/bin/cryptsetup-askpass
|
||||||
|
|
||||||
${optionalString luks.yubikeySupport ''
|
${optionalString luks.yubikeySupport ''
|
||||||
copy_bin_and_libs ${pkgs.ykpers}/bin/ykchalresp
|
copy_bin_and_libs ${pkgs.ykpers}/bin/ykchalresp
|
||||||
copy_bin_and_libs ${pkgs.ykpers}/bin/ykinfo
|
copy_bin_and_libs ${pkgs.ykpers}/bin/ykinfo
|
||||||
|
@ -432,6 +447,8 @@ in
|
||||||
|
|
||||||
cat > $out/bin/openssl-wrap <<EOF
|
cat > $out/bin/openssl-wrap <<EOF
|
||||||
#!$out/bin/sh
|
#!$out/bin/sh
|
||||||
|
export OPENSSL_CONF=$out/etc/ssl/openssl.cnf
|
||||||
|
$out/bin/openssl "\$@"
|
||||||
EOF
|
EOF
|
||||||
chmod +x $out/bin/openssl-wrap
|
chmod +x $out/bin/openssl-wrap
|
||||||
''}
|
''}
|
||||||
|
@ -442,11 +459,6 @@ in
|
||||||
${optionalString luks.yubikeySupport ''
|
${optionalString luks.yubikeySupport ''
|
||||||
$out/bin/ykchalresp -V
|
$out/bin/ykchalresp -V
|
||||||
$out/bin/ykinfo -V
|
$out/bin/ykinfo -V
|
||||||
cat > $out/bin/openssl-wrap <<EOF
|
|
||||||
#!$out/bin/sh
|
|
||||||
export OPENSSL_CONF=$out/etc/ssl/openssl.cnf
|
|
||||||
$out/bin/openssl "\$@"
|
|
||||||
EOF
|
|
||||||
$out/bin/openssl-wrap version
|
$out/bin/openssl-wrap version
|
||||||
''}
|
''}
|
||||||
'';
|
'';
|
||||||
|
|
|
@ -149,6 +149,10 @@ udevadm trigger --action=add
|
||||||
udevadm settle
|
udevadm settle
|
||||||
|
|
||||||
|
|
||||||
|
# Additional devices initialization.
|
||||||
|
@postEarlyDeviceCommands@
|
||||||
|
|
||||||
|
|
||||||
# Load boot-time keymap before any LVM/LUKS initialization
|
# Load boot-time keymap before any LVM/LUKS initialization
|
||||||
@extraUtils@/bin/busybox loadkmap < "@busyboxKeymap@"
|
@extraUtils@/bin/busybox loadkmap < "@busyboxKeymap@"
|
||||||
|
|
||||||
|
|
|
@ -104,7 +104,7 @@ let
|
||||||
stripDirs "lib bin" "-s"
|
stripDirs "lib bin" "-s"
|
||||||
|
|
||||||
# Run patchelf to make the programs refer to the copied libraries.
|
# Run patchelf to make the programs refer to the copied libraries.
|
||||||
for i in $out/bin/* $out/lib/*; do if ! test -L $i; then nuke-refs $i; fi; done
|
for i in $out/bin/* $out/lib/*; do if ! test -L $i; then nuke-refs -e $out $i; fi; done
|
||||||
|
|
||||||
for i in $out/bin/*; do
|
for i in $out/bin/*; do
|
||||||
if ! test -L $i; then
|
if ! test -L $i; then
|
||||||
|
@ -203,7 +203,7 @@ let
|
||||||
inherit (config.boot) resumeDevice devSize runSize;
|
inherit (config.boot) resumeDevice devSize runSize;
|
||||||
|
|
||||||
inherit (config.boot.initrd) checkJournalingFS
|
inherit (config.boot.initrd) checkJournalingFS
|
||||||
preLVMCommands postDeviceCommands postMountCommands kernelModules;
|
postEarlyDeviceCommands preLVMCommands postDeviceCommands postMountCommands kernelModules;
|
||||||
|
|
||||||
resumeDevices = map (sd: if sd ? device then sd.device else "/dev/disk/by-label/${sd.label}")
|
resumeDevices = map (sd: if sd ? device then sd.device else "/dev/disk/by-label/${sd.label}")
|
||||||
(filter (sd: (sd ? label || hasPrefix "/dev/" sd.device) && !sd.randomEncryption) config.swapDevices);
|
(filter (sd: (sd ? label || hasPrefix "/dev/" sd.device) && !sd.randomEncryption) config.swapDevices);
|
||||||
|
@ -313,6 +313,14 @@ in
|
||||||
'';
|
'';
|
||||||
};
|
};
|
||||||
|
|
||||||
|
boot.initrd.postEarlyDeviceCommands = mkOption {
|
||||||
|
default = "";
|
||||||
|
type = types.lines;
|
||||||
|
description = ''
|
||||||
|
Shell commands to be executed early after creation of device nodes.
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
boot.initrd.postMountCommands = mkOption {
|
boot.initrd.postMountCommands = mkOption {
|
||||||
default = "";
|
default = "";
|
||||||
type = types.lines;
|
type = types.lines;
|
||||||
|
|
|
@ -3,11 +3,26 @@ source $stdenv/setup
|
||||||
mkdir -p $out/bin
|
mkdir -p $out/bin
|
||||||
cat > $out/bin/nuke-refs <<EOF
|
cat > $out/bin/nuke-refs <<EOF
|
||||||
#! $SHELL -e
|
#! $SHELL -e
|
||||||
for i in \$*; do
|
|
||||||
if test ! -L \$i -a -f \$i; then
|
excludes=""
|
||||||
cat \$i | sed "s|$NIX_STORE/[a-z0-9]*-|$NIX_STORE/eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee-|g" > \$i.tmp
|
while getopts e: o; do
|
||||||
if test -x \$i; then chmod +x \$i.tmp; fi
|
case "\$o" in
|
||||||
mv \$i.tmp \$i
|
e) storeId=\$(echo "\$OPTARG" | sed -n "s|^$NIX_STORE/\\([a-z0-9]\{32\}\\)-.*|\1|p")
|
||||||
|
if [ -z "\$storeId" ]; then
|
||||||
|
echo "-e argument must be a Nix store path"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
excludes="\$excludes(?!\$storeId)"
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
shift \$((\$OPTIND-1))
|
||||||
|
|
||||||
|
for i in "\$@"; do
|
||||||
|
if test ! -L "\$i" -a -f "\$i"; then
|
||||||
|
cat "\$i" | $perl/bin/perl -pe "s|$NIX_STORE/\$excludes[a-z0-9]{32}-|$NIX_STORE/eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee-|g" > "\$i.tmp"
|
||||||
|
if test -x "\$i"; then chmod +x "\$i.tmp"; fi
|
||||||
|
mv "\$i.tmp" "\$i"
|
||||||
fi
|
fi
|
||||||
done
|
done
|
||||||
EOF
|
EOF
|
||||||
|
|
|
@ -3,9 +3,10 @@
|
||||||
# path (/nix/store/eeee...). This is useful for getting rid of
|
# path (/nix/store/eeee...). This is useful for getting rid of
|
||||||
# dependencies that you know are not actually needed at runtime.
|
# dependencies that you know are not actually needed at runtime.
|
||||||
|
|
||||||
{stdenv}:
|
{ stdenv, perl }:
|
||||||
|
|
||||||
stdenv.mkDerivation {
|
stdenv.mkDerivation {
|
||||||
name = "nuke-references";
|
name = "nuke-references";
|
||||||
builder = ./builder.sh;
|
builder = ./builder.sh;
|
||||||
}
|
inherit perl;
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,26 @@
|
||||||
|
{ stdenv, fetchurl, xz }:
|
||||||
|
|
||||||
|
stdenv.mkDerivation rec {
|
||||||
|
name = "mkinitcpio-nfs-utils-0.3";
|
||||||
|
|
||||||
|
src = fetchurl {
|
||||||
|
url = "https://sources.archlinux.org/other/mkinitcpio/${name}.tar.xz";
|
||||||
|
sha256 = "0fc93sfk41ycpa33083kyd7i4y00ykpbhj5qlw611bjghj4x946j";
|
||||||
|
# ugh, upstream...
|
||||||
|
name = "${name}.tar.gz";
|
||||||
|
};
|
||||||
|
|
||||||
|
makeFlags = [ "DESTDIR=$(out)" "bindir=/bin" ];
|
||||||
|
|
||||||
|
postInstall = ''
|
||||||
|
rm -rf $out/usr
|
||||||
|
'';
|
||||||
|
|
||||||
|
meta = with stdenv.lib; {
|
||||||
|
homepage = https://archlinux.org/;
|
||||||
|
description = "ipconfig and nfsmount tools for root on NFS, ported from klibc";
|
||||||
|
license = licenses.gpl2;
|
||||||
|
platforms = platforms.linux;
|
||||||
|
maintainers = with maintainers; [ abbradar ];
|
||||||
|
};
|
||||||
|
}
|
|
@ -35,9 +35,11 @@ stdenv.mkDerivation rec {
|
||||||
|
|
||||||
buildInputs = [ zlib ];
|
buildInputs = [ zlib ];
|
||||||
|
|
||||||
meta = {
|
meta = with stdenv.lib; {
|
||||||
homepage = http://matt.ucc.asn.au/dropbear/dropbear.html;
|
homepage = http://matt.ucc.asn.au/dropbear/dropbear.html;
|
||||||
description = "An small footprint implementation of the SSH 2 protocol";
|
description = "An small footprint implementation of the SSH 2 protocol";
|
||||||
license = stdenv.lib.licenses.mit;
|
license = licenses.mit;
|
||||||
|
maintainers = with maintainers; [ abbradar ];
|
||||||
|
platforms = platforms.unix;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,31 +1,36 @@
|
||||||
diff --git a/svr-chansession.c b/svr-chansession.c
|
diff --git a/svr-chansession.c b/svr-chansession.c
|
||||||
index 23dad8c..32cac13 100644
|
index e44299e..7ef750a 100644
|
||||||
--- a/svr-chansession.c
|
--- a/svr-chansession.c
|
||||||
+++ b/svr-chansession.c
|
+++ b/svr-chansession.c
|
||||||
@@ -823,6 +823,7 @@ static void addchildpid(struct ChanSess *chansess, pid_t pid) {
|
@@ -893,6 +893,8 @@ static void addchildpid(struct ChanSess *chansess, pid_t pid) {
|
||||||
static void execchild(void *user_data) {
|
static void execchild(void *user_data) {
|
||||||
struct ChanSess *chansess = user_data;
|
struct ChanSess *chansess = user_data;
|
||||||
char *usershell = NULL;
|
char *usershell = NULL;
|
||||||
+ const char *path = DEFAULT_PATH;
|
+ const char *path = DEFAULT_PATH;
|
||||||
|
+ const char *ldpath = NULL;
|
||||||
|
|
||||||
/* with uClinux we'll have vfork()ed, so don't want to overwrite the
|
/* with uClinux we'll have vfork()ed, so don't want to overwrite the
|
||||||
* hostkey. can't think of a workaround to clear it */
|
* hostkey. can't think of a workaround to clear it */
|
||||||
@@ -835,6 +836,9 @@ static void execchild(void *user_data) {
|
@@ -905,6 +907,10 @@ static void execchild(void *user_data) {
|
||||||
reseedrandom();
|
seedrandom();
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
+ if (getenv("PATH"))
|
+ if (getenv("PATH"))
|
||||||
+ path = getenv("PATH");
|
+ path = getenv("PATH");
|
||||||
|
+ ldpath = getenv("LD_LIBRARY_PATH");
|
||||||
+
|
+
|
||||||
/* clear environment */
|
/* clear environment */
|
||||||
/* if we're debugging using valgrind etc, we need to keep the LD_PRELOAD
|
/* if we're debugging using valgrind etc, we need to keep the LD_PRELOAD
|
||||||
* etc. This is hazardous, so should only be used for debugging. */
|
* etc. This is hazardous, so should only be used for debugging. */
|
||||||
@@ -878,7 +882,7 @@ static void execchild(void *user_data) {
|
@@ -948,7 +954,10 @@ static void execchild(void *user_data) {
|
||||||
addnewvar("LOGNAME", ses.authstate.pw_name);
|
addnewvar("LOGNAME", ses.authstate.pw_name);
|
||||||
addnewvar("HOME", ses.authstate.pw_dir);
|
addnewvar("HOME", ses.authstate.pw_dir);
|
||||||
addnewvar("SHELL", get_user_shell());
|
addnewvar("SHELL", get_user_shell());
|
||||||
- addnewvar("PATH", DEFAULT_PATH);
|
- addnewvar("PATH", DEFAULT_PATH);
|
||||||
+ addnewvar("PATH", path);
|
+ addnewvar("PATH", path);
|
||||||
|
+ if (ldpath != NULL) {
|
||||||
|
+ addnewvar("LD_LIBRARY_PATH", ldpath);
|
||||||
|
+ }
|
||||||
if (chansess->term != NULL) {
|
if (chansess->term != NULL) {
|
||||||
addnewvar("TERM", chansess->term);
|
addnewvar("TERM", chansess->term);
|
||||||
}
|
}
|
||||||
|
|
|
@ -10169,6 +10169,8 @@ let
|
||||||
systemd = systemd.override { enableKDbus = true; };
|
systemd = systemd.override { enableKDbus = true; };
|
||||||
};
|
};
|
||||||
|
|
||||||
|
mkinitcpio-nfs-utils = callPackage ../os-specific/linux/mkinitcpio-nfs-utils { };
|
||||||
|
|
||||||
module_init_tools = callPackage ../os-specific/linux/module-init-tools { };
|
module_init_tools = callPackage ../os-specific/linux/module-init-tools { };
|
||||||
|
|
||||||
aggregateModules = modules:
|
aggregateModules = modules:
|
||||||
|
|
Loading…
Reference in New Issue