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
|
# LUKS backup sticks for pika-backup, unlocked and mounted on access.
{ lib, ... }:
let
sticks = [
{ name = "backup-stick1"; uuid = "c9c0c874-cb2c-4702-9f4c-103d196f808f"; }
];
in
{
config = {
# Each stick is unlocked and mounted on first access of /mnt/<name>,
# unmounted after 5 idle minutes, and closed when pulled out. No prompt:
# its LUKS key is a system credential encrypted with
# --with-key=host+tpm2, so it needs both
# /var/lib/systemd/credential.secret (root-only, on the encrypted root)
# and this machine's TPM. A live system on this hardware has the TPM but
# not the host key; a copy of the root disk elsewhere has the host key
# but not the TPM. Secure Boot is off, so a TPM-only (PCR) binding would
# have unlocked it for any live system. The stick's own passphrase keyslot
# stays, for unlocking it anywhere else. Enrolling (as root, once per
# stick; asks for its passphrase; the key is text, as
# cryptsetup.passphrase is read as a passphrase, and only ever on tmpfs):
# n=<name> uuid=<uuid> # from `sticks` above
# umask 077; k=/run/$n.key
# head --bytes=48 /dev/urandom | base64 --wrap=0 > $k
# cryptsetup luksAddKey /dev/disk/by-uuid/$uuid $k
# mkdir --parents /etc/credstore.encrypted
# systemd-creds encrypt --with-key=host+tpm2 --name=cryptsetup.passphrase \
# $k /etc/credstore.encrypted/$n.cred
# shred --remove $k
# Any user's access to the mount point unlocks it; file modes decide the
# rest (the repo directories are philip's, 0700).
# Not "headless": systemd-cryptsetup checks it before it looks at the
# cryptsetup.passphrase credential, so the credential would never be read.
# The credential is tried first; only without it does a prompt come up, and
# tries=1 plus the short timeout keep a missing one from hanging the mount.
# The device timeout is for the stick itself: absent, access fails in 5s.
environment.etc.crypttab.text = lib.concatMapStrings (s: ''
${s.name} UUID=${s.uuid} none luks,noauto,nofail,tries=1,timeout=10s,x-systemd.device-timeout=5s
'') sticks;
systemd.services = lib.listToAttrs (map (s: {
name = "systemd-cryptsetup@${lib.replaceStrings [ "-" ] [ "\\x2d" ] s.name}";
value = {
overrideStrategy = "asDropin";
serviceConfig.LoadCredentialEncrypted =
"cryptsetup.passphrase:/etc/credstore.encrypted/${s.name}.cred";
};
}) sticks);
fileSystems = lib.listToAttrs (map (s: {
name = "/mnt/${s.name}";
value = {
device = "/dev/mapper/${s.name}";
fsType = "ext4";
options = [
"noauto"
"nofail"
"x-systemd.automount"
"x-systemd.idle-timeout=5min"
# waits for the unlocked /dev/mapper device: unlocking takes ~6s
# (argon2), so this must be well above that
"x-systemd.device-timeout=30s"
];
};
}) sticks);
};
}
|