diff options
Diffstat (limited to 'nixos/modules')
-rw-r--r-- | nixos/modules/module-list.nix | 1 | ||||
-rw-r--r-- | nixos/modules/services/misc/zigbee2mqtt.nix | 96 | ||||
-rw-r--r-- | nixos/modules/services/networking/adguardhome.nix | 78 | ||||
-rw-r--r-- | nixos/modules/services/web-servers/nginx/default.nix | 12 | ||||
-rw-r--r-- | nixos/modules/virtualisation/nixos-containers.nix | 28 |
5 files changed, 178 insertions, 37 deletions
diff --git a/nixos/modules/module-list.nix b/nixos/modules/module-list.nix index 2ddb85943d3..62dfac0857d 100644 --- a/nixos/modules/module-list.nix +++ b/nixos/modules/module-list.nix @@ -631,6 +631,7 @@ ./services/network-filesystems/xtreemfs.nix ./services/network-filesystems/ceph.nix ./services/networking/3proxy.nix + ./services/networking/adguardhome.nix ./services/networking/amuled.nix ./services/networking/aria2.nix ./services/networking/asterisk.nix diff --git a/nixos/modules/services/misc/zigbee2mqtt.nix b/nixos/modules/services/misc/zigbee2mqtt.nix index cd987eb76c7..4458da1346b 100644 --- a/nixos/modules/services/misc/zigbee2mqtt.nix +++ b/nixos/modules/services/misc/zigbee2mqtt.nix @@ -5,29 +5,17 @@ with lib; let cfg = config.services.zigbee2mqtt; - configJSON = pkgs.writeText "configuration.json" - (builtins.toJSON (recursiveUpdate defaultConfig cfg.config)); - configFile = pkgs.runCommand "configuration.yaml" { preferLocalBuild = true; } '' - ${pkgs.remarshal}/bin/json2yaml -i ${configJSON} -o $out - ''; + format = pkgs.formats.yaml { }; + configFile = format.generate "zigbee2mqtt.yaml" cfg.settings; - # the default config contains all required settings, - # so the service starts up without crashing. - defaultConfig = { - homeassistant = false; - permit_join = false; - mqtt = { - base_topic = "zigbee2mqtt"; - server = "mqtt://localhost:1883"; - }; - serial.port = "/dev/ttyACM0"; - # put device configuration into separate file because configuration.yaml - # is copied from the store on startup - devices = "devices.yaml"; - }; in { - meta.maintainers = with maintainers; [ sweber ]; + meta.maintainers = with maintainers; [ sweber hexa ]; + + imports = [ + # Remove warning before the 21.11 release + (mkRenamedOptionModule [ "services" "zigbee2mqtt" "config" ] [ "services" "zigbee2mqtt" "settings" ]) + ]; options.services.zigbee2mqtt = { enable = mkEnableOption "enable zigbee2mqtt service"; @@ -37,7 +25,11 @@ in default = pkgs.zigbee2mqtt.override { dataDir = cfg.dataDir; }; - defaultText = "pkgs.zigbee2mqtt"; + defaultText = literalExample '' + pkgs.zigbee2mqtt { + dataDir = services.zigbee2mqtt.dataDir + } + ''; type = types.package; }; @@ -47,9 +39,9 @@ in type = types.path; }; - config = mkOption { + settings = mkOption { + type = format.type; default = {}; - type = with types; nullOr attrs; example = literalExample '' { homeassistant = config.services.home-assistant.enable; @@ -61,11 +53,28 @@ in ''; description = '' Your <filename>configuration.yaml</filename> as a Nix attribute set. + Check the <link xlink:href="https://www.zigbee2mqtt.io/information/configuration.html">documentation</link> + for possible options. ''; }; }; config = mkIf (cfg.enable) { + + # preset config values + services.zigbee2mqtt.settings = { + homeassistant = mkDefault config.services.home-assistant.enable; + permit_join = mkDefault false; + mqtt = { + base_topic = mkDefault "zigbee2mqtt"; + server = mkDefault "mqtt://localhost:1883"; + }; + serial.port = mkDefault "/dev/ttyACM0"; + # reference device configuration, that is kept in a separate file + # to prevent it being overwritten in the units ExecStartPre script + devices = mkDefault "devices.yaml"; + }; + systemd.services.zigbee2mqtt = { description = "Zigbee2mqtt Service"; wantedBy = [ "multi-user.target" ]; @@ -76,10 +85,48 @@ in User = "zigbee2mqtt"; WorkingDirectory = cfg.dataDir; Restart = "on-failure"; + + # Hardening + CapabilityBoundingSet = ""; + DeviceAllow = [ + config.services.zigbee2mqtt.settings.serial.port + ]; + DevicePolicy = "closed"; + LockPersonality = true; + MemoryDenyWriteExecute = false; + NoNewPrivileges = true; + PrivateDevices = false; # prevents access to /dev/serial, because it is set 0700 root:root + PrivateUsers = true; + PrivateTmp = true; + ProtectClock = true; + ProtectControlGroups = true; + ProtectHome = true; + ProtectHostname = true; + ProtectKernelLogs = true; + ProtectKernelModules = true; + ProtectKernelTunables = true; + ProtectProc = "invisible"; + ProcSubset = "pid"; ProtectSystem = "strict"; ReadWritePaths = cfg.dataDir; - PrivateTmp = true; RemoveIPC = true; + RestrictAddressFamilies = [ + "AF_INET" + "AF_INET6" + ]; + RestrictNamespaces = true; + RestrictRealtime = true; + RestrictSUIDSGID = true; + SupplementaryGroups = [ + "dialout" + ]; + SystemCallArchitectures = "native"; + SystemCallFilter = [ + "@system-service" + "~@privileged" + "~@resources" + ]; + UMask = "0077"; }; preStart = '' cp --no-preserve=mode ${configFile} "${cfg.dataDir}/configuration.yaml" @@ -90,7 +137,6 @@ in home = cfg.dataDir; createHome = true; group = "zigbee2mqtt"; - extraGroups = [ "dialout" ]; uid = config.ids.uids.zigbee2mqtt; }; diff --git a/nixos/modules/services/networking/adguardhome.nix b/nixos/modules/services/networking/adguardhome.nix new file mode 100644 index 00000000000..4388ef2b7e5 --- /dev/null +++ b/nixos/modules/services/networking/adguardhome.nix @@ -0,0 +1,78 @@ +{ config, lib, pkgs, ... }: + +with lib; + +let + cfg = config.services.adguardhome; + + args = concatStringsSep " " ([ + "--no-check-update" + "--pidfile /run/AdGuardHome/AdGuardHome.pid" + "--work-dir /var/lib/AdGuardHome/" + "--config /var/lib/AdGuardHome/AdGuardHome.yaml" + "--host ${cfg.host}" + "--port ${toString cfg.port}" + ] ++ cfg.extraArgs); + +in +{ + options.services.adguardhome = with types; { + enable = mkEnableOption "AdGuard Home network-wide ad blocker"; + + host = mkOption { + default = "0.0.0.0"; + type = str; + description = '' + Host address to bind HTTP server to. + ''; + }; + + port = mkOption { + default = 3000; + type = port; + description = '' + Port to serve HTTP pages on. + ''; + }; + + openFirewall = mkOption { + default = false; + type = bool; + description = '' + Open ports in the firewall for the AdGuard Home web interface. Does not + open the port needed to access the DNS resolver. + ''; + }; + + extraArgs = mkOption { + default = [ ]; + type = listOf str; + description = '' + Extra command line parameters to be passed to the adguardhome binary. + ''; + }; + }; + + config = mkIf cfg.enable { + systemd.services.adguardhome = { + description = "AdGuard Home: Network-level blocker"; + after = [ "syslog.target" "network.target" ]; + wantedBy = [ "multi-user.target" ]; + unitConfig = { + StartLimitIntervalSec = 5; + StartLimitBurst = 10; + }; + serviceConfig = { + DynamicUser = true; + ExecStart = "${pkgs.adguardhome}/bin/adguardhome ${args}"; + AmbientCapabilities = [ "CAP_NET_BIND_SERVICE" ]; + Restart = "always"; + RestartSec = 10; + RuntimeDirectory = "AdGuardHome"; + StateDirectory = "AdGuardHome"; + }; + }; + + networking.firewall.allowedTCPPorts = mkIf cfg.openFirewall [ cfg.port ]; + }; +} diff --git a/nixos/modules/services/web-servers/nginx/default.nix b/nixos/modules/services/web-servers/nginx/default.nix index 18e1263fef5..d811879b7b1 100644 --- a/nixos/modules/services/web-servers/nginx/default.nix +++ b/nixos/modules/services/web-servers/nginx/default.nix @@ -819,28 +819,38 @@ in # Logs directory and mode LogsDirectory = "nginx"; LogsDirectoryMode = "0750"; + # Proc filesystem + ProcSubset = "pid"; + ProtectProc = "invisible"; + # New file permissions + UMask = "0027"; # 0640 / 0750 # Capabilities AmbientCapabilities = [ "CAP_NET_BIND_SERVICE" "CAP_SYS_RESOURCE" ]; CapabilityBoundingSet = [ "CAP_NET_BIND_SERVICE" "CAP_SYS_RESOURCE" ]; # Security NoNewPrivileges = true; - # Sandboxing + # Sandboxing (sorted by occurrence in https://www.freedesktop.org/software/systemd/man/systemd.exec.html) ProtectSystem = "strict"; ProtectHome = mkDefault true; PrivateTmp = true; PrivateDevices = true; ProtectHostname = true; + ProtectClock = true; ProtectKernelTunables = true; ProtectKernelModules = true; + ProtectKernelLogs = true; ProtectControlGroups = true; RestrictAddressFamilies = [ "AF_UNIX" "AF_INET" "AF_INET6" ]; + RestrictNamespaces = true; LockPersonality = true; MemoryDenyWriteExecute = !(builtins.any (mod: (mod.allowMemoryWriteExecute or false)) cfg.package.modules); RestrictRealtime = true; RestrictSUIDSGID = true; + RemoveIPC = true; PrivateMounts = true; # System Call Filtering SystemCallArchitectures = "native"; + SystemCallFilter = "~@chown @cpu-emulation @debug @keyring @ipc @module @mount @obsolete @privileged @raw-io @reboot @setuid @swap"; }; }; diff --git a/nixos/modules/virtualisation/nixos-containers.nix b/nixos/modules/virtualisation/nixos-containers.nix index 7a1f11ce40d..a158509a77a 100644 --- a/nixos/modules/virtualisation/nixos-containers.nix +++ b/nixos/modules/virtualisation/nixos-containers.nix @@ -35,6 +35,9 @@ let '' #! ${pkgs.runtimeShell} -e + # Exit early if we're asked to shut down. + trap "exit 0" SIGRTMIN+3 + # Initialise the container side of the veth pair. if [ -n "$HOST_ADDRESS" ] || [ -n "$HOST_ADDRESS6" ] || [ -n "$LOCAL_ADDRESS" ] || [ -n "$LOCAL_ADDRESS6" ] || @@ -60,8 +63,12 @@ let ${concatStringsSep "\n" (mapAttrsToList renderExtraVeth cfg.extraVeths)} - # Start the regular stage 1 script. - exec "$1" + # Start the regular stage 2 script. + # We source instead of exec to not lose an early stop signal, which is + # also the only _reliable_ shutdown signal we have since early stop + # does not execute ExecStop* commands. + set +e + . "$1" '' ); @@ -127,12 +134,16 @@ let ''} # Run systemd-nspawn without startup notification (we'll - # wait for the container systemd to signal readiness). + # wait for the container systemd to signal readiness) + # Kill signal handling means systemd-nspawn will pass a system-halt signal + # to the container systemd when it receives SIGTERM for container shutdown; + # containerInit and stage2 have to handle this as well. exec ${config.systemd.package}/bin/systemd-nspawn \ --keep-unit \ -M "$INSTANCE" -D "$root" $extraFlags \ $EXTRA_NSPAWN_FLAGS \ --notify-ready=yes \ + --kill-signal=SIGRTMIN+3 \ --bind-ro=/nix/store \ --bind-ro=/nix/var/nix/db \ --bind-ro=/nix/var/nix/daemon-socket \ @@ -259,13 +270,10 @@ let Slice = "machine.slice"; Delegate = true; - # Hack: we don't want to kill systemd-nspawn, since we call - # "machinectl poweroff" in preStop to shut down the - # container cleanly. But systemd requires sending a signal - # (at least if we want remaining processes to be killed - # after the timeout). So send an ignored signal. + # We rely on systemd-nspawn turning a SIGTERM to itself into a shutdown + # signal (SIGRTMIN+3) for the inner container. KillMode = "mixed"; - KillSignal = "WINCH"; + KillSignal = "TERM"; DevicePolicy = "closed"; DeviceAllow = map (d: "${d.node} ${d.modifier}") cfg.allowedDevices; @@ -747,8 +755,6 @@ in postStart = postStartScript dummyConfig; - preStop = "machinectl poweroff $INSTANCE"; - restartIfChanged = false; serviceConfig = serviceDirectives dummyConfig; |