diff options
author | Martin Weinelt <hexa@darmstadt.ccc.de> | 2024-06-11 02:42:39 +0200 |
---|---|---|
committer | Sandro Jäckel <sandro.jaeckel@gmail.com> | 2024-06-16 01:33:12 +0200 |
commit | be53df7236663eda1fc4fed4461813289872745c (patch) | |
tree | 77a62ede9858390238d543257f026e832299f80b | |
parent | d8c8faf8c3966456d63794e7d4685def105d36f9 (diff) |
nixos/vaultwarden: harden systemd unit
Drops the capability to bind to privileged ports.
-rw-r--r-- | nixos/doc/manual/release-notes/rl-2411.section.md | 4 | ||||
-rw-r--r-- | nixos/modules/services/security/vaultwarden/default.nix | 39 | ||||
-rw-r--r-- | nixos/tests/vaultwarden.nix | 15 |
3 files changed, 47 insertions, 11 deletions
diff --git a/nixos/doc/manual/release-notes/rl-2411.section.md b/nixos/doc/manual/release-notes/rl-2411.section.md index 7777df071b182..077712be52e0c 100644 --- a/nixos/doc/manual/release-notes/rl-2411.section.md +++ b/nixos/doc/manual/release-notes/rl-2411.section.md @@ -35,6 +35,10 @@ - `services.ddclient.use` has been deprecated: `ddclient` now supports separate IPv4 and IPv6 configuration. Use `services.ddclient.usev4` and `services.ddclient.usev6` instead. +- `vaultwarden` lost the capability to bind to privileged ports. If you rely on + this behavior, override the systemd unit to allow `CAP_NET_BIND_SERVICE` in + your local configuration. + - The Invoiceplane module now only accepts the structured `settings` option. `extraConfig` is now removed. diff --git a/nixos/modules/services/security/vaultwarden/default.nix b/nixos/modules/services/security/vaultwarden/default.nix index 0f2ba4d3f5b7c..41f7de5d80fab 100644 --- a/nixos/modules/services/security/vaultwarden/default.nix +++ b/nixos/modules/services/security/vaultwarden/default.nix @@ -178,16 +178,45 @@ in { User = user; Group = group; EnvironmentFile = [ configFile ] ++ lib.optional (cfg.environmentFile != null) cfg.environmentFile; - ExecStart = "${vaultwarden}/bin/vaultwarden"; + ExecStart = lib.getExe vaultwarden; LimitNOFILE = "1048576"; - PrivateTmp = "true"; - PrivateDevices = "true"; - ProtectHome = "true"; + CapabilityBoundingSet = [ "" ]; + DeviceAllow = [ "" ]; + DevicePolicy = "closed"; + LockPersonality = true; + MemoryDenyWriteExecute = true; + NoNewPrivileges = true; + PrivateDevices = true; + PrivateTmp = true; + PrivateUsers = true; + ProcSubset = "pid"; + ProtectClock = true; + ProtectControlGroups = true; + ProtectHome = true; + ProtectHostname = true; + ProtectKernelLogs = true; + ProtectKernelModules = true; + ProtectKernelTunables = true; + ProtectProc = "noaccess"; ProtectSystem = "strict"; - AmbientCapabilities = "CAP_NET_BIND_SERVICE"; + RemoveIPC = true; + RestrictAddressFamilies = [ + "AF_INET" + "AF_INET6" + "AF_UNIX" + ]; + RestrictNamespaces = true; + RestrictRealtime = true; + RestrictSUIDSGID = true; inherit StateDirectory; StateDirectoryMode = "0700"; + SystemCallArchitectures = "native"; + SystemCallFilter = [ + "@system-service" + "~@privileged" + ]; Restart = "always"; + UMask = "0077"; }; wantedBy = [ "multi-user.target" ]; }; diff --git a/nixos/tests/vaultwarden.nix b/nixos/tests/vaultwarden.nix index 3aba3f6845fa7..baefa67dbf535 100644 --- a/nixos/tests/vaultwarden.nix +++ b/nixos/tests/vaultwarden.nix @@ -34,7 +34,7 @@ let driver = Firefox(options=options) driver.implicitly_wait(20) - driver.get('http://localhost/#/register') + driver.get('http://localhost:8080/#/register') wait = WebDriverWait(driver, 10) @@ -134,11 +134,11 @@ let dbBackend = backend; config = { rocketAddress = "0.0.0.0"; - rocketPort = 80; + rocketPort = 8080; }; }; - networking.firewall.allowedTCPPorts = [ 80 ]; + networking.firewall.allowedTCPPorts = [ 8080 ]; environment.systemPackages = [ pkgs.firefox-unwrapped pkgs.geckodriver testRunner ]; } @@ -152,10 +152,10 @@ let testScript = if testScript != null then testScript else '' start_all() server.wait_for_unit("vaultwarden.service") - server.wait_for_open_port(80) + server.wait_for_open_port(8080) with subtest("configure the cli"): - client.succeed("bw --nointeraction config server http://server") + client.succeed("bw --nointeraction config server http://server:8080") with subtest("can't login to nonexistent account"): client.fail( @@ -179,6 +179,9 @@ let timeout=60 ) assert password.strip() == "${storedPassword}" + + with subtest("Check systemd unit hardening"): + server.log(server.succeed("systemd-analyze security vaultwarden.service | grep -v ✓")) ''; }); in @@ -193,7 +196,7 @@ builtins.mapAttrs (k: v: makeVaultwardenTest k v) { testScript = '' start_all() server.wait_for_unit("vaultwarden.service") - server.wait_for_open_port(80) + server.wait_for_open_port(8080) with subtest("Set up vaultwarden"): server.succeed("PYTHONUNBUFFERED=1 test-runner | systemd-cat -t test-runner") |