Merge pull request #10464 from abbradar/encrypted-swap

nixos/swap: refactor, add randomEncryption option
This commit is contained in:
Nikolay Amiantov 2015-10-30 11:49:46 +03:00
commit 00f79aab90
3 changed files with 104 additions and 67 deletions

View File

@ -3,6 +3,84 @@
with utils; with utils;
with lib; with lib;
let
swapCfg = {config, options, ...}: {
options = {
device = mkOption {
example = "/dev/sda3";
type = types.str;
description = "Path of the device.";
};
label = mkOption {
example = "swap";
type = types.str;
description = ''
Label of the device. Can be used instead of <varname>device</varname>.
'';
};
size = mkOption {
default = null;
example = 2048;
type = types.nullOr types.int;
description = ''
If this option is set, device is interpreted as the
path of a swapfile that will be created automatically
with the indicated size (in megabytes) if it doesn't
exist.
'';
};
priority = mkOption {
default = null;
example = 2048;
type = types.nullOr types.int;
description = ''
Specify the priority of the swap device. Priority is a value between 0 and 32767.
Higher numbers indicate higher priority.
null lets the kernel choose a priority, which will show up as a negative value.
'';
};
randomEncryption = mkOption {
default = false;
type = types.bool;
description = ''
Encrypt swap device with a random key. This way you won't have a persistent swap device.
WARNING: Don't try to hibernate when you have at least one swap partition with
this option enabled! We have no way to set the partition into which hibernation image
is saved, so if your image ends up on an encrypted one you would lose it!
'';
};
deviceName = mkOption {
type = types.str;
internal = true;
};
realDevice = mkOption {
type = types.path;
internal = true;
};
};
config = rec {
device = mkIf options.label.isDefined
"/dev/disk/by-label/${config.label}";
deviceName = escapeSystemdPath config.device;
realDevice = if config.randomEncryption then "/dev/mapper/${deviceName}" else config.device;
};
};
in
{ {
###### interface ###### interface
@ -26,58 +104,7 @@ with lib;
recommended. recommended.
''; '';
type = types.listOf types.optionSet; type = types.listOf (types.submodule swapCfg);
options = {config, options, ...}: {
options = {
device = mkOption {
example = "/dev/sda3";
type = types.str;
description = "Path of the device.";
};
label = mkOption {
example = "swap";
type = types.str;
description = ''
Label of the device. Can be used instead of <varname>device</varname>.
'';
};
size = mkOption {
default = null;
example = 2048;
type = types.nullOr types.int;
description = ''
If this option is set, device is interpreted as the
path of a swapfile that will be created automatically
with the indicated size (in megabytes) if it doesn't
exist.
'';
};
priority = mkOption {
default = null;
example = 2048;
type = types.nullOr types.int;
description = ''
Specify the priority of the swap device. Priority is a value between 0 and 32767.
Higher numbers indicate higher priority.
null lets the kernel choose a priority, which will show up as a negative value.
'';
};
};
config = {
device = mkIf options.label.isDefined
"/dev/disk/by-label/${config.label}";
};
};
}; };
}; };
@ -95,27 +122,37 @@ with lib;
createSwapDevice = sw: createSwapDevice = sw:
assert sw.device != ""; assert sw.device != "";
let device' = escapeSystemdPath sw.device; in let realDevice' = escapeSystemdPath sw.realDevice;
nameValuePair "mkswap-${escapeSystemdPath sw.device}" in nameValuePair "mkswap-${sw.deviceName}"
{ description = "Initialisation of Swapfile ${sw.device}"; { description = "Initialisation of swap device ${sw.device}";
wantedBy = [ "${device'}.swap" ]; wantedBy = [ "${realDevice'}.swap" ];
before = [ "${device'}.swap" ]; before = [ "${realDevice'}.swap" ];
path = [ pkgs.utillinux ]; path = [ pkgs.utillinux ] ++ optional sw.randomEncryption pkgs.cryptsetup;
script = script =
'' ''
if [ ! -e "${sw.device}" ]; then ${optionalString (sw.size != null) ''
fallocate -l ${toString sw.size}M "${sw.device}" || if [ ! -e "${sw.device}" ]; then
dd if=/dev/zero of="${sw.device}" bs=1M count=${toString sw.size} fallocate -l ${toString sw.size}M "${sw.device}" ||
chmod 0600 ${sw.device} dd if=/dev/zero of="${sw.device}" bs=1M count=${toString sw.size}
mkswap ${sw.device} chmod 0600 ${sw.device}
fi ${optionalString (!sw.randomEncryption) "mkswap ${sw.realDevice}"}
fi
''}
${optionalString sw.randomEncryption ''
echo "secretkey" | cryptsetup luksFormat --batch-mode ${sw.device}
echo "secretkey" | cryptsetup luksOpen ${sw.device} ${sw.deviceName}
cryptsetup luksErase --batch-mode ${sw.device}
mkswap ${sw.realDevice}
''}
''; '';
unitConfig.RequiresMountsFor = [ "${dirOf sw.device}" ]; unitConfig.RequiresMountsFor = [ "${dirOf sw.device}" ];
unitConfig.DefaultDependencies = false; # needed to prevent a cycle unitConfig.DefaultDependencies = false; # needed to prevent a cycle
serviceConfig.Type = "oneshot"; serviceConfig.Type = "oneshot";
serviceConfig.RemainAfterExit = sw.randomEncryption;
serviceConfig.ExecStop = optionalString sw.randomEncryption "cryptsetup luksClose ${sw.deviceName}";
}; };
in listToAttrs (map createSwapDevice (filter (sw: sw.size != null) config.swapDevices)); in listToAttrs (map createSwapDevice (filter (sw: sw.size != null || sw.randomEncryption) config.swapDevices));
}; };

View File

@ -206,7 +206,7 @@ let
preLVMCommands postDeviceCommands postMountCommands kernelModules; 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) config.swapDevices); (filter (sd: (sd ? label || hasPrefix "/dev/" sd.device) && !sd.randomEncryption) config.swapDevices);
fsInfo = fsInfo =
let f = fs: [ fs.mountPoint (if fs.device != null then fs.device else "/dev/disk/by-label/${fs.label}") fs.fsType fs.options ]; let f = fs: [ fs.mountPoint (if fs.device != null then fs.device else "/dev/disk/by-label/${fs.label}") fs.fsType fs.options ];

View File

@ -174,7 +174,7 @@ in
# Swap devices. # Swap devices.
${flip concatMapStrings config.swapDevices (sw: ${flip concatMapStrings config.swapDevices (sw:
"${sw.device} none swap${prioOption sw.priority}\n" "${sw.realDevice} none swap${prioOption sw.priority}\n"
)} )}
''; '';