Skip unnecessary mounts and privileges for landingpage (#4518)

* Skip unnecessary mounts for landingpage

* Remove privileged and cgroup rules from landingpage
This commit is contained in:
Mike Degatano 2023-09-03 12:21:35 -04:00 committed by GitHub
parent 6adb4fbcf7
commit f30d21361f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 204 additions and 45 deletions

View File

@ -66,10 +66,14 @@ class DockerHomeAssistant(DockerInterface):
def cgroups_rules(self) -> list[str]:
"""Return a list of needed cgroups permission."""
return (
self.sys_hardware.policy.get_cgroups_rules(PolicyGroup.UART)
+ self.sys_hardware.policy.get_cgroups_rules(PolicyGroup.VIDEO)
+ self.sys_hardware.policy.get_cgroups_rules(PolicyGroup.GPIO)
+ self.sys_hardware.policy.get_cgroups_rules(PolicyGroup.USB)
[]
if self.sys_homeassistant.version == LANDINGPAGE
else (
self.sys_hardware.policy.get_cgroups_rules(PolicyGroup.UART)
+ self.sys_hardware.policy.get_cgroups_rules(PolicyGroup.VIDEO)
+ self.sys_hardware.policy.get_cgroups_rules(PolicyGroup.GPIO)
+ self.sys_hardware.policy.get_cgroups_rules(PolicyGroup.USB)
)
)
@property
@ -79,54 +83,62 @@ class DockerHomeAssistant(DockerInterface):
MOUNT_DEV,
MOUNT_DBUS,
MOUNT_UDEV,
# Add folders
# HA config folder
Mount(
type=MountType.BIND.value,
source=self.sys_config.path_extern_homeassistant.as_posix(),
target="/config",
read_only=False,
),
Mount(
type=MountType.BIND.value,
source=self.sys_config.path_extern_ssl.as_posix(),
target="/ssl",
read_only=True,
),
Mount(
type=MountType.BIND.value,
source=self.sys_config.path_extern_share.as_posix(),
target="/share",
read_only=False,
propagation=PropagationMode.RSLAVE.value,
),
Mount(
type=MountType.BIND.value,
source=self.sys_config.path_extern_media.as_posix(),
target="/media",
read_only=False,
propagation=PropagationMode.RSLAVE.value,
),
# Configuration audio
Mount(
type=MountType.BIND.value,
source=self.sys_homeassistant.path_extern_pulse.as_posix(),
target="/etc/pulse/client.conf",
read_only=True,
),
Mount(
type=MountType.BIND.value,
source=self.sys_plugins.audio.path_extern_pulse.as_posix(),
target="/run/audio",
read_only=True,
),
Mount(
type=MountType.BIND.value,
source=self.sys_plugins.audio.path_extern_asound.as_posix(),
target="/etc/asound.conf",
read_only=True,
),
]
# Landingpage does not need all this access
if self.sys_homeassistant.version != LANDINGPAGE:
mounts.extend(
[
# All other folders
Mount(
type=MountType.BIND.value,
source=self.sys_config.path_extern_ssl.as_posix(),
target="/ssl",
read_only=True,
),
Mount(
type=MountType.BIND.value,
source=self.sys_config.path_extern_share.as_posix(),
target="/share",
read_only=False,
propagation=PropagationMode.RSLAVE.value,
),
Mount(
type=MountType.BIND.value,
source=self.sys_config.path_extern_media.as_posix(),
target="/media",
read_only=False,
propagation=PropagationMode.RSLAVE.value,
),
# Configuration audio
Mount(
type=MountType.BIND.value,
source=self.sys_homeassistant.path_extern_pulse.as_posix(),
target="/etc/pulse/client.conf",
read_only=True,
),
Mount(
type=MountType.BIND.value,
source=self.sys_plugins.audio.path_extern_pulse.as_posix(),
target="/run/audio",
read_only=True,
),
Mount(
type=MountType.BIND.value,
source=self.sys_plugins.audio.path_extern_asound.as_posix(),
target="/etc/asound.conf",
read_only=True,
),
]
)
# Machine ID
if MACHINE_ID.exists():
mounts.append(MOUNT_MACHINE_ID)
@ -154,7 +166,7 @@ class DockerHomeAssistant(DockerInterface):
name=self.name,
hostname=self.name,
detach=True,
privileged=True,
privileged=self.sys_homeassistant.version != LANDINGPAGE,
init=False,
security_opt=self.security_opt,
network_mode="host",

View File

