diff --git a/nixos/modules/services/misc/home-assistant.nix b/nixos/modules/services/misc/home-assistant.nix index c8ffead7b1ac..d68d7b05c173 100644 --- a/nixos/modules/services/misc/home-assistant.nix +++ b/nixos/modules/services/misc/home-assistant.nix @@ -268,6 +268,52 @@ in { "CAP_NET_BIND_SERVICE" "CAP_NET_RAW" ])); + componentsUsingBluetooth = [ + # Components that require the AF_BLUETOOTH address family + "bluetooth_tracker" + "bluetooth_le_tracker" + ]; + componentsUsingSerialDevices = [ + # Components that require access to serial devices (/dev/tty*) + # List generated from home-assistant documentation: + # git clone https://github.com/home-assistant/home-assistant.io/ + # cd source/_integrations + # rg "/dev/tty" -l | cut -d'/' -f3 | cut -d'.' -f1 | sort + # And then extended by references found in the source code, these + # mostly the ones using config flows already. + "acer_projector" + "alarmdecoder" + "arduino" + "blackbird" + "dsmr" + "edl21" + "elkm1" + "elv" + "enocean" + "firmata" + "flexit" + "gpsd" + "insteon" + "kwb" + "lacrosse" + "mhz19" + "modbus" + "modem_callerid" + "mysensors" + "nad" + "numato" + "rflink" + "rfxtrx" + "scsgate" + "serial" + "serial_pm" + "sms" + "upb" + "velbus" + "w800rf32" + "xbee" + "zha" + ]; in { ExecStart = "${package}/bin/hass --runner --config '${cfg.configDir}'"; ExecReload = "${pkgs.coreutils}/bin/kill -HUP $MAINPID"; @@ -281,11 +327,11 @@ in { # Hardening AmbientCapabilities = capabilities; CapabilityBoundingSet = capabilities; - DeviceAllow = [ + DeviceAllow = (optionals (any useComponent componentsUsingSerialDevices) [ "char-ttyACM rw" "char-ttyAMA rw" "char-ttyUSB rw" - ]; + ]); DevicePolicy = "closed"; LockPersonality = true; MemoryDenyWriteExecute = true; @@ -314,13 +360,15 @@ in { "AF_INET6" "AF_NETLINK" "AF_UNIX" - ] ++ optionals (useComponent "bluetooth_tracker" || useComponent "bluetooth_le_tracker") [ + ] ++ optionals (any useComponent componentsUsingBluetooth) [ "AF_BLUETOOTH" ]; RestrictNamespaces = true; RestrictRealtime = true; RestrictSUIDSGID = true; - SupplementaryGroups = [ "dialout" ]; + SupplementaryGroups = optionals (any useComponent componentsUsingSerialDevices) [ + "dialout" + ]; SystemCallArchitectures = "native"; SystemCallFilter = [ "@system-service" diff --git a/nixos/tests/home-assistant.nix b/nixos/tests/home-assistant.nix index c75dd248ecb3..f8f8e9fd183f 100644 --- a/nixos/tests/home-assistant.nix +++ b/nixos/tests/home-assistant.nix @@ -45,6 +45,7 @@ in { payload_on = "let_there_be_light"; payload_off = "off"; }]; + # tests component-based capability assignment (CAP_NET_BIND_SERVICE) emulated_hue = { host_ip = "127.0.0.1"; listen_port = 80; @@ -100,6 +101,7 @@ in { assert "let_there_be_light" in output_log with subtest("Check systemd unit hardening"): + hass.log(hass.succeed("systemctl show home-assistant.service")) hass.log(hass.succeed("systemd-analyze security home-assistant.service")) ''; })