diff --git a/options/services.nix b/options/services.nix index f6c5cf4..3800bcd 100644 --- a/options/services.nix +++ b/options/services.nix @@ -15,5 +15,6 @@ in stubby.enable = mkEnableOption "stubby"; jellyfin.enable = mkEnableOption "jellyfin"; rust-motd.enable = mkEnableOption "rust-motd"; + wireguard.enable = mkEnableOption "wireguard"; }; } diff --git a/profiles/homeserver.nix b/profiles/homeserver.nix index b6d65fd..e5a7606 100644 --- a/profiles/homeserver.nix +++ b/profiles/homeserver.nix @@ -45,10 +45,11 @@ samba.enable = true; nextcloud.enable = true; syncthing.enable = true; - openvpn.enable = true; + openvpn.enable = false; stubby.enable = true; jellyfin.enable = true; rust-motd.enable = true; + wireguard.enable = true; }; }; } diff --git a/secrets/wireguard.yaml b/secrets/wireguard.yaml new file mode 100644 index 0000000..4e49e46 --- /dev/null +++ b/secrets/wireguard.yaml @@ -0,0 +1,25 @@ +wireguard: + private_keys: + server: ENC[AES256_GCM,data:YMk7ovSiX+vWsTEw1pwVLnLXTxFZwNbAlc9jdOamMJ3RwRePI1gpocg6ygQ=,iv:KteQl87XR6qs8uGX6v5AcSkl/X9/U5HvsDTqQx5ewCc=,tag:bERlujgiMOCfU9PzgFyUaQ==,type:str] + laptop: ENC[AES256_GCM,data:IuXyPe8WoiJ5eU4YCurSIQm9KfnM7isu3lgMuEnwDUDBG6YVtQxaEe2DAa4=,iv:leaYu6Wn/SanZp9//6/ssiFcUq2Z2lIrTP+NkXgdjZ8=,tag:7eSmYjs+y7qnnqfZMFZWfg==,type:str] + phone: ENC[AES256_GCM,data:n/RpqkgQ8NsuPf/K4aWhkxKlJ7KQJ3ogy+sihS/BeU5/NlrqTC7Qc7SJzdU=,iv:oZCTSnSl4IYQEBM514e6dn+HqyBK5IoHjPJ2l2ekBps=,tag:Ld1TzK/65kHkaW9qnvWmlQ==,type:str] +sops: + kms: [] + gcp_kms: [] + azure_kv: [] + hc_vault: [] + age: + - recipient: age1kruum2varzua7w5n6n52vhwyek2arc685rhcwt0u7k2jf5mecsjslkl9ll + enc: | + -----BEGIN AGE ENCRYPTED FILE----- + YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSB0ODgrS1Y1dERLWWFEYTBY + Ti9zTWYwdlBhVlJIM3hLVUt4TzdmRUZTakRjCkVMOEhQbHBua0JNRVNGbEJJZ2hW + RDhRYzhKWFlDTjJwS0ZCRzA1RFBtY1EKLS0tIGJGcCszd1VaM1NMdnRuazgzT3ox + U3MwaXpzNjZMdjY2UFhOM3dmdUdXdXcKp+1e2vPXL9xoNzepobH8Z23YaAxmOV44 + 9KYdsjudhLSSbQvVpvSca++WChWlMNHNq+5PgLy7uinP5lOocQUajQ== + -----END AGE ENCRYPTED FILE----- + lastmodified: "2024-06-23T12:13:05Z" + mac: ENC[AES256_GCM,data:DaLwpgmaRkiNM4AjbDxf2fH8dbGZ8DKx8rAoyJNnvTVlO4bKt31/yMGeCH6VW0SC0RApRc8NrBgdH3uYHAsSxDlwj/eXXVDAPrjjAhXTmABPGXLtMIK0LYhfq4nu5d5zsIaV1vrAsAmjcSm35FrttYsPMpL7V00Ah3pOlo6UCSA=,iv:qZlM2cgeWSWSKEVZJzojOk4cCWeG3GHD9axwi2WSeFQ=,tag:pbUwOBytwNuFmABuICYa9Q==,type:str] + pgp: [] + unencrypted_suffix: _unencrypted + version: 3.8.1 diff --git a/system/services/default.nix b/system/services/default.nix index c2dcec0..0d7ca99 100644 --- a/system/services/default.nix +++ b/system/services/default.nix @@ -12,5 +12,6 @@ ./samba.nix ./stubby.nix ./syncthing.nix + ./wireguard.nix ]; } diff --git a/system/services/syncthing.nix b/system/services/syncthing.nix index 10aa012..a158cc7 100644 --- a/system/services/syncthing.nix +++ b/system/services/syncthing.nix @@ -73,6 +73,11 @@ in id = "OpenVPN"; devices = lib.attrsets.mapAttrsToList (key: _value: key) config.services.syncthing.settings.devices; }; + "/nas/Syncthing/Sync/WireGuard" = { + label = "WireGuard"; + id = "WireGuard"; + devices = lib.attrsets.mapAttrsToList (key: _value: key) config.services.syncthing.settings.devices; + }; }; devices = { s20fe = { diff --git a/system/services/wireguard.nix b/system/services/wireguard.nix new file mode 100644 index 0000000..84272b3 --- /dev/null +++ b/system/services/wireguard.nix @@ -0,0 +1,114 @@ +{ config, lib, pkgs, ... }: +let + cfg = config.profile.services.wireguard; + externalInterface = config.profile.networking.externalInterface; + devices = [ + { + name = "phone"; + ip = "10.100.0.2"; + secret = "wireguard/private_keys/phone"; + publicKey = "27GSz9iWqtg23sWcwIQI3VglNtE/RWykv+nZUrmHHxA="; + } + { + name = "laptop"; + ip = "10.100.0.3"; + secret = "wireguard/private_keys/laptop"; + publicKey = "5nporvzbJtTQC9Hek8JBJNIF+wGlWUj4En2w9DrvaV0="; + } + ]; + serverPublicKey = "GDRUvnKUPNzwAloQ5fxvdHoVw4D1YbdCR0GyiOyyB38="; + sopsFile = ../../secrets/wireguard.yaml; + inherit (lib) mkIf mergeAttrsList generators; +in +{ + config = mkIf cfg.enable { + sops.secrets = mergeAttrsList ([ + { + "wireguard/private_keys/server" = { inherit sopsFile; }; + } + ] ++ + (map (device: { ${device.secret} = { inherit sopsFile; }; }) devices) + ); + + sops.templates = + let + template = { privateKey, ip }: + # '' + # [Interface] + # Address = ${ip}/32 + # PrivateKey = ${privateKey} + # DNS = 192.168.100.3 + # + # [Peer] + # PublicKey = ${serverPublicKey} + # Endpoint = vpn.tigor.web.id:51820 + # AllowedIPs = 0.0.0.0/0, ::/0 + # ''; + generators.toINI ({ }) { + Interface = { + Address = "${ip}/32"; + PrivateKey = privateKey; + DNS = "192.168.100.3"; + }; + + Peer = { + PublicKey = serverPublicKey; + Endpoint = "vpn.tigor.web.id:51820"; + AllowedIPs = "0.0.0.0/0, ::/0"; + }; + }; + in + mergeAttrsList (map + (device: { + "wireguard/clients/${device.name}" = { + content = template { + privateKey = config.sops.placeholder.${device.secret}; + ip = device.ip; + }; + path = "/nas/Syncthing/Sync/WireGuard/${device.name}.conf"; + owner = config.profile.user.name; + }; + }) + devices + ); + + networking = { + nat = { + enable = true; + inherit externalInterface; + internalInterfaces = [ "wg0" ]; + }; + firewall.allowedUDPPorts = [ 51820 ]; + + wireguard.interfaces = { + wg0 = { + # Determines the IP address and subnet of the server's end of the tunnel interface. + ips = [ "10.100.0.1/16" ]; + + # The port that WireGuard listens to. Must be accessible by the client. + listenPort = 51820; + + # This allows the wireguard server to route your traffic to the internet and hence be like a VPN + # For this to work you have to set the dnsserver IP of your router (or dnsserver of choice) in your clients + postSetup = '' + ${pkgs.iptables}/bin/iptables -t nat -A POSTROUTING -s 10.100.0.0/16 -o ${externalInterface} -j MASQUERADE + ''; + + # This undoes the above command + postShutdown = '' + ${pkgs.iptables}/bin/iptables -t nat -D POSTROUTING -s 10.100.0.0/16 -o ${externalInterface} -j MASQUERADE + ''; + + privateKeyFile = config.sops.secrets."wireguard/private_keys/server".path; + + peers = map + (device: { + publicKey = device.publicKey; + allowedIPs = [ device.ip ]; + }) + devices; + }; + }; + }; + }; +}