diff --git a/README.md b/README.md index ca4d436..239ab16 100644 --- a/README.md +++ b/README.md @@ -41,7 +41,7 @@ A sample configuration would be as follows: port = 8081; # serve web application on port 8081 user = "pi-aqm"; group = "pi-aqm"; - device = "/dev/ttyUSB0"; # this is the device port that corresponds to your sensor device + serialPort = "/dev/ttyUSB0"; # this is the serial port that corresponds to your sensor device redis.createLocally = true; }; diff --git a/nix/module.nix b/nix/module.nix index fb6b9ac..224c29c 100644 --- a/nix/module.nix +++ b/nix/module.nix @@ -14,35 +14,36 @@ in { type = types.package; default = self.packages.${pkgs.system}.pi-air-quality-monitor; }; + openFirewall = mkOption { type = types.bool; default = true; - description = "Whether to open the firewall for the server"; + description = "Whether to open the firewall for the service"; }; settings = { port = mkOption { type = types.int; default = 8080; - description = "Port to run the server on"; + description = "Port to run the service on"; }; user = mkOption { type = types.str; default = "pi-aqm"; - description = "User to run the server as"; + description = "User to run the servvice as"; }; group = mkOption { type = types.str; default = "pi-aqm"; - description = "Group to run the server as"; + description = "Group to run the service as"; }; - device = mkOption { + serialPort = mkOption { type = types.path; default = "/dev/ttyUSB0"; - description = "Device to read data from"; + description = "Serial port device to read data from"; }; environmentFile = mkOption { @@ -128,6 +129,33 @@ in { WorkingDirectory = "${cfg.settings.dataDir}"; ExecStart = "${lib.getExe cfg.package}"; Restart = "always"; + + # Hardening + CapabilityBoundingSet = ""; + DeviceAllow = [cfg.settings.serialPort]; + DevicePolicy = "closed"; + DynamicUser = true; + LockPersonality = true; + MemoryDenyWriteExecute = false; + NoNewPrivileges = true; + PrivateUsers = true; + PrivateTmp = true; + ProtectClock = true; + ProtectControlGroups = true; + ProtectHome = true; + ProtectHostname = true; + ProtectKernelLogs = true; + ProtectKernelModules = true; + RemoveIPC = true; + RestrictNamespaces = true; + RestrictRealtime = true; + RestrictSUIDSGID = true; + SystemCallArchitectures = "native"; + UMask = "0077"; + SystemCallFilter = [ + "@system-service @pkey" + "~@privileged @resources" + ]; }; }; }; diff --git a/nix/tests/checks/basic.nix b/nix/tests/checks/basic.nix index 6abc9ab..745c0c1 100644 --- a/nix/tests/checks/basic.nix +++ b/nix/tests/checks/basic.nix @@ -2,55 +2,73 @@ nixosTest, self, ... -}: -nixosTest { - name = "basic"; +}: let + serialPort = "/dev/ttyS0"; +in + nixosTest { + name = "basic"; - nodes = { - client = {pkgs, ...}: { - imports = [../profiles/test-setup.nix]; + nodes = { + client = {pkgs, ...}: { + imports = [../profiles/test-setup.nix]; - environment.systemPackages = with pkgs; [ - netcat - ]; - }; - - server = {pkgs, ...}: { - imports = [ - ../profiles/test-setup.nix - self.nixosModules.pi-air-quality-monitor - ]; - - users.users.test = { - isNormalUser = true; - extraGroups = ["wheel"]; - packages = with pkgs; [ - tree + environment.systemPackages = with pkgs; [ + netcat ]; }; - services.pi-air-quality-monitor = { - enable = true; - openFirewall = true; + server = {pkgs, ...}: { + imports = [ + ../profiles/test-setup.nix + self.nixosModules.pi-air-quality-monitor + ]; - settings = { - port = 8080; - user = "pi-aqm"; - group = "pi-aqm"; + users.users.test = { + isNormalUser = true; + extraGroups = ["wheel"]; + packages = with pkgs; [ + tree + ]; }; + + services.pi-air-quality-monitor = { + enable = true; + openFirewall = true; + + settings = { + port = 8080; + user = "pi-aqm"; + group = "pi-aqm"; + inherit serialPort; + }; + }; + + system.stateVersion = "23.11"; }; - - system.stateVersion = "23.11"; }; - }; - testScript = '' - server.wait_for_unit("default.target") - server.succeed("ls -lah /dev/ttyUSB0") - #server.succeed('systemctl status pi-air-quality-monitor | grep \"Active: active (running)\" || return 0') - #server.succeed('nc -vz server 8080') + testScript = '' + server.start() - #client.wait_for_unit("default.target") - #client.succeed("nc -vz server 8080") - ''; -} + server.wait_for_unit("default.target") + log.info("Checking if configured serial port exists") + server.succeed("ls -lah ${serialPort}") + + log.info("Check if unit is running correctly") + server.wait_for_unit("pi-air-quality-monitor.service") + server.succeed("systemctl status pi-air-quality-monitor.service | grep 'Active: active (running)' >&2") + server.succeed("journalctl -u pi-air-quality-monitor.service >&2") + + log.info("Showing units content") + server.succeed("systemctl status pi-air-quality-monitor.service >&2") + server.succeed("systemctl cat pi-air-quality-monitor.service >&2") + server.succeed("systemctl cat pi-air-quality-monitor.socket >&2") + + log.info("Checking if service is accessible locally") + server.succeed("nc -vz localhost 8080") + + client.start() + client.wait_for_unit("default.target") + #client.succeed("nc -vz server 8080") + ''; + }