diff options
Diffstat (limited to 'os/srv/wireguard.nix')
| -rw-r--r-- | os/srv/wireguard.nix | 146 |
1 files changed, 143 insertions, 3 deletions
diff --git a/os/srv/wireguard.nix b/os/srv/wireguard.nix index 4b9dbc4..15675a4 100644 --- a/os/srv/wireguard.nix +++ b/os/srv/wireguard.nix @@ -1,9 +1,149 @@ -{ config, lib, ... }: +{ + config, + lib, + hostname, + masterDomain, + ... +}: let cfg = config.os.srv.wireguard; in { - options.os.srv.wireguard.enable = lib.mkEnableOption "enables wireguard vpn"; - config = lib.mkIf cfg.enable { + options.os.srv.wireguard = { + enable = lib.mkEnableOption "enables wireguard vpn"; + + role = lib.mkOption { + type = lib.types.enum [ + "server" + "client" + ]; + default = "client"; + description = "where the machine is accepting connections or connecting"; + }; + + server = { + externalInterface = lib.mkOption { + type = lib.types.str; + default = "eth0"; + description = "The public WAN interface of the server"; + }; + + peers = lib.mkOption { + type = lib.types.listOf ( + lib.types.submodule { + options = { + name = lib.mkOption { type = lib.types.str; }; + publicKey = lib.mkOption { type = lib.types.str; }; + }; + } + ); + default = [ ]; + description = "List of client peers authorized to connect to this server"; + }; + }; + + client = { + index = lib.mkOption { + type = lib.types.nullOr lib.types.int; + default = null; + description = "The assigned host index number for the client IP address"; + }; + + routeAllTraffic = lib.mkOption { + type = lib.types.bool; + default = false; + description = "Routes 100% of your internet traffic through the server when active"; + }; + }; }; + + config = lib.mkIf cfg.enable ( + lib.mkMerge [ + { + assertions = [ + { + assertion = config.os.srv.sops.enable; + message = "required for wg private key"; + } + ]; + + sops.secrets."wg_private_key/${hostname}" = { + owner = "root"; + group = "root"; + mode = "0600"; + }; + } + + (lib.mkIf (cfg.role == "server") { + assertions = [ + { + assertion = config.os.srv.firewall.enable; + message = "required for opening ports and passthrough"; + } + ]; + boot.kernel.sysctl."net.ipv4.ip_forward" = 1; + networking.firewall.allowedUDPPorts = [ 51280 ]; + + networking.nftables = { + tables.wg-nat = { + family = "inet"; + content = '' + chain forward { + type filter hook forward priority 0; policy accept; + iifname "wg0" accept + oifname "wg0" accept + } + + chain postrouting { + type nat hook postrouting priority 100; policy accept; + iifname "wg0" oifname "${cfg.server.externalInterface}" masquerade + } + ''; + }; + }; + + networking.wireguard.interfaces.wg0 = { + ips = [ "10.255.1.1/16" ]; + listenPort = 51280; + privateKeyFile = config.sops.secrets."wg_private_key/${hostname}".path; + + peers = lib.imap1 (i: peer: { + publicKey = peer.publicKey; + allowedIPs = [ "10.255.0.${toString i}/32" ]; + persistentKeepalive = 25; + }) cfg.server.peers; + }; + }) + + (lib.mkIf (cfg.role == "client") { + assertions = [ + { + assertion = cfg.client.index != null; + message = "WireGuard client role requires a valid 'client.index' integer designation."; + } + ]; + + networking.nameservers = [ + "10.255.1.1" + "9.9.9.9" + ]; + + networking.wireguard.interfaces.wg0 = { + ips = [ "10.255.0.${toString cfg.client.index}/16" ]; + privateKeyFile = config.sops.secrets."wg_private_key/${hostname}".path; + + peers = [ + { + # TODO get the server public key + publicKey = ""; + endpoint = "${masterDomain}:51280"; + persistentKeepalive = 25; + + allowedIPs = if cfg.client.routeAllTraffic then [ "0.0.0.0/0" ] else [ "10.255.0.0/16" ]; + } + ]; + }; + }) + ] + ); } |