@ -0,0 +1,147 @@
"""Test Home Assistant container."""
from ipaddress import IPv4Address
from pathlib import Path
from unittest.mock import ANY, patch
from awesomeversion import AwesomeVersion
from docker.types import Mount
from supervisor.coresys import CoreSys
from supervisor.docker.homeassistant import DockerHomeAssistant
from supervisor.docker.manager import DockerAPI
from supervisor.homeassistant.const import LANDINGPAGE
async def test_homeassistant_start(
coresys: CoreSys, tmp_supervisor_data: Path, path_extern
):
"""Test starting homeassistant."""
coresys.homeassistant.version = AwesomeVersion("2023.8.1")
with patch.object(DockerAPI, "run") as run, patch.object(
DockerHomeAssistant, "is_running", side_effect=[False, False, True]
), patch("supervisor.homeassistant.core.asyncio.sleep"):
await coresys.homeassistant.core.start()
run.assert_called_once()
assert run.call_args.kwargs["name"] == "homeassistant"
assert run.call_args.kwargs["hostname"] == "homeassistant"
assert run.call_args.kwargs["privileged"] is True
assert run.call_args.kwargs["oom_score_adj"] == -300
assert run.call_args.kwargs["device_cgroup_rules"]
assert run.call_args.kwargs["extra_hosts"] == {
"supervisor": IPv4Address("172.30.32.2"),
"observer": IPv4Address("172.30.32.6"),
}
assert run.call_args.kwargs["environment"] == {
"SUPERVISOR": IPv4Address("172.30.32.2"),
"HASSIO": IPv4Address("172.30.32.2"),
"TZ": ANY,
"SUPERVISOR_TOKEN": ANY,
"HASSIO_TOKEN": ANY,
}
assert run.call_args.kwargs["mounts"] == [
Mount(type="bind", source="/dev", target="/dev", read_only=True),
Mount(type="bind", source="/run/dbus", target="/run/dbus", read_only=True),
Mount(type="bind", source="/run/udev", target="/run/udev", read_only=True),
Mount(
type="bind",
source=coresys.config.path_extern_homeassistant.as_posix(),
target="/config",
read_only=False,
),
Mount(
type="bind",
source=coresys.config.path_extern_ssl.as_posix(),
target="/ssl",
read_only=True,
),
Mount(
type="bind",
source=coresys.config.path_extern_share.as_posix(),
target="/share",
read_only=False,
propagation="rslave",
),
Mount(
type="bind",
source=coresys.config.path_extern_media.as_posix(),
target="/media",
read_only=False,
propagation="rslave",
),
Mount(
type="bind",
source=coresys.homeassistant.path_extern_pulse.as_posix(),
target="/etc/pulse/client.conf",
read_only=True,
),
Mount(
type="bind",
source=coresys.plugins.audio.path_extern_pulse.as_posix(),
target="/run/audio",
read_only=True,
),
Mount(
type="bind",
source=coresys.plugins.audio.path_extern_asound.as_posix(),
target="/etc/asound.conf",
read_only=True,
),
Mount(
type="bind",
source="/etc/machine-id",
target="/etc/machine-id",
read_only=True,
),
]
assert "volumes" not in run.call_args.kwargs
async def test_landingpage_start(
coresys: CoreSys, tmp_supervisor_data: Path, path_extern
):
"""Test starting landingpage."""
coresys.homeassistant.version = LANDINGPAGE
with patch.object(DockerAPI, "run") as run, patch.object(
DockerHomeAssistant, "is_running", return_value=False
):
await coresys.homeassistant.core.start()
run.assert_called_once()
assert run.call_args.kwargs["name"] == "homeassistant"
assert run.call_args.kwargs["hostname"] == "homeassistant"
assert run.call_args.kwargs["privileged"] is False
assert run.call_args.kwargs["oom_score_adj"] == -300
assert not run.call_args.kwargs["device_cgroup_rules"]
assert run.call_args.kwargs["extra_hosts"] == {
"supervisor": IPv4Address("172.30.32.2"),
"observer": IPv4Address("172.30.32.6"),
}
assert run.call_args.kwargs["environment"] == {
"SUPERVISOR": IPv4Address("172.30.32.2"),
"HASSIO": IPv4Address("172.30.32.2"),
"TZ": ANY,
"SUPERVISOR_TOKEN": ANY,
"HASSIO_TOKEN": ANY,
}
assert run.call_args.kwargs["mounts"] == [
Mount(type="bind", source="/dev", target="/dev", read_only=True),
Mount(type="bind", source="/run/dbus", target="/run/dbus", read_only=True),
Mount(type="bind", source="/run/udev", target="/run/udev", read_only=True),
Mount(
type="bind",
source=coresys.config.path_extern_homeassistant.as_posix(),
target="/config",
read_only=False,
),
Mount(
type="bind",
source="/etc/machine-id",
target="/etc/machine-id",
read_only=True,
),
]
assert "volumes" not in run.call_args.kwargs