-
-
Notifications
You must be signed in to change notification settings - Fork 366
/
auto-luks.nix
140 lines (113 loc) · 4.46 KB
/
auto-luks.nix
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
# Module to automatically create LUKS-encrypted devices.
{ config, lib, pkgs, utils, ... }:
with lib;
with utils;
{
###### interface
options = {
deployment.autoLuks = mkOption {
default = { };
example = { secretdisk = { device = "/dev/xvdf"; passphrase = "foobar"; }; };
type = with types; attrsOf (submodule {
options = {
device = mkOption {
example = "/dev/xvdg";
type = types.str;
description = ''
The underlying (encrypted) device.
'';
};
cipher = mkOption {
default = "aes-cbc-essiv:sha256";
type = types.str;
description = ''
The cipher used to encrypt the volume.
'';
};
keySize = mkOption {
default = 128;
type = types.int;
description = ''
The size in bits of the encryption key.
'';
};
passphrase = mkOption {
default = "";
type = types.str;
description = ''
The passphrase (key file) used to decrypt the key to access
the volume. If left empty, a passphrase is generated
automatically; this passphrase is lost when you destroy the
machine or underlying device, unless you copy it from
NixOps's state file. Note that unless
<option>deployment.storeKeysOnMachine</option> is set to
<literal>false</literal>, the passphrase is stored in the
Nix store of the instance, so an attacker who gains access
to the disk containing the store can subsequently decrypt
the encrypted volume.
'';
};
autoFormat = mkOption {
default = false;
type = types.bool;
description = ''
If the underlying device does not currently contain a
filesystem (as determined by <command>blkid</command>, then
automatically initialise it using <command>cryptsetup
luksFormat</command>.
'';
};
};
});
description = ''
The LUKS volumes to be created. The name of each attribute
set specifies the name of the LUKS volume; thus, the resulting
device will be named
<filename>/dev/mapper/<replaceable>name</replaceable></filename>.
'';
};
};
###### implementation
config = {
systemd.services =
let
luksFormat = name: attrs:
let
device' = escapeSystemdPath attrs.device + ".device";
mapperDevice = "/dev/mapper/${name}";
mapperDevice' = escapeSystemdPath mapperDevice;
mapperDevice'' = mapperDevice' + ".device";
keyFile = config.deployment.keys."luks-${name}".path;
in assert attrs.passphrase != ""; nameValuePair "cryptsetup-${name}"
{ description = "Cryptographic Setup of Device ${mapperDevice}";
wantedBy = [ mapperDevice'' ];
before = [ mapperDevice'' "mkfs-${mapperDevice'}.service" ];
requires = [ device' "keys.target" ];
after = [ device' "keys.target" ];
path = [ pkgs.cryptsetup pkgs.utillinux ];
unitConfig.DefaultDependencies = false; # needed to prevent a cycle
serviceConfig.Type = "oneshot";
script =
''
# Do LUKS formatting if the device is empty.
${optionalString attrs.autoFormat ''
[ -e "${attrs.device}" ]
type=$(blkid -p -s TYPE -o value "${attrs.device}") || res=$?
if [ -z "$type" -a \( -z "$res" -o "$res" = 2 \) ]; then
echo "initialising encryption on device ‘${attrs.device}’..."
cryptsetup luksFormat "${attrs.device}" --key-file=${keyFile} \
--cipher ${attrs.cipher} --key-size ${toString attrs.keySize}
fi
''}
# Activate the LUKS device.
if [ ! -e "${mapperDevice}" ]; then
cryptsetup luksOpen "${attrs.device}" "${name}" --key-file=${keyFile}
fi
'';
};
in mapAttrs' luksFormat config.deployment.autoLuks;
deployment.keys = mapAttrs'
(name: attrs: nameValuePair "luks-${name}" { text = attrs.passphrase; } )
config.deployment.autoLuks;
};
}