summaryrefslogtreecommitdiff
path: root/os/srv/wireguard.nix
diff options
context:
space:
mode:
Diffstat (limited to 'os/srv/wireguard.nix')
-rw-r--r--os/srv/wireguard.nix146
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" ];
+ }
+ ];
+ };
+ })
+ ]
+ );
}