summaryrefslogtreecommitdiffstats
path: root/modules/services/wireguard.nix
blob: 4d76a324cddecd85fc7a1a56b97d573c67e796b1 (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
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
{ config, lib, ... }:

let

  cfg = config.services.codewreck.wireguard;

in {
  options.services.codewreck.wireguard = {
    enabled = lib.mkOption {
      description = "enabled (on by default if local machine description is found, don't blame me if you enable it without one)";
      default = builtins.hasAttr cfg.hostname cfg.machines;
      type = lib.types.bool;
    };
    domain = lib.mkOption {
      description = "domain (used to shorten hosts for config and /etc/hosts";
      default = config.networking.domain;
      type = lib.types.str;
    };
    hostname = lib.mkOption {
      description = "short part of the hostname (select wireguard config from configs)";
      default = lib.removeSuffix ".${config.networking.domain}" config.networking.hostName;
      type = lib.types.str;
    };
    machines = lib.mkOption {
      description = "attr of machine configuration";
      default = {};
      example = {
        jormungand = {
          ip = "fd13:537e:dbbf:1210::1";
          endpoint = "jormungand.codewreck.org";
          listenPort = 51733;
          publicKey = "Hx5RnhfyP91LEgXAn4pLiOm4nMRZvVx+rsX0YhVzqAQ=";
        };
        odin = {
          ip = "fd13:537e:dbbf:1210::2";
          allowedIPs = [ "fd13:537e:dbbf:1211::/64" "10.17.42.0/24" ];
          endpoint = "gaia.codewreck.org";
          listenPort = 51432;
          publicKey = "7YALjkbDv6iId1VHJu4uTgVAj41VvAoQfaiVChJdZQ8=";
        };
        fenrir = {
          ip = "fd13:537e:dbbf:1210::3";
          allowedIPs = [ "fd13:537e:dbbf:1213::/64" "10.42.17.0/24" ];
          publicKey = "SrLUKqoxYxFriLDenMwNHLqetxVCLmyCG606hg3h9mQ=";
          listenPort = 51123;
          keepalive = 55;
        };
      };
      type = lib.types.attrsOf (lib.types.submodule { options = {
        ip = lib.mkOption {
          description = "ip is used both to configure interface if target and for allowed IPs";
          type = lib.types.str;
        };
        allowedIPs = lib.mkOption {
	  description = "extra list of allowed IPs for wg";
          default = [];
          type = lib.types.listOf lib.types.str;
        };
        publicKey = lib.mkOption {
          description = "wg public key";
          type = lib.types.str;
        };
        listenPort = lib.mkOption {
          description = "wg port (actual listen-port, firewall and endpoint)";
          type = lib.types.int;
        };
        endpoint = lib.mkOption {
          description = "wg endpoint without port component (taken from mandatory listenPort)";
          default = null;
          type = lib.types.nullOr lib.types.str;
        };
        keepalive = lib.mkOption {
          description = "wg keepalive for all peers if present on current machine";
          default = null;
          type = lib.types.nullOr lib.types.int;
        };
        only = lib.mkOption {
          description = "limit to single server";
          default = null;
          type = lib.types.nullOr lib.types.str;
        };
      };});
    };
  };

  config = let
    current = builtins.getAttr cfg.hostname cfg.machines;
    others = builtins.removeAttrs cfg.machines [ cfg.hostname ];
    peers = lib.mapAttrsToList (name: value: {
      allowedIPs = [ value.ip ] ++ value.allowedIPs;
      publicKey = value.publicKey;
      endpoint = (if value.endpoint != null then value.endpoint + ":" + (toString value.listenPort) else null);
      persistentKeepalive = current.keepalive;
    }) (lib.filterAttrs (n: v:
        current.only == n
        || (current.only == null &&
          (v.endpoint != null ||
            (current.endpoint != null && (v.only == null || v.only == cfg.hostname))
          )
        ))
        others);

    hosts = lib.mapAttrs' (name: value: lib.attrsets.nameValuePair
      (builtins.head (builtins.split "/" value.ip)) [ (name + ".wg.${cfg.domain}") (name + ".wg") ]
    ) others;
  in
    lib.mkIf cfg.enabled {
      networking.wireguard.interfaces.wg0 = {
        ips = [ current.ip ];
        listenPort = current.listenPort;
        privateKeyFile = "/etc/nixos/secrets/wg0.key";
        peers = peers;
      };
      networking.hosts = hosts;
      networking.firewall.allowedUDPPorts = [ current.listenPort ];
    };
}