summaryrefslogtreecommitdiff
path: root/sys/boot/stack/luks-ext4-fscrypt-impermanence.nix
blob: 72336d6c04c8fe28903aecd68cd3049357b60644 (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
{ 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.crypt (encrypted for /toplevel/boot-archive.pub)
  #         - /toplevel/boot-keys/...
  #         - /toplevel/boot-keys/last.key.crypt -> 2000-01-01T00:00:00-06:00.key.crypt
  #       - /toplevel/boots
  #         - /toplevel/boots/2000-01-01T00:00:00-06:00 (raw protector in last.key.crypt)
  #         - /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 && \
          ${pkgs.openssl}/bin/openssl pkeyutl -encrypt \
          -in /boot-key -pubin -inkey /mnt-toplevel/boot-archive.pub \
          -out "/mnt-toplevel/boot-keys/$boot_stamp.key.crypt")
        rm -f /boot-key

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

        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;
    };
  };
}