From 369cfec06d76aa8e34c394159fe4dfcb222334e2 Mon Sep 17 00:00:00 2001 From: Alexander Sieg Date: Sat, 9 Mar 2024 17:20:01 +0100 Subject: nixos/wg-access-server: init module --- nixos/modules/module-list.nix | 1 + .../services/networking/wg-access-server.nix | 124 +++++++++++++++++++++ nixos/tests/all-tests.nix | 1 + nixos/tests/wg-access-server.nix | 28 +++++ 4 files changed, 154 insertions(+) create mode 100644 nixos/modules/services/networking/wg-access-server.nix create mode 100644 nixos/tests/wg-access-server.nix (limited to 'nixos') diff --git a/nixos/modules/module-list.nix b/nixos/modules/module-list.nix index b20e98a9f229b..7022c36f31e2b 100644 --- a/nixos/modules/module-list.nix +++ b/nixos/modules/module-list.nix @@ -1222,6 +1222,7 @@ ./services/networking/vsftpd.nix ./services/networking/wasabibackend.nix ./services/networking/websockify.nix + ./services/networking/wg-access-server.nix ./services/networking/wg-netmanager.nix ./services/networking/webhook.nix ./services/networking/wg-quick.nix diff --git a/nixos/modules/services/networking/wg-access-server.nix b/nixos/modules/services/networking/wg-access-server.nix new file mode 100644 index 0000000000000..5876699924b22 --- /dev/null +++ b/nixos/modules/services/networking/wg-access-server.nix @@ -0,0 +1,124 @@ +{ config, pkgs, lib, ... }: +let + inherit (lib) mkEnableOption mkPackageOption mkOption types; + + cfg = config.services.wg-access-server; + + settingsFormat = pkgs.formats.yaml { }; + configFile = settingsFormat.generate "config.yaml" cfg.settings; +in +{ + + options.services.wg-access-server = { + enable = mkEnableOption "wg-access-server"; + + package = mkPackageOption pkgs "wg-access-server" { }; + + settings = mkOption { + type = lib.types.submodule { + freeformType = settingsFormat.type; + options = { + dns.enable = mkOption { + type = types.bool; + default = true; + description = '' + Enable/disable the embedded DNS proxy server. + This is enabled by default and allows VPN clients to avoid DNS leaks by sending all DNS requests to wg-access-server itself. + ''; + }; + storage = mkOption { + type = types.str; + default = "sqlite3://db.sqlite"; + description = "A storage backend connection string. See [storage docs](https://www.freie-netze.org/wg-access-server/3-storage/)"; + }; + }; + }; + description = "See https://www.freie-netze.org/wg-access-server/2-configuration/ for possible options"; + }; + + secretsFile = mkOption { + type = types.path; + description = '' + yaml file containing all secrets. this needs to be in the same structure as the configuration. + + This must to contain the admin password and wireguard private key. + As well as the secrets for your auth backend. + + Example: + ```yaml + adminPassword: + wireguard: + privateKey: + auth: + oidc: + clientSecret: + ``` + ''; + }; + }; + + config = lib.mkIf cfg.enable { + assertions = + map + (attrPath: + { + assertion = !lib.hasAttrByPath attrPath config.services.wg-access-server.settings; + message = '' + {option}`services.wg-access-server.settings.${lib.concatStringsSep "." attrPath}` must definded + in {option}`services.wg-access-server.secretsFile`. + ''; + }) + [ + [ "adminPassword" ] + [ "wireguard" "privateKey" ] + [ "auth" "sessionStore" ] + [ "auth" "oidc" "clientSecret" ] + [ "auth" "gitlab" "clientSecret" ] + ]; + + boot.kernel.sysctl = { + "net.ipv4.conf.all.forwarding" = "1"; + "net.ipv6.conf.all.forwarding" = "1"; + }; + + systemd.services.wg-access-server = { + description = "WG access server"; + wantedBy = [ "multi-user.target" ]; + requires = [ "network-online.target" ]; + after = [ "network-online.target" ]; + script = '' + # merge secrets into main config + yq eval-all "select(fileIndex == 0) * select(fileIndex == 1)" ${configFile} $CREDENTIALS_DIRECTORY/SECRETS_FILE \ + > "$STATE_DIRECTORY/config.yml" + + ${lib.getExe cfg.package} serve --config "$STATE_DIRECTORY/config.yml" + ''; + + path = with pkgs; [ + iptables + # needed by startup script + yq-go + ]; + + serviceConfig = + let + capabilities = [ + "CAP_NET_ADMIN" + ] ++ lib.optional cfg.settings.dns.enabled "CAP_NET_BIND_SERVICE"; + in + { + WorkingDirectory = "/var/lib/wg-access-server"; + StateDirectory = "wg-access-server"; + + LoadCredential = [ + "SECRETS_FILE:${cfg.secretsFile}" + ]; + + # Hardening + DynamicUser = true; + AmbientCapabilities = capabilities; + CapabilityBoundingSet = capabilities; + }; + }; + }; +} diff --git a/nixos/tests/all-tests.nix b/nixos/tests/all-tests.nix index 746b29fd27258..9f07fc9055ef6 100644 --- a/nixos/tests/all-tests.nix +++ b/nixos/tests/all-tests.nix @@ -1036,6 +1036,7 @@ in { wiki-js = handleTest ./wiki-js.nix {}; wine = handleTest ./wine.nix {}; wireguard = handleTest ./wireguard {}; + wg-access-server = handleTest ./wg-access-server.nix {}; without-nix = handleTest ./without-nix.nix {}; wmderland = handleTest ./wmderland.nix {}; workout-tracker = handleTest ./workout-tracker.nix {}; diff --git a/nixos/tests/wg-access-server.nix b/nixos/tests/wg-access-server.nix new file mode 100644 index 0000000000000..84fdf43e7943b --- /dev/null +++ b/nixos/tests/wg-access-server.nix @@ -0,0 +1,28 @@ +import ./make-test-python.nix ({ pkgs, lib, kernelPackages ? null, ... }: +{ + name = "wg-access-server"; + meta = with pkgs.lib.maintainers; { + maintainers = [ xanderio ]; + }; + + nodes = { + server = { + services.wg-access-server = { + enable = true; + settings = { + adminUsername = "admin"; + }; + secretsFile = (pkgs.writers.writeYAML "secrets.yaml" { + adminPassword = "hunter2"; + }); + }; + }; + }; + + testScript = '' + start_all() + + server.wait_for_unit("wg-access-server.service") + ''; +} +) -- cgit 1.4.1