summaryrefslogtreecommitdiff
path: root/sys/boot/stack/luks-ext4-fscrypt-impermanence.nix
blob: 4a3e51e4a861745c5c4039acd3a32e444ad3dc8f (plain)
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
{
  config,
  lib,
  pkgs,
  ...
}:
with lib; let
  cfg = config.local.boot.stack.luksExt4FscryptImpermanence;
in {
  options.local.boot.stack.luksExt4FscryptImpermanence = {
    enable = mkEnableOption "filesystem stack: whatever LUKS approach+ext4+impermanence with per-boot keys";

    target = mkOption {
      type = types.str;
    };
  };

  # - boot device
  #   - some unknown fs, probably vfat
  #     - detached luks header file
  #
  # - toplevel device
  #   - headerless luks
  #     - /toplevel (ext4)
  #       - /toplevel/nix
  #       - /toplevel/persist
  #       - /toplevel/boot-archive.pub
  #       - /toplevel/boot-keys
  #         - /toplevel/boot-keys/2000-01-01T00:00:00-06:00.key.age (encrypted for /toplevel/boot-archive.pub)
  #         - /toplevel/boot-keys/...
  #         - /toplevel/boot-keys/last.key.age -> 2000-01-01T00:00:00-06:00.key.age
  #       - /toplevel/boots
  #         - /toplevel/boots/2000-01-01T00:00:00-06:00 (raw protector in last.key.age)
  #         - /toplevel/boots/...
  #         - /toplevel/boots/last -> 2000-01-01T00:00:00-06:00 (mounted as /)
  config = mkIf cfg.enable {
    boot.initrd.luks.devices.${cfg.target}.postOpenCommands = let
      fscryptctl = "${pkgs.fscryptctl}/bin/fscryptctl";
    in ''
      # FIXME: posiblemente algunos --make-* son innecesarios a partir de aquí
      mkdir -p /mnt-root /mnt-toplevel
      mount -o noatime /dev/mapper/${cfg.target} /mnt-toplevel
      mount --make-private /mnt-toplevel

      boot_stamp="$(date -Is)"
      root_from_toplevel="/mnt-toplevel/boots/$boot_stamp"

      mkdir -p "$root_from_toplevel" /mnt-toplevel/boot-keys
      chmod 700 /mnt-toplevel/boot-keys

      head -c64 /dev/urandom >/boot-key
      key_id=$(${fscryptctl} add_key /mnt-toplevel </boot-key)
      ${fscryptctl} set_policy "$key_id" "$root_from_toplevel"
      (umask 077; test -f /mnt-toplevel/boot-archive.pub && \
        ${getExe pkgs.rage} -ae \
          -R /mnt-toplevel/boot-archive.pub \
          -o "/mnt-toplevel/boot-keys/$boot_stamp.key.age" \
          /boot-key)
      rm -f /boot-key

      ln -Tsf "$boot_stamp" /mnt-toplevel/boots/last
      ln -Tsf "$boot_stamp.key.age" /mnt-toplevel/boot-keys/last.key.age

      mount --bind "$root_from_toplevel" /mnt-root
      mount --make-shared /mnt-root

      # mount --move es mala idea, ya que "moving a mount residing under a
      # shared mount is unsupported"
      mkdir -p /mnt-root/toplevel
      mount --bind /mnt-toplevel /mnt-root/toplevel
      mount --make-private /mnt-root/toplevel
      umount /mnt-toplevel
    '';

    fileSystems = {
      "/" = {
        device = "none";
        fsType = "ext4";
        options = ["remount"];
      };

      "/nix" = {
        device = "/persist/nix";
        options = ["bind"];
      };

      "/persist" = {
        device = "/toplevel/persist";
        options = ["bind"];
        neededForBoot = true;
      };
    };

    local.boot = {
      fscrypt.enable = true;
      impermanence.enable = true;
    };
  };
}