diff --git a/nixos/doc/manual/release-notes/rl-2105.xml b/nixos/doc/manual/release-notes/rl-2105.xml
index 6e4a9e7114b..b45c19fa9af 100644
--- a/nixos/doc/manual/release-notes/rl-2105.xml
+++ b/nixos/doc/manual/release-notes/rl-2105.xml
@@ -692,6 +692,12 @@ environment.systemPackages = [
skip-kernel-setup true and takes care of setting forwarding and rp_filter sysctls by itself as well
as for each interface in services.babeld.interfaces.
+
+
+
+ The option has been renamed to and
+ now follows RFC 0042.
+
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 configuration.yaml as a Nix attribute set.
+ Check the documentation
+ 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/tests/zigbee2mqtt.nix b/nixos/tests/zigbee2mqtt.nix
index b7bb21f9227..98aadbb699b 100644
--- a/nixos/tests/zigbee2mqtt.nix
+++ b/nixos/tests/zigbee2mqtt.nix
@@ -1,4 +1,4 @@
-import ./make-test-python.nix ({ pkgs, ... }:
+import ./make-test-python.nix ({ pkgs, lib, ... }:
{
machine = { pkgs, ... }:
@@ -6,6 +6,8 @@ import ./make-test-python.nix ({ pkgs, ... }:
services.zigbee2mqtt = {
enable = true;
};
+
+ systemd.services.zigbee2mqtt.serviceConfig.DevicePolicy = lib.mkForce "auto";
};
testScript = ''
@@ -14,6 +16,8 @@ import ./make-test-python.nix ({ pkgs, ... }:
machine.succeed(
"journalctl -eu zigbee2mqtt | grep \"Error: Error while opening serialport 'Error: Error: No such file or directory, cannot open /dev/ttyACM0'\""
)
+
+ machine.log(machine.succeed("systemd-analyze security zigbee2mqtt.service"))
'';
}
)