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,32 +3,9 @@
with utils; with utils;
with lib; with lib;
{ let
###### interface swapCfg = {config, options, ...}: {
options = {
swapDevices = mkOption {
default = [];
example = [
{ device = "/dev/hda7"; }
{ device = "/var/swapfile"; }
{ label = "bigswap"; }
];
description = ''
The swap devices and swap files. These must have been
initialised using <command>mkswap</command>. Each element
should be an attribute set specifying either the path of the
swap device or file (<literal>device</literal>) or the label
of the swap device (<literal>label</literal>, see
<command>mkswap -L</command>). Using a label is
recommended.
'';
type = types.listOf types.optionSet;
options = {config, options, ...}: {
options = { options = {
@ -69,15 +46,65 @@ with lib;
''; '';
}; };
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!
'';
}; };
config = { deviceName = mkOption {
type = types.str;
internal = true;
};
realDevice = mkOption {
type = types.path;
internal = true;
};
};
config = rec {
device = mkIf options.label.isDefined device = mkIf options.label.isDefined
"/dev/disk/by-label/${config.label}"; "/dev/disk/by-label/${config.label}";
deviceName = escapeSystemdPath config.device;
realDevice = if config.randomEncryption then "/dev/mapper/${deviceName}" else config.device;
}; };
}; };
in
{
###### interface
options = {
swapDevices = mkOption {
default = [];
example = [
{ device = "/dev/hda7"; }
{ device = "/var/swapfile"; }
{ label = "bigswap"; }
];
description = ''
The swap devices and swap files. These must have been
initialised using <command>mkswap</command>. Each element
should be an attribute set specifying either the path of the
swap device or file (<literal>device</literal>) or the label
of the swap device (<literal>label</literal>, see
<command>mkswap -L</command>). Using a label is
recommended.
'';
type = types.listOf (types.submodule swapCfg);
}; };
}; };
@ -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 =
'' ''
${optionalString (sw.size != null) ''
if [ ! -e "${sw.device}" ]; then if [ ! -e "${sw.device}" ]; then
fallocate -l ${toString sw.size}M "${sw.device}" || fallocate -l ${toString sw.size}M "${sw.device}" ||
dd if=/dev/zero of="${sw.device}" bs=1M count=${toString sw.size} dd if=/dev/zero of="${sw.device}" bs=1M count=${toString sw.size}
chmod 0600 ${sw.device} chmod 0600 ${sw.device}
mkswap ${sw.device} ${optionalString (!sw.randomEncryption) "mkswap ${sw.realDevice}"}
fi 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"
)} )}
''; '';