mirror of
https://github.com/home-assistant/supervisor.git
synced 2025-07-23 17:16:33 +00:00
Add host UTS namespace support for Add-Ons (#3596)
* Add host UTS namespace support for Add-Ons Using the UTS host namespace is useful when running a mDNS responder which learns the hostname from the gethostname syscall. This way the add-on can use the system's hostname without further doing. * Check host_uts default * Adjust Security rating if host UTS mode and CAP_ADMIN is set * Don't add hostname to DNS server if UTS namespace is disabled * Simplify hostname logic * Update supervisor/docker/addon.py Co-authored-by: Mike Degatano <michael.degatano@gmail.com> --------- Co-authored-by: Mike Degatano <michael.degatano@gmail.com>
This commit is contained in:
parent
d73d8d00f0
commit
919f1e9149
@ -34,6 +34,7 @@ from ..const import (
|
|||||||
ATTR_HOST_IPC,
|
ATTR_HOST_IPC,
|
||||||
ATTR_HOST_NETWORK,
|
ATTR_HOST_NETWORK,
|
||||||
ATTR_HOST_PID,
|
ATTR_HOST_PID,
|
||||||
|
ATTR_HOST_UTS,
|
||||||
ATTR_IMAGE,
|
ATTR_IMAGE,
|
||||||
ATTR_INGRESS,
|
ATTR_INGRESS,
|
||||||
ATTR_INGRESS_STREAM,
|
ATTR_INGRESS_STREAM,
|
||||||
@ -308,6 +309,11 @@ class AddonModel(CoreSysAttributes, ABC):
|
|||||||
"""Return True if add-on run on host IPC namespace."""
|
"""Return True if add-on run on host IPC namespace."""
|
||||||
return self.data[ATTR_HOST_IPC]
|
return self.data[ATTR_HOST_IPC]
|
||||||
|
|
||||||
|
@property
|
||||||
|
def host_uts(self) -> bool:
|
||||||
|
"""Return True if add-on run on host UTS namespace."""
|
||||||
|
return self.data[ATTR_HOST_UTS]
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def host_dbus(self) -> bool:
|
def host_dbus(self) -> bool:
|
||||||
"""Return True if add-on run on host D-BUS."""
|
"""Return True if add-on run on host D-BUS."""
|
||||||
|
@ -70,6 +70,10 @@ def rating_security(addon: AddonModel) -> int:
|
|||||||
if addon.host_pid:
|
if addon.host_pid:
|
||||||
rating += -2
|
rating += -2
|
||||||
|
|
||||||
|
# UTS host namespace allows to set hostname only with SYS_ADMIN
|
||||||
|
if addon.host_uts and Capabilities.SYS_ADMIN in addon.privileged:
|
||||||
|
rating += -1
|
||||||
|
|
||||||
# Docker Access & full Access
|
# Docker Access & full Access
|
||||||
if addon.access_docker_api or addon.with_full_access:
|
if addon.access_docker_api or addon.with_full_access:
|
||||||
rating = 1
|
rating = 1
|
||||||
|
@ -41,6 +41,7 @@ from ..const import (
|
|||||||
ATTR_HOST_IPC,
|
ATTR_HOST_IPC,
|
||||||
ATTR_HOST_NETWORK,
|
ATTR_HOST_NETWORK,
|
||||||
ATTR_HOST_PID,
|
ATTR_HOST_PID,
|
||||||
|
ATTR_HOST_UTS,
|
||||||
ATTR_IMAGE,
|
ATTR_IMAGE,
|
||||||
ATTR_INGRESS,
|
ATTR_INGRESS,
|
||||||
ATTR_INGRESS_ENTRY,
|
ATTR_INGRESS_ENTRY,
|
||||||
@ -283,6 +284,7 @@ _SCHEMA_ADDON_CONFIG = vol.Schema(
|
|||||||
vol.Optional(ATTR_HOST_NETWORK, default=False): vol.Boolean(),
|
vol.Optional(ATTR_HOST_NETWORK, default=False): vol.Boolean(),
|
||||||
vol.Optional(ATTR_HOST_PID, default=False): vol.Boolean(),
|
vol.Optional(ATTR_HOST_PID, default=False): vol.Boolean(),
|
||||||
vol.Optional(ATTR_HOST_IPC, default=False): vol.Boolean(),
|
vol.Optional(ATTR_HOST_IPC, default=False): vol.Boolean(),
|
||||||
|
vol.Optional(ATTR_HOST_UTS, default=False): vol.Boolean(),
|
||||||
vol.Optional(ATTR_HOST_DBUS, default=False): vol.Boolean(),
|
vol.Optional(ATTR_HOST_DBUS, default=False): vol.Boolean(),
|
||||||
vol.Optional(ATTR_DEVICES): [str],
|
vol.Optional(ATTR_DEVICES): [str],
|
||||||
vol.Optional(ATTR_UDEV, default=False): vol.Boolean(),
|
vol.Optional(ATTR_UDEV, default=False): vol.Boolean(),
|
||||||
|
@ -46,6 +46,7 @@ from ..const import (
|
|||||||
ATTR_HOST_IPC,
|
ATTR_HOST_IPC,
|
||||||
ATTR_HOST_NETWORK,
|
ATTR_HOST_NETWORK,
|
||||||
ATTR_HOST_PID,
|
ATTR_HOST_PID,
|
||||||
|
ATTR_HOST_UTS,
|
||||||
ATTR_HOSTNAME,
|
ATTR_HOSTNAME,
|
||||||
ATTR_ICON,
|
ATTR_ICON,
|
||||||
ATTR_INGRESS,
|
ATTR_INGRESS,
|
||||||
@ -216,6 +217,7 @@ class APIAddons(CoreSysAttributes):
|
|||||||
ATTR_HOST_NETWORK: addon.host_network,
|
ATTR_HOST_NETWORK: addon.host_network,
|
||||||
ATTR_HOST_PID: addon.host_pid,
|
ATTR_HOST_PID: addon.host_pid,
|
||||||
ATTR_HOST_IPC: addon.host_ipc,
|
ATTR_HOST_IPC: addon.host_ipc,
|
||||||
|
ATTR_HOST_UTS: addon.host_uts,
|
||||||
ATTR_HOST_DBUS: addon.host_dbus,
|
ATTR_HOST_DBUS: addon.host_dbus,
|
||||||
ATTR_PRIVILEGED: addon.privileged,
|
ATTR_PRIVILEGED: addon.privileged,
|
||||||
ATTR_FULL_ACCESS: addon.with_full_access,
|
ATTR_FULL_ACCESS: addon.with_full_access,
|
||||||
|
@ -181,6 +181,7 @@ ATTR_HOST_INTERNET = "host_internet"
|
|||||||
ATTR_HOST_IPC = "host_ipc"
|
ATTR_HOST_IPC = "host_ipc"
|
||||||
ATTR_HOST_NETWORK = "host_network"
|
ATTR_HOST_NETWORK = "host_network"
|
||||||
ATTR_HOST_PID = "host_pid"
|
ATTR_HOST_PID = "host_pid"
|
||||||
|
ATTR_HOST_UTS = "host_uts"
|
||||||
ATTR_HOSTNAME = "hostname"
|
ATTR_HOSTNAME = "hostname"
|
||||||
ATTR_ICON = "icon"
|
ATTR_ICON = "icon"
|
||||||
ATTR_ID = "id"
|
ATTR_ID = "id"
|
||||||
|
@ -265,6 +265,13 @@ class DockerAddon(DockerInterface):
|
|||||||
return "host"
|
return "host"
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
@property
|
||||||
|
def uts_mode(self) -> str | None:
|
||||||
|
"""Return UTS mode for add-on."""
|
||||||
|
if self.addon.host_uts:
|
||||||
|
return "host"
|
||||||
|
return None
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def capabilities(self) -> list[str] | None:
|
def capabilities(self) -> list[str] | None:
|
||||||
"""Generate needed capabilities."""
|
"""Generate needed capabilities."""
|
||||||
@ -472,18 +479,22 @@ class DockerAddon(DockerInterface):
|
|||||||
# Cleanup
|
# Cleanup
|
||||||
self._stop()
|
self._stop()
|
||||||
|
|
||||||
|
# Don't set a hostname if no separate UTS namespace is used
|
||||||
|
hostname = None if self.uts_mode else self.addon.hostname
|
||||||
|
|
||||||
# Create & Run container
|
# Create & Run container
|
||||||
try:
|
try:
|
||||||
docker_container = self.sys_docker.run(
|
docker_container = self.sys_docker.run(
|
||||||
self.image,
|
self.image,
|
||||||
tag=str(self.addon.version),
|
tag=str(self.addon.version),
|
||||||
name=self.name,
|
name=self.name,
|
||||||
hostname=self.addon.hostname,
|
hostname=hostname,
|
||||||
detach=True,
|
detach=True,
|
||||||
init=self.addon.default_init,
|
init=self.addon.default_init,
|
||||||
stdin_open=self.addon.with_stdin,
|
stdin_open=self.addon.with_stdin,
|
||||||
network_mode=self.network_mode,
|
network_mode=self.network_mode,
|
||||||
pid_mode=self.pid_mode,
|
pid_mode=self.pid_mode,
|
||||||
|
uts_mode=self.uts_mode,
|
||||||
ports=self.ports,
|
ports=self.ports,
|
||||||
extra_hosts=self.network_mapping,
|
extra_hosts=self.network_mapping,
|
||||||
device_cgroup_rules=self.cgroups_rules,
|
device_cgroup_rules=self.cgroups_rules,
|
||||||
|
@ -176,6 +176,7 @@ class DockerAPI:
|
|||||||
if dns:
|
if dns:
|
||||||
kwargs["dns"] = [str(self.network.dns)]
|
kwargs["dns"] = [str(self.network.dns)]
|
||||||
kwargs["dns_search"] = [DNS_SUFFIX]
|
kwargs["dns_search"] = [DNS_SUFFIX]
|
||||||
|
if hostname:
|
||||||
kwargs["domainname"] = DNS_SUFFIX
|
kwargs["domainname"] = DNS_SUFFIX
|
||||||
|
|
||||||
# Setup network
|
# Setup network
|
||||||
|
@ -23,6 +23,7 @@ def test_basic_config():
|
|||||||
assert not valid_config["host_ipc"]
|
assert not valid_config["host_ipc"]
|
||||||
assert not valid_config["host_dbus"]
|
assert not valid_config["host_dbus"]
|
||||||
assert not valid_config["host_pid"]
|
assert not valid_config["host_pid"]
|
||||||
|
assert not valid_config["host_uts"]
|
||||||
|
|
||||||
assert not valid_config["hassio_api"]
|
assert not valid_config["hassio_api"]
|
||||||
assert not valid_config["homeassistant_api"]
|
assert not valid_config["homeassistant_api"]
|
||||||
|
Loading…
x
Reference in New Issue
Block a user