about summary refs log tree commit diff
path: root/modules/tailscale-initrd.nix
blob: 4b7610ef9e665314f16c1b8c6b8f7c4869d68fe1 (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
# To set this up, first get tailscale working in an isolated linux shell:
#  1. sudo systemctl stop tailscaled.service
#  2. tailscaled -port 9993 -state tailscale-luks-setup.state -tun userspace-networking -socket ./tailscaled.sock
#  3. tailscale -socket ./tailscaled.sock up -hostname HOSTNAME-luks
#  4. tailscale -socket ./tailscaled.sock down
#  5. ctrl-c out of tailscaled
#  6 sudo systemctl start tailscaled.service
#
# Then add the .state file to your machine secrets and pass its path as tailscaleStatePath.

{ config, lib, pkgs, ... }: {
  options = {
    modules.tailscale-initrd = with lib; {
      enable = mkOption {
        description = "Turn on unlock via tailscale";
        default = false;
      };

      tailscaleStatePath = mkOption {
        description = "Pre-initialized tailscale state file as a secret. Make sure to set it to not require re-authentication, otherwise the machine may not boot up after a few weeks.";
      };
    };
  };

  config =
    let
      cfg = config.modules.tailscale-initrd;
      # TODO: This uses old-style non-nftables iptables; ideally, we wouldn't have to opt out of that.
      # Enabling nftables compat means having to shuffle the list of
      # modules down in availableKernelModules; that's a bunch of work
      # (deploying to a linux machine & rebooting to see what doesn't
      # work this time), so I'm a bit too lazy for that now.
      iptables-static = (pkgs.iptables.override { nftablesCompat = false; }).overrideAttrs (old: {
        dontDisableStatic = true;
        configureFlags = (lib.remove "--enable-shared" old.configureFlags) ++ [
          "--enable-static"
          "--disable-shared"
        ];
      });
    in
    lib.mkIf cfg.enable {
      boot.initrd = {
        secrets = {
          "/var/lib/tailscale/tailscaled.state" = cfg.tailscaleStatePath;
          "/etc/ssl/certs/ca-certificates.crt" = "${pkgs.cacert}/etc/ssl/certs/ca-bundle.crt";
          "/etc/ssl/certs/ca-bundle.crt" = "${pkgs.cacert}/etc/ssl/certs/ca-bundle.crt";
        };
        network = {
          enable = true;
          flushBeforeStage2 = true;
          postCommands = ''
            # Bring up tailscaled and dial in
            echo 'nameserver 8.8.8.8' > /etc/resolv.conf
            mkdir /dev/net
            mknod /dev/net/tun c 10 200
            .tailscaled-wrapped 2>/dev/null &
            sleep 5
            .tailscale-wrapped up
            .tailscale-wrapped status

            echo "echo 'Use cryptsetup-askpass to unlock!'" >> /root/.profile
          '';
        };
        availableKernelModules = [
          "ip6_tables"
          "ip6table_filter"
          "ip6table_nat"
          "ip6table_raw"
          "ip_tables"
          "iptable_filter"
          "iptable_nat"
          "iptable_raw"
          "nf_conntrack"
          "nf_nat"
          "tun"
          "xt_comment"
          "xt_conntrack"
          "xt_mark"
          "xt_MASQUERADE"
          "xt_LOG"
          "xt_tcpudp"
        ];
        extraUtilsCommands = ''
          copy_bin_and_libs ${pkgs.tailscale}/bin/.tailscaled-wrapped
          copy_bin_and_libs ${pkgs.tailscale}/bin/.tailscale-wrapped
          copy_bin_and_libs ${pkgs.iproute}/bin/ip
          copy_bin_and_libs ${iptables-static}/bin/iptables
          copy_bin_and_libs ${iptables-static}/bin/xtables-legacy-multi

          copy_bin_and_libs ${pkgs.strace}/bin/strace
        '';
        postMountCommands = ''
          # tear down tailscale
          pkill .tailscaled-wrapped
          .tailscaled-wrapped --cleanup
        '';
      };
    };
}