summaryrefslogtreecommitdiff
path: root/os/kay/modules/network/headscale.nix
blob: 3e44108267620ab07d7f4251481b036a06d6de6f (plain) (blame)
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
141
142
143
144
145
146
147
148
149
150
151
152
{
  config,
  pkgs,
  lib,
  ...
}:
let
  url = "https://headscale.${config.global.userdata.domain}";
  stunPort = 3478;

  # A workaround generate a valid Headscale config accepted by Headplane when `config_strict == true`.
  settings = lib.recursiveUpdate config.services.headscale.settings {
    tls_cert_path = "/dev/null";
    tls_key_path = "/dev/null";
    policy.path = "/dev/null";
  };
  format = pkgs.formats.yaml { };
  headscaleConfig = format.generate "headscale.yml" settings;

  policyFormat = pkgs.formats.json { };
  policy = {
    groups = {
      "group:owner" = [ "sinan@" ];
      "group:bud" = [
        "sinan@"
        "ann@"
      ];
    };
    tagOwners = {
      "tag:bud_clients" = [ "group:bud" ];
      "tag:internal" = [ "group:owner" ];
      "tag:cusat" = [ "group:owner" ];
      "tag:gaijin" = [ "group:owner" ];
    };
    autoApprovers = {
      routes = {
        "192.168.43.0/24" = [
          "group:owner"
          "tag:internal"
        ];
        "192.168.38.0/24" = [
          "group:owner"
          "tag:internal"
        ];
      };
      exitNode = [
        "group:owner"
        "tag:internal"
      ];
    };
    acls = [
      {
        action = "accept";
        src = [ "group:owner" ];
        dst = [ "*:*" ];
      }

      {
        action = "accept";
        src = [ "group:bud" ];
        dst = [ "tag:bud_clients:*" ];
      }
    ];
  };
in
{
  sops.secrets = {
    # server
    "headplane/cookie_secret".owner = config.services.headscale.user;
    "headplane/preauth_key".owner = config.services.headscale.user;
    "headscale/noise_private_key".owner = config.services.headscale.user;
    "headscale/derp_private_key".owner = config.services.headscale.user;
    # client
    "headscale/pre_auth_key" = { };
  };

  networking.firewall = {
    interfaces.ppp0.allowedUDPPorts = [ stunPort ];
    trustedInterfaces = [ config.services.tailscale.interfaceName ];
  };

  services = {
    headscale = {
      enable = true;
      port = 8139;

      settings = {
        logtail.enabled = false;
        server_url = url;
        noise.private_key_path = config.sops.secrets."headscale/noise_private_key".path;
        dns = {
          base_domain = "tsnet.${config.global.userdata.domain}";
          override_local_dns = false;
        };
        derp = {
          server = {
            enabled = true;
            private_key_path = config.sops.secrets."headscale/derp_private_key".path;
            region_code = config.networking.hostName;
            region_name = config.networking.hostName;
            stun_listen_addr = "0.0.0.0:${toString stunPort}";
            region_id = 6969;
            automatically_add_embedded_derp_region = true;
          };
          urls = [ ];
        };
        policy = {
          mode = "file";
          path = policyFormat.generate "acl.json" policy;
        };
      };
    };

    headplane = {
      enable = true;
      settings = {
        server = {
          port = 8140;
          cookie_secret_path = config.sops.secrets."headplane/cookie_secret".path;
        };
        headscale = {
          inherit url;
          config_path = "${headscaleConfig}";
        };
        integration.agent = {
          enabled = true;
          pre_authkey_path = config.sops.secrets."headplane/preauth_key".path;
        };
      };
    };

    tailscale = {
      enable = true;
      interfaceName = "headscale";
      openFirewall = true;

      authKeyFile = config.sops.secrets."headscale/pre_auth_key".path;
      extraUpFlags = [
        "--login-server=${url}"
        "--advertise-exit-node"
        "--advertise-routes=192.168.43.0/24,192.168.38.0/24"
      ];
    };
  };

  boot.kernel.sysctl = {
    "net.ipv4.ip_forward" = true;
    "net.ipv6.conf.all.forwarding" = true;
  };

  environment.systemPackages = [ config.services.headscale.package ];
}