diff --git a/.gitattributes b/.gitattributes index dca0b4c..fdfc04b 100644 --- a/.gitattributes +++ b/.gitattributes @@ -1,3 +1,4 @@ secrets/**/*.secret filter=git-crypt diff=git-crypt secrets/matrix-email-config.nix filter=git-crypt diff=git-crypt +secrets/wireguard.nix filter=git-crypt diff=git-crypt home/secrets/*.secret filter=git-crypt diff=git-crypt diff --git a/README.org b/README.org index dc9d8ff..16dad36 100644 --- a/README.org +++ b/README.org @@ -42,3 +42,5 @@ RSS reader Grafana and Prometheus are currently used as a glorified =htop=. ** Nextcloud + +** Wireguard VPN diff --git a/hosts/boreal/default.nix b/hosts/boreal/default.nix index 2cb59ee..3ccfe73 100644 --- a/hosts/boreal/default.nix +++ b/hosts/boreal/default.nix @@ -32,6 +32,11 @@ in }; }; + services.tailscale = { + enable = true; + package = pkgs.unstable.tailscale; + }; + networking.hostName = "boreal"; # Define your hostname. networking.domain = "alarsyo.net"; @@ -82,7 +87,22 @@ in pipewire.enable = true; - tailscale.enable = true; + wireguard = { + enable = false; + iface = "wg"; + port = 51820; + + net = { + v4 = { + subnet = "10.0.0"; + mask = 24; + }; + v6 = { + subnet = "fd42:42:42"; + mask = 64; + }; + }; + }; }; services = { diff --git a/hosts/poseidon/default.nix b/hosts/poseidon/default.nix index b81dbf3..298f35d 100644 --- a/hosts/poseidon/default.nix +++ b/hosts/poseidon/default.nix @@ -21,6 +21,11 @@ in boot.supportedFilesystems = [ "btrfs" ]; + boot.kernel.sysctl = { + "net.ipv6.conf.all.forwarding" = true; + "net.ipv4.ip_forward" = true; + }; + services.btrfs = { autoScrub = { enable = true; @@ -28,6 +33,18 @@ in }; }; + services.tailscale = { + enable = true; + package = pkgs.unstable.tailscale; + }; + systemd.services.tailscaled = { + path = [ pkgs.procps ]; + }; + networking.firewall = { + trustedInterfaces = [ "tailscale0" ]; + allowedUDPPorts = [ config.services.tailscale.port ]; + }; + virtualisation.docker = { enable = true; }; @@ -123,8 +140,6 @@ in enable = true; }; - tailscale.enable = true; - tgv = { enable = true; }; @@ -134,6 +149,23 @@ in username = "alarsyo"; password = secrets.transmission-password; }; + + wireguard = { + enable = true; + iface = "wg"; + port = 51820; + + net = { + v4 = { + subnet = "10.0.0"; + mask = 24; + }; + v6 = { + subnet = "fd42:42:42"; + mask = 64; + }; + }; + }; }; # Enable the OpenSSH daemon. diff --git a/secrets/default.nix b/secrets/default.nix index 547eb06..9df6f72 100644 --- a/secrets/default.nix +++ b/secrets/default.nix @@ -18,6 +18,8 @@ with lib; borg-backup = import ./borg-backup { inherit lib; }; + wireguard = pkgs.callPackage ./wireguard.nix { }; + matrixEmailConfig = import ./matrix-email-config.nix; }; } diff --git a/secrets/wireguard.nix b/secrets/wireguard.nix new file mode 100644 index 0000000..3a19c05 Binary files /dev/null and b/secrets/wireguard.nix differ diff --git a/services/default.nix b/services/default.nix index 79b72f4..1761fc1 100644 --- a/services/default.nix +++ b/services/default.nix @@ -19,8 +19,8 @@ ./pipewire.nix ./postgresql-backup.nix ./postgresql.nix - ./tailscale.nix ./tgv.nix ./transmission.nix + ./wireguard.nix ]; } diff --git a/services/tailscale.nix b/services/tailscale.nix deleted file mode 100644 index 75fef50..0000000 --- a/services/tailscale.nix +++ /dev/null @@ -1,35 +0,0 @@ -{ config, lib, pkgs, ... }: - -with lib; - -let - cfg = config.my.services.tailscale; -in -{ - options.my.services.tailscale = { - enable = lib.mkEnableOption "Tailscale"; - }; - - config = mkIf cfg.enable { - services.tailscale = { - enable = true; - package = pkgs.unstable.tailscale; - }; - - # FIXME: remove when upgrading to 21.11, added to module by default - systemd.services.tailscaled = { - path = [ pkgs.procps ]; - }; - - networking.firewall = { - trustedInterfaces = [ "tailscale0" ]; - allowedUDPPorts = [ config.services.tailscale.port ]; - }; - - # enable IP forwarding to use as exit node - boot.kernel.sysctl = { - "net.ipv6.conf.all.forwarding" = true; - "net.ipv4.ip_forward" = true; - }; - }; -} diff --git a/services/wireguard.nix b/services/wireguard.nix new file mode 100644 index 0000000..9d13b55 --- /dev/null +++ b/services/wireguard.nix @@ -0,0 +1,122 @@ +# Stolen from: +# +# https://gitea.belanyi.fr/ambroisie/nix-config/src/branch/main/services/wireguard.nix + +{ config, lib, pkgs, ... }: +let + cfg = config.my.services.wireguard; + hostName = config.networking.hostName; + + peers = config.my.secrets.wireguard.peers; + thisPeer = peers."${hostName}"; + otherPeers = lib.filterAttrs (name: _: name != hostName) peers; + + extIface = config.my.networking.externalInterface; +in +{ + options.my.services.wireguard = with lib; { + enable = mkEnableOption "Wireguard VPN service"; + + iface = mkOption { + type = types.str; + default = "wg"; + example = "wg0"; + description = "Name of the interface to configure"; + }; + + port = mkOption { + type = types.port; + default = 51820; + example = 55555; + description = "Port to configure for Wireguard"; + }; + + net = { + v4 = { + subnet = mkOption { + type = types.str; + default = "10.0.0"; + example = "10.100.0"; + description = "Which prefix to use for internal IPs"; + }; + mask = mkOption { + type = types.int; + default = 24; + example = 28; + description = "The CIDR mask to use on internal IPs"; + }; + }; + v6 = { + subnet = mkOption { + type = types.str; + default = "fd42:42:42"; + example = "fdc9:281f:04d7:9ee9"; + description = "Which prefix to use for internal IPs"; + }; + mask = mkOption { + type = types.int; + default = 64; + example = 68; + description = "The CIDR mask to use on internal IPs"; + }; + }; + }; + }; + + config.networking = lib.mkIf cfg.enable { + wg-quick.interfaces."${cfg.iface}" = { + listenPort = cfg.port; + address = with cfg.net; with lib; [ + "${v4.subnet}.${toString thisPeer.clientNum}/${toString v4.mask}" + "${v6.subnet}::${toString thisPeer.clientNum}/${toHexString v6.mask}" + ]; + privateKey = thisPeer.privateKey; + + peers = lib.mapAttrsToList + (name: peer: { + inherit (peer) publicKey; + } // lib.optionalAttrs (thisPeer ? externalIp) { + # Only forward from server to clients + allowedIPs = with cfg.net; [ + "${v4.subnet}.${toString peer.clientNum}/32" + "${v6.subnet}::${toString peer.clientNum}/128" + ]; + } // lib.optionalAttrs (peer ? externalIp) { + # Known addresses + endpoint = "${peer.externalIp}:${toString cfg.port}"; + } // lib.optionalAttrs (!(thisPeer ? externalIp)) { + # Forward all traffic to server + allowedIPs = with cfg.net; [ + "0.0.0.0/0" + "::/0" + ]; + # Roaming clients need to keep NAT-ing active + persistentKeepalive = 10; + }) + otherPeers; + } // lib.optionalAttrs (thisPeer ? externalIp) { + # Setup forwarding on server + postUp = with cfg.net; '' + ${pkgs.iptables}/bin/iptables -A FORWARD -i ${cfg.iface} -j ACCEPT + ${pkgs.iptables}/bin/iptables -t nat -A POSTROUTING -s ${v4.subnet}.1/${toString v4.mask} -o ${extIface} -j MASQUERADE + ${pkgs.iptables}/bin/ip6tables -A FORWARD -i ${cfg.iface} -j ACCEPT + ${pkgs.iptables}/bin/ip6tables -t nat -A POSTROUTING -s ${v6.subnet}::1/${toString v6.mask} -o ${extIface} -j MASQUERADE + ''; + preDown = with cfg.net; '' + ${pkgs.iptables}/bin/iptables -D FORWARD -i ${cfg.iface} -j ACCEPT + ${pkgs.iptables}/bin/iptables -t nat -D POSTROUTING -s ${v4.subnet}.1/${toString v4.mask} -o ${extIface} -j MASQUERADE + ${pkgs.iptables}/bin/ip6tables -D FORWARD -i ${cfg.iface} -j ACCEPT + ${pkgs.iptables}/bin/ip6tables -t nat -D POSTROUTING -s ${v6.subnet}::1/${toString v6.mask} -o ${extIface} -j MASQUERADE + ''; + + }; + + nat = lib.optionalAttrs (thisPeer ? externalIp) { + enable = true; + externalInterface = extIface; + internalInterfaces = [ cfg.iface ]; + }; + + firewall.allowedUDPPorts = lib.optional (thisPeer ? externalIp) cfg.port; + }; +}