From 07b2bf1d3b0eb27ad34b8c99d3d99b8cf96da7eb Mon Sep 17 00:00:00 2001 From: Vinzenz Schroeter Date: Sun, 12 Oct 2025 19:01:07 +0200 Subject: [PATCH] add configurable service to nixosModule --- flake.nix | 132 ++++++++++++++++++++++++++- tanks-backend/TanksServer/Program.cs | 3 + 2 files changed, 132 insertions(+), 3 deletions(-) diff --git a/flake.nix b/flake.nix index 83da6a7..9c213b4 100644 --- a/flake.nix +++ b/flake.nix @@ -135,13 +135,139 @@ "--set-default TANKSSERVER_CLIENT ${selfPkgs.servicepoint-tanks-frontend}" "--set-default TANKSSERVER_ASSETS ${selfPkgs.servicepoint-tanks-assets}" ]; + + meta = { + mainProgram = "TanksServer"; + }; }; } ); - nixosModules.default = { - nixpkgs.overlays = [ self.overlays.default ]; - }; + nixosModules.default = + { + pkgs, + config, + lib, + ... + }: + let + cfg = config.services.servicepoint-tanks; + default-user-name = "servicepoint-tanks"; + in + { + options.services.servicepoint-tanks = { + enable = lib.mkEnableOption "servicepoint-tanks"; + package = lib.mkPackageOption pkgs "servicepoint-tanks" { }; + urls = lib.mkOption { + default = [ "http://localhost:5000" ]; + description = '' + Configures which protocol to bind on which host:port combination. + ''; + type = lib.types.listOf lib.types.str; + example = [ + "http://0.0.0.0" + "http://localhost:5000" + # TODO: allow HTTPS + ]; + }; + user = lib.mkOption { + default = default-user-name; + description = '' + The user under which servicepoint-tanks is run. + + This module utilizes systemd's DynamicUser feature. See the corresponding section in + {manpage}`systemd.exec(5)` for more details. + ''; + type = lib.types.str; + }; + group = lib.mkOption { + default = default-user-name; + description = '' + The group under which servicepoint-tanks is run. + + This module utilizes systemd's DynamicUser feature. See the corresponding section in + {manpage}`systemd.exec(5)` for more details. + ''; + type = lib.types.str; + }; + }; + + nixpkgs.overlays = [ self.overlays.default ]; + + config = lib.mkIf cfg.enable { + users = { + users = lib.mkIf (cfg.user == default-user-name) { + "${default-user-name}" = { + isSystemUser = true; + group = cfg.group; + }; + }; + + groups = lib.mkIf (cfg.group == default-user-name) { + "${default-user-name}" = { }; + }; + }; + + systemd.services.sericepoint-tanks = { + description = "Run the servicepoint-tanks server"; + wantedBy = [ "multi-user.target" ]; + after = [ "network-online.target" ]; + wants = [ "network-online.target" ]; + + environment = { + ASPNETCORE_URLS = "${lib.strings.concatStringsSep ";" cfg.urls}"; + }; + + serviceConfig = { + User = cfg.user; + Group = cfg.group; + DynamicUser = true; + + Type = "exec"; + ExecStart = lib.getExe cfg.package; + + # hardening + NoNewPrivileges = true; + CapabilityBoundingSet = null; + SystemCallFilter = [ + "@system-service" + "~@privileged" + ]; + SystemCallArchitectures = "native"; + AmbientCapabilities = ""; + PrivateMounts = true; + PrivateUsers = true; + PrivateTmp = true; + PrivateDevices = true; + ProtectHome = true; + ProtectClock = true; + ProtectHostname = true; + ProtectKernelLogs = true; + ProtectKernelModules = true; + ProtectKernelTunables = true; + ProtectProc = "invisible"; + ProtectSystem = "strict"; + ProtectControlGroups = "strict"; + LockPersonality = true; + RemoveIPC = true; + RestrictRealtime = true; + RestrictSUIDSGID = true; + RestrictNamespaces = true; + RestrictAddressFamilies = [ + "AF_INET" + "AF_INET6" + + # TODO: enable unix domain socket bind + # "AF_UNIX" + ]; + + # TODO: try fully AOT build with: + #MemoryDenyWriteExecute = true; + }; + }; + }; + + }; overlays.default = final: prev: { servicepoint-tanks = self.packages."${prev.system}".servicepoint-tanks; diff --git a/tanks-backend/TanksServer/Program.cs b/tanks-backend/TanksServer/Program.cs index cbac46a..cd3f3d6 100644 --- a/tanks-backend/TanksServer/Program.cs +++ b/tanks-backend/TanksServer/Program.cs @@ -133,6 +133,9 @@ public static class Program app.UseWebSockets(); app.UseHttpLogging(); + // TODO add domain socket support + // TODO Call UseKestrelHttpsConfiguration() on IWebHostBuilder to automatically enable HTTPS when an https:// address is used + return app; }