diff --git a/configs/nixos/plover/modules/services/vaultwarden.nix b/configs/nixos/plover/modules/services/vaultwarden.nix index 7c726bf8..4a7d7727 100644 --- a/configs/nixos/plover/modules/services/vaultwarden.nix +++ b/configs/nixos/plover/modules/services/vaultwarden.nix @@ -10,22 +10,22 @@ let # This should be set from service module from nixpkgs. vaultwardenUser = config.users.users.vaultwarden.name; - - # However, this is set on our own. - vaultwardenDbName = "vaultwarden"; -in -{ +in { options.hosts.plover.services.vaultwarden.enable = lib.mkEnableOption "Vaultwarden instance"; config = lib.mkIf cfg.enable (lib.mkMerge [ { - state.ports.vaultwarden.value = 8222; - - sops.secrets = foodogsquaredLib.sops-nix.getSecrets ../../secrets/secrets.yaml { - "vaultwarden/env".owner = vaultwardenUser; + state.ports = { + vaultwarden.value = 8222; + vaultwarden-webproxy.value = 3012; }; + sops.secrets = + foodogsquaredLib.sops-nix.getSecrets ../../secrets/secrets.yaml { + "vaultwarden/env".owner = vaultwardenUser; + }; + services.vaultwarden = { enable = true; environmentFile = config.sops.secrets."vaultwarden/env".path; @@ -52,7 +52,7 @@ in # Notifications... WEBSOCKET_ENABLED = true; - WEBSOCKET_PORT = 3012; + WEBSOCKET_PORT = config.state.ports.vaultwarden-webproxy.value; WEBSOCKET_ADDRESS = "0.0.0.0"; # Enabling web vault with whatever nixpkgs comes in. @@ -60,78 +60,29 @@ in }; }; - # We do a little service hardening. Even though the Vaultwarden NixOS - # module is already doing some of those things, we'll just add some of - # them. - systemd.services.vaultwarden = { - serviceConfig = lib.mkAfter { - LockPersonality = true; - NoNewPrivileges = true; - RestrictSUIDSGID = true; - RestrictRealtime = true; - ProtectClock = true; - ProtectKernelLogs = true; - ProtectKernelTunables = true; - ProtectKernelModules = true; - ProtectHostname = true; - ProtectControlGroups = true; - ProtectProc = "invisible"; - - # Filtering system calls. - SystemCallFilter = [ - "@system-service" - "~@privileged" - ]; - SystemCallErrorNumber = "EPERM"; - SystemCallArchitectures = "native"; - - # Restricting what capabilities it has access to which it - # has none. - CapabilityBoundingSet = [ "" ]; - AmbientCapabilities = lib.mkForce [ "" ]; - - # Restrict what address families this service can interact - # with. Since it is a web service, we expect it will only - # interact with web service stuff like IPs. - RestrictAddressFamilies = [ - # It's required especially it can communicate with the local system. - "AF_LOCAL" - - # The IPs. - "AF_INET" - "AF_INET6" - ]; - - # Restrict what namespaces it can create which is none. - RestrictNamespaces = true; - }; - }; + systemd.services.vaultwarden.path = [ pkgs.system-sendmail ]; } (lib.mkIf hostCfg.services.database.enable { services.vaultwarden = { dbBackend = "postgresql"; - config.DATABASE_URL = "postgresql://${vaultwardenUser}@/${vaultwardenDbName}"; + config.DATABASE_URL = "postgresql://"; }; services.postgresql = { - ensureDatabases = [ vaultwardenDbName ]; + ensureDatabases = [ vaultwardenUser ]; ensureUsers = lib.singleton { name = vaultwardenUser; ensureDBOwnership = true; }; }; - systemd.services.vaultwarden = { - path = [ config.services.postgresql.package ]; - - # Making it comply with PostgreSQL secure schema usage pattern. - preStart = lib.mkAfter '' - # Setting up the appropriate schema for PostgreSQL secure schema usage. - psql -tAc "SELECT 1 FROM information_schema.schemata WHERE schema_name='${vaultwardenUser}';" \ - | grep -q 1 || psql -tAc "CREATE SCHEMA IF NOT EXISTS AUTHORIZATION ${vaultwardenUser};" - ''; - }; + systemd.services.vaultwarden.preStart = let + psql = lib.getExe' config.services.postgresql.package "psql"; + schema = config.users.users.vaultwarden.name; + in lib.mkBefore '' + ${psql} -tAc "CREATE SCHEMA IF NOT EXISTS AUTHORIZATION ${schema};" + ''; }) (lib.mkIf hostCfg.services.reverse-proxy.enable { @@ -140,27 +91,25 @@ in enableACME = true; acmeRoot = null; kTLS = true; - locations = - let - address = config.services.vaultwarden.config.ROCKET_ADDRESS; - websocketPort = config.services.vaultwarden.config.WEBSOCKET_PORT; - in - { - "/" = { - proxyPass = "http://vaultwarden"; - proxyWebsockets = true; - }; - - "/notifications/hub" = { - proxyPass = "http://${address}:${toString websocketPort}"; - proxyWebsockets = true; - }; - - "/notifications/hub/negotiate" = { - proxyPass = "http://vaultwarden"; - proxyWebsockets = true; - }; + locations = let + address = config.services.vaultwarden.config.ROCKET_ADDRESS; + websocketPort = config.services.vaultwarden.config.WEBSOCKET_PORT; + in { + "/" = { + proxyPass = "http://vaultwarden"; + proxyWebsockets = true; }; + + "/notifications/hub" = { + proxyPass = "http://${address}:${toString websocketPort}"; + proxyWebsockets = true; + }; + + "/notifications/hub/negotiate" = { + proxyPass = "http://vaultwarden"; + proxyWebsockets = true; + }; + }; extraConfig = '' proxy_cache ${config.services.nginx.proxyCachePath.apps.keysZoneName}; ''; @@ -171,20 +120,17 @@ in zone services; keepalive 2; ''; - servers = - let - address = config.services.vaultwarden.config.ROCKET_ADDRESS; - port = config.services.vaultwarden.config.ROCKET_PORT; - in - { - "${address}:${builtins.toString port}" = { }; - }; + servers = let + address = config.services.vaultwarden.config.ROCKET_ADDRESS; + port = config.services.vaultwarden.config.ROCKET_PORT; + in { "${address}:${builtins.toString port}" = { }; }; }; }) (lib.mkIf hostCfg.services.backup.enable { # Add the data directory to be backed up. - services.borgbackup.jobs.services-backup.paths = [ "/var/lib/bitwarden_rs" ]; + services.borgbackup.jobs.services-backup.paths = + [ "/var/lib/bitwarden_rs" ]; }) (lib.mkIf hostCfg.services.fail2ban.enable { @@ -194,14 +140,16 @@ in vaultwarden-user.settings = { enabled = true; backend = "systemd"; - filter = "vaultwarden-user[journalmatch='_SYSTEMD_UNIT=vaultwarden.service + _COMM=vaultwarden']"; + filter = + "vaultwarden-user[journalmatch='_SYSTEMD_UNIT=vaultwarden.service + _COMM=vaultwarden']"; maxretry = 5; }; vaultwarden-admin.settings = { enabled = true; backend = "systemd"; - filter = "vaultwarden-admin[journalmatch='_SYSTEMD_UNIT=vaultwarden.service + _COMM=vaultwarden']"; + filter = + "vaultwarden-admin[journalmatch='_SYSTEMD_UNIT=vaultwarden.service + _COMM=vaultwarden']"; maxretry = 3; }; }; @@ -215,7 +163,7 @@ in # for configuring fail2ban with the application (i.e., # https://github.com/dani-garcia/vaultwarden/wiki/Fail2Ban-Setup). [Definition] - failregex = ^.*Username or password is incorrect\. Try again\. IP: \. Username:.*$ + failregex = ^.*Username or password is incorrect\. Try again\. IP: \. Username: .*\.$ ignoreregex = '';