diff --git a/options/default.nix b/options/default.nix index 799b016..bfab333 100644 --- a/options/default.nix +++ b/options/default.nix @@ -14,6 +14,10 @@ hostname = lib.mkOption { type = lib.types.str; }; + networking.externalInterface = lib.mkOption { + type = lib.types.str; + default = "eth0"; + }; user = { name = lib.mkOption { diff --git a/options/services.nix b/options/services.nix index db8cab6..cfb1037 100644 --- a/options/services.nix +++ b/options/services.nix @@ -11,5 +11,6 @@ in samba.enable = mkEnableOption "samba"; nextcloud.enable = mkEnableOption "nextcloud"; syncthing.enable = mkEnableOption "syncthing"; + openvpn.enable = mkEnableOption "openvpn"; }; } diff --git a/profiles/homeserver.nix b/profiles/homeserver.nix index 8604d7f..4dc0b5d 100644 --- a/profiles/homeserver.nix +++ b/profiles/homeserver.nix @@ -6,6 +6,7 @@ profile = { hostname = "homeserver"; + networking.externalInterface = "enp9s0"; user = { name = "homeserver"; fullName = "Homeserver"; @@ -33,6 +34,7 @@ samba.enable = true; nextcloud.enable = true; syncthing.enable = true; + openvpn.enable = true; }; }; } diff --git a/secrets/openvpn.yaml b/secrets/openvpn.yaml new file mode 100644 index 0000000..595a991 --- /dev/null +++ b/secrets/openvpn.yaml @@ -0,0 +1,24 @@ +openvpn: + key: + phone: ENC[AES256_GCM,data:JobVqgDl1Lk8jsIPeJgfA3tuMY1IHkTL2+rWY8CQkyJ9Q+dLIS8hMrmlqhtfiEkaWs3NFqwFuyUhK8uuOa0stBzQ/lZiQ7OKjOH8Y3d4fs6sF/FCuaVOuwfAXNy2gVEG2HgKBzFkBT/ciFxF3guy2EVNaLZCm01PaA8XMr8piXDs6lqt/YoEUNr2l+LfOsphrxLCYpGxRJxJkUWjoNGm/ZtbxI/HFO94l9JAlSoCfETqgEgWOOP3OgGKFSjr6pVty5Nw6iKHnhzFYdXyPFy67MPK9NvLWM3sAZnKrmF+B6lUFGAyZwKDwenKbjM/e5VOZrEGjj7O7EgMG7tYkbPngCPvRhQ4URIibKhKlmuP/On2WuJsNhNW7mtGMAKps0Q3B9GVAWeEGAhJUo5Y3FHGtSs0dRglAo6DCB0bgSTpa87LmY0JskW+PXCTQzJgVd6EnqL+ewMXM+1ID9upedivBZpTPbN41KAz9pCa/EziSsz7vEijq1i40RS/TTvjAC2SJkiv0tCmM7/jAoPDd/N4l7doqhk8jvokGw2PBmYkxnhPo0B2Ofhx+td/Pe/Q1fDHt42POTQ1EEuptD+utvPZUdLaOGg2ybiEYn8lsB9oEK4tVZoPaxOqHPlckSOcnTjwLmQ8M2Nf5e+iW74w+dfJrXuSz15XMSGthWmYHNPZGYo24+437HcVpEs2txcysK003PTy62X56jB5Wrv3l8rqqufVeMZDgLqo3Lw3btniFs6b3lJp1+dvYwGFXBhMeOuoannOi0bQvtIwxqTYgovHv+7/HPD06Hg9ZuU6/Lip3Vp/XR0kT3IfU7S0rmxTSVdgmlJbY8IM5VDMJTk=,iv:y6rP58/eIdMOWK1KsIYOL3pve4ew8mLQZBmIWjVWRCM=,tag:PlUTapNdWwkVKqy2yzLTdQ==,type:str] + laptop: ENC[AES256_GCM,data:n6atoq4XVXd8xBdXpmlrZ1ZCB3dsuwJ7XUUEJeoFmxkLoT8b+A/SrEo3Cp0xaU7pwMmWZvWBj0trTGlodFM07b+rrpPHiYSPrZkKOSYTx4kj7s6jf2Fu/514fsNS76+hEu3Iof3Bxw+LhEQ3jL1Bd1lYU0+x5bh0b3JSl71VDto40VBoiM1UdQtO54XlfsfKJC9Qy6asWqDUIEpU4L4JElfFXNO9fWSUbHQX1m5UWLaZpAcAwcJknnpdr8MJPbaE2LLf9gddEoEYqZqeDcrxlWuVavgzqCwCdCHuwecmiF/Luvx1F1/O+btG0z2Iz7UzvZKjGONUV0lNE1aJiCLZhNdFluHiv+hTmjU4GRiUe2GJFACOp624GtSENrafnFV8m+cLYqrMnmCByk5FoW1CQ4Clm0txbIRRHG1zZcrwf8G/S0VAJ0CMeEHZJoe6Adh0a/BdxWaLvexxl2OQBAhv0KiISfkp5oU3RPIo5ITrNE06fXXRiVXUiB3YXV+tOUmfUzTqBBLwOiS2yT2ggRxS9j8cWvNpQJFQB0zfYE3Q9TNdzvItXD/0TtGfxC/hBEorjqQEeFrVg60qbV3m8pxZMcCSUK/2+fBrBmuJsZ6KkEX1mqMP+QLg8JyAX8Eyn3FI+EPbcoHTrTts0hrOUbSwKQjJiN3nwOm9iGB2u8q3xUUo8uV4Bx9tyVpZPmeTS3S9aA8md2UnwUHQLd+DsKtdgFMUeW7ynZKGVesi+Tf5TEkw39/zhUor/JbwoXBlKLmPNs+X3a50yr22uRqyQ0rC7WQ2DfR5cXTgS2itcFC/iyUdB0DolDX49flK3Wyr4+taMVA7nf0qnbfMmus=,iv:s8yYzh/sF2Nb+fnr+/X9GhGCg2Ft/bNJk5L+FQhG3nU=,tag:NT7jH148RvcjnmsarL9qZQ==,type:str] +sops: + kms: [] + gcp_kms: [] + azure_kv: [] + hc_vault: [] + age: + - recipient: age1kruum2varzua7w5n6n52vhwyek2arc685rhcwt0u7k2jf5mecsjslkl9ll + enc: | + -----BEGIN AGE ENCRYPTED FILE----- + YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBtbnpHV0dlaWxXSDNnYnBa + NDhaMWdEMDB2allPUm9MUll0QVNWUmNNZlN3CkUxNFF6YmMxMjdWRDlMMTNHZUNq + YVJDQWZWT1pVWkFDMVA1ank1amUySjQKLS0tIEs2SFNWTEhLRjdaM2sya3FmYVdP + NmVZSk5jUUs3ZnhCTC9NOEQ1WkRJem8KvwC+Tc67NgV6rJM9vdfWbVaJSrX7xZS4 + aRvTzGL4Q2e+BnrFcyX8QiiZFgEUGEbk6MYbPELeGapwW79WvHzP8A== + -----END AGE ENCRYPTED FILE----- + lastmodified: "2024-06-14T06:31:34Z" + mac: ENC[AES256_GCM,data:dbnrwOcg8HrzIvG42rUAX9/p3/SfRlHA6ReMKFtVXESIvIrwfagbFPO8I5CspMyy/sqNhxPj2Pe05oBP6193SbfTTrKFVO+7X7085G2Yl/8EJD89a9hQN94SfzAqGs4NQHUI/YlO+piVLeVklhRhu+rwFnOmQ72nwVo+GKR/Rw0=,iv:A0oX4yu70ufZogYnTmewa5/w7W55BEsl4h1ppbd/Qwk=,tag:aVuwzS4I8nRVNIcXiFQOJA==,type:str] + pgp: [] + unencrypted_suffix: _unencrypted + version: 3.8.1 diff --git a/system/services/default.nix b/system/services/default.nix index d4b9140..492e9ee 100644 --- a/system/services/default.nix +++ b/system/services/default.nix @@ -8,5 +8,6 @@ ./nextcloud.nix ./syncthing.nix ./kavita.nix + ./openvpn.nix ]; } diff --git a/system/services/openvpn.nix b/system/services/openvpn.nix new file mode 100644 index 0000000..87e71bc --- /dev/null +++ b/system/services/openvpn.nix @@ -0,0 +1,124 @@ +# It's a pain setting up Certificate Authority, Public Key Infrastructure, etc. for OpenVPN. +# Instead setup multiple openvpn servers with multiple ports, with each server having one client. +# +# Does not scale well, but it's good enough for personal use. +# +# TODO: Create CA, and ROOTCA, and use them to sign the keys, then store in sops-nix secrets. + + +{ config, lib, pkgs, ... }: +let + cfg = config.profile.services.openvpn; + domain = "vpn.tigor.web.id"; + portLaptop = 1194; + portPhone = 1195; + vpn-dev-laptop = "tun0"; + vpn-dev-phone = "tun1"; + externalInterface = config.profile.networking.externalInterface; + inherit (lib) mkIf; +in +{ + config = mkIf cfg.enable { + environment.systemPackages = [ pkgs.openvpn ]; # To generate keys with openvpn --genkey --secret .key + + networking.nat = { + enable = true; + inherit externalInterface; + internalInterfaces = [ vpn-dev-laptop vpn-dev-phone ]; + }; + + networking.firewall.trustedInterfaces = [ vpn-dev-laptop vpn-dev-phone ]; + networking.firewall.allowedUDPPorts = [ portLaptop portPhone ]; + + sops = { + # Activate the secrets. + secrets = + let + opts = { + sopsFile = ../../secrets/openvpn.yaml; + }; + in + { + "openvpn/key/phone" = opts; + "openvpn/key/laptop" = opts; + }; + + # This section creates .ovpn files for the clients in /etc/openvpn folder. These should be shared with the clients. + templates = + let + template = { placeholder, port, ifConfig }: '' + dev tun + remote "${domain}" + port ${toString port} + ifconfig ${ifConfig} + redirect-gateway def1 + + cipher AES-256-CBC + auth-nocache + + comp-lzo + keepalive 10 60 + resolv-retry infinite + nobind + persist-key + persist-tun + secret [inline] + + + ${placeholder} + + ''; + in + { + "openvpn/key/phone" = { + content = template { + placeholder = config.sops.placeholder."openvpn/key/phone"; + port = portPhone; + ifConfig = "10.8.1.1 10.8.1.2"; + }; + path = "/etc/openvpn/phone.ovpn"; + owner = config.profile.user.name; + }; + "openvpn/key/laptop" = { + content = template { + placeholder = config.sops.placeholder."openvpn/key/laptop"; + port = portLaptop; + ifConfig = "10.8.2.1 10.8.2.2"; + }; + path = "/etc/openvpn/laptop.ovpn"; + owner = config.profile.user.name; + }; + }; + }; + services.openvpn.servers = + let + configTemplate = { secretFile, port, dev }: '' + dev ${dev} + proto udp + secret ${secretFile} + port ${toString port} + + cipher AES-256-CBC + auth-nocache + + comp-lzo + keepalive 10 60 + ping-timer-rem + persist-tun + persist-key + ''; + in + { + phone = { + config = configTemplate { secretFile = config.sops.secrets."openvpn/key/phone".path; port = portPhone; dev = vpn-dev-phone; }; + autoStart = true; + }; + laptop = { + config = configTemplate { secretFile = config.sops.secrets."openvpn/key/laptop".path; port = portLaptop; dev = vpn-dev-laptop; }; + autoStart = true; + }; + }; + }; +} + +