Merge pull request #120526 from mweinelt/home-assistant
This commit is contained in:
commit
fb5b00d2eb
@ -245,22 +245,85 @@ in {
|
|||||||
rm -f "${cfg.configDir}/ui-lovelace.yaml"
|
rm -f "${cfg.configDir}/ui-lovelace.yaml"
|
||||||
ln -s ${lovelaceConfigFile} "${cfg.configDir}/ui-lovelace.yaml"
|
ln -s ${lovelaceConfigFile} "${cfg.configDir}/ui-lovelace.yaml"
|
||||||
'');
|
'');
|
||||||
serviceConfig = {
|
serviceConfig = let
|
||||||
ExecStart = "${package}/bin/hass --config '${cfg.configDir}'";
|
# List of capabilities to equip home-assistant with, depending on configured components
|
||||||
|
capabilities = [
|
||||||
|
# Empty string first, so we will never accidentally have an empty capability bounding set
|
||||||
|
# https://github.com/NixOS/nixpkgs/issues/120617#issuecomment-830685115
|
||||||
|
""
|
||||||
|
] ++ (unique (optionals (useComponent "bluetooth_tracker" || useComponent "bluetooth_le_tracker") [
|
||||||
|
# Required for interaction with hci devices and bluetooth sockets
|
||||||
|
# https://www.home-assistant.io/integrations/bluetooth_le_tracker/#rootless-setup-on-core-installs
|
||||||
|
"CAP_NET_ADMIN"
|
||||||
|
"CAP_NET_RAW"
|
||||||
|
] ++ lib.optionals (useComponent "emulated_hue") [
|
||||||
|
# Alexa looks for the service on port 80
|
||||||
|
# https://www.home-assistant.io/integrations/emulated_hue
|
||||||
|
"CAP_NET_BIND_SERVICE"
|
||||||
|
] ++ lib.optionals (useComponent "nmap_tracker") [
|
||||||
|
# https://www.home-assistant.io/integrations/nmap_tracker#linux-capabilities
|
||||||
|
"CAP_NET_ADMIN"
|
||||||
|
"CAP_NET_BIND_SERVICE"
|
||||||
|
"CAP_NET_RAW"
|
||||||
|
]));
|
||||||
|
in {
|
||||||
|
ExecStart = "${package}/bin/hass --runner --config '${cfg.configDir}'";
|
||||||
ExecReload = "${pkgs.coreutils}/bin/kill -HUP $MAINPID";
|
ExecReload = "${pkgs.coreutils}/bin/kill -HUP $MAINPID";
|
||||||
User = "hass";
|
User = "hass";
|
||||||
Group = "hass";
|
Group = "hass";
|
||||||
Restart = "on-failure";
|
Restart = "on-failure";
|
||||||
|
RestartForceExitStatus = "100";
|
||||||
|
SuccessExitStatus = "100";
|
||||||
|
KillSignal = "SIGINT";
|
||||||
|
|
||||||
|
# Hardening
|
||||||
|
AmbientCapabilities = capabilities;
|
||||||
|
CapabilityBoundingSet = capabilities;
|
||||||
|
DeviceAllow = [
|
||||||
|
"char-ttyACM rw"
|
||||||
|
"char-ttyAMA rw"
|
||||||
|
"char-ttyUSB rw"
|
||||||
|
];
|
||||||
|
DevicePolicy = "closed";
|
||||||
|
LockPersonality = true;
|
||||||
|
MemoryDenyWriteExecute = true;
|
||||||
|
NoNewPrivileges = true;
|
||||||
|
PrivateTmp = true;
|
||||||
|
PrivateUsers = false; # prevents gaining capabilities in the host namespace
|
||||||
|
ProtectClock = true;
|
||||||
|
ProtectControlGroups = true;
|
||||||
|
ProtectHome = true;
|
||||||
|
ProtectHostname = true;
|
||||||
|
ProtectKernelLogs = true;
|
||||||
|
ProtectKernelModules = true;
|
||||||
|
ProtectKernelTunables = true;
|
||||||
|
ProtectProc = "invisible";
|
||||||
|
ProcSubset = "pid";
|
||||||
ProtectSystem = "strict";
|
ProtectSystem = "strict";
|
||||||
|
RemoveIPC = true;
|
||||||
ReadWritePaths = let
|
ReadWritePaths = let
|
||||||
|
# Allow rw access to explicitly configured paths
|
||||||
cfgPath = [ "config" "homeassistant" "allowlist_external_dirs" ];
|
cfgPath = [ "config" "homeassistant" "allowlist_external_dirs" ];
|
||||||
value = attrByPath cfgPath [] cfg;
|
value = attrByPath cfgPath [] cfg;
|
||||||
allowPaths = if isList value then value else singleton value;
|
allowPaths = if isList value then value else singleton value;
|
||||||
in [ "${cfg.configDir}" ] ++ allowPaths;
|
in [ "${cfg.configDir}" ] ++ allowPaths;
|
||||||
KillSignal = "SIGINT";
|
RestrictAddressFamilies = [
|
||||||
PrivateTmp = true;
|
"AF_UNIX"
|
||||||
RemoveIPC = true;
|
"AF_INET"
|
||||||
AmbientCapabilities = "cap_net_raw,cap_net_admin+eip";
|
"AF_INET6"
|
||||||
|
] ++ optionals (useComponent "bluetooth_tracker" || useComponent "bluetooth_le_tracker") [
|
||||||
|
"AF_BLUETOOTH"
|
||||||
|
];
|
||||||
|
RestrictNamespaces = true;
|
||||||
|
RestrictRealtime = true;
|
||||||
|
RestrictSUIDSGID = true;
|
||||||
|
SupplementaryGroups = [ "dialout" ];
|
||||||
|
SystemCallArchitectures = "native";
|
||||||
|
SystemCallFilter = [
|
||||||
|
"@system-service"
|
||||||
|
"~@privileged"
|
||||||
|
];
|
||||||
|
UMask = "0077";
|
||||||
};
|
};
|
||||||
path = [
|
path = [
|
||||||
"/run/wrappers" # needed for ping
|
"/run/wrappers" # needed for ping
|
||||||
@ -278,7 +341,6 @@ in {
|
|||||||
home = cfg.configDir;
|
home = cfg.configDir;
|
||||||
createHome = true;
|
createHome = true;
|
||||||
group = "hass";
|
group = "hass";
|
||||||
extraGroups = [ "dialout" ];
|
|
||||||
uid = config.ids.uids.hass;
|
uid = config.ids.uids.hass;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import ./make-test-python.nix ({ pkgs, ... }:
|
import ./make-test-python.nix ({ pkgs, lib, ... }:
|
||||||
|
|
||||||
let
|
let
|
||||||
configDir = "/var/lib/foobar";
|
configDir = "/var/lib/foobar";
|
||||||
@ -6,9 +6,7 @@ let
|
|||||||
mqttPassword = "secret";
|
mqttPassword = "secret";
|
||||||
in {
|
in {
|
||||||
name = "home-assistant";
|
name = "home-assistant";
|
||||||
meta = with pkgs.lib; {
|
meta.maintainers = lib.teams.home-assistant.members;
|
||||||
maintainers = with maintainers; [ dotlambda ];
|
|
||||||
};
|
|
||||||
|
|
||||||
nodes.hass = { pkgs, ... }: {
|
nodes.hass = { pkgs, ... }: {
|
||||||
environment.systemPackages = with pkgs; [ mosquitto ];
|
environment.systemPackages = with pkgs; [ mosquitto ];
|
||||||
@ -47,6 +45,10 @@ in {
|
|||||||
payload_on = "let_there_be_light";
|
payload_on = "let_there_be_light";
|
||||||
payload_off = "off";
|
payload_off = "off";
|
||||||
}];
|
}];
|
||||||
|
emulated_hue = {
|
||||||
|
host_ip = "127.0.0.1";
|
||||||
|
listen_port = 80;
|
||||||
|
};
|
||||||
logger = {
|
logger = {
|
||||||
default = "info";
|
default = "info";
|
||||||
logs."homeassistant.components.mqtt" = "debug";
|
logs."homeassistant.components.mqtt" = "debug";
|
||||||
@ -82,6 +84,9 @@ in {
|
|||||||
hass.succeed(
|
hass.succeed(
|
||||||
"mosquitto_pub -V mqttv5 -t home-assistant/test -u ${mqttUsername} -P '${mqttPassword}' -m let_there_be_light"
|
"mosquitto_pub -V mqttv5 -t home-assistant/test -u ${mqttUsername} -P '${mqttPassword}' -m let_there_be_light"
|
||||||
)
|
)
|
||||||
|
with subtest("Check that capabilities are passed for emulated_hue to bind to port 80"):
|
||||||
|
hass.wait_for_open_port(80)
|
||||||
|
hass.succeed("curl --fail http://localhost:80/description.xml")
|
||||||
with subtest("Print log to ease debugging"):
|
with subtest("Print log to ease debugging"):
|
||||||
output_log = hass.succeed("cat ${configDir}/home-assistant.log")
|
output_log = hass.succeed("cat ${configDir}/home-assistant.log")
|
||||||
print("\n### home-assistant.log ###\n")
|
print("\n### home-assistant.log ###\n")
|
||||||
@ -93,5 +98,8 @@ in {
|
|||||||
# example line: 2020-06-20 10:01:32 DEBUG (MainThread) [homeassistant.components.mqtt] Received message on home-assistant/test: b'let_there_be_light'
|
# example line: 2020-06-20 10:01:32 DEBUG (MainThread) [homeassistant.components.mqtt] Received message on home-assistant/test: b'let_there_be_light'
|
||||||
with subtest("Check we received the mosquitto message"):
|
with subtest("Check we received the mosquitto message"):
|
||||||
assert "let_there_be_light" in output_log
|
assert "let_there_be_light" in output_log
|
||||||
|
|
||||||
|
with subtest("Check systemd unit hardening"):
|
||||||
|
hass.log(hass.succeed("systemd-analyze security home-assistant.service"))
|
||||||
'';
|
'';
|
||||||
})
|
})
|
||||||
|
Loading…
x
Reference in New Issue
Block a user