mirror of
https://github.com/home-assistant/supervisor.git
synced 2025-07-09 02:06:30 +00:00
Add support for Seccomp/AppArmor profiles
This commit is contained in:
parent
4eb24fcbc5
commit
72279072ac
2
API.md
2
API.md
@ -427,6 +427,8 @@ Get all available addons.
|
|||||||
"host_ipc": "bool",
|
"host_ipc": "bool",
|
||||||
"host_dbus": "bool",
|
"host_dbus": "bool",
|
||||||
"privileged": ["NET_ADMIN", "SYS_ADMIN"],
|
"privileged": ["NET_ADMIN", "SYS_ADMIN"],
|
||||||
|
"seccomp": "disable|default|custom",
|
||||||
|
"apparmor": "disable|default|custom",
|
||||||
"devices": ["/dev/xy"],
|
"devices": ["/dev/xy"],
|
||||||
"auto_uart": "bool",
|
"auto_uart": "bool",
|
||||||
"icon": "bool",
|
"icon": "bool",
|
||||||
|
@ -23,7 +23,9 @@ from ..const import (
|
|||||||
ATTR_STATE, ATTR_TIMEOUT, ATTR_AUTO_UPDATE, ATTR_NETWORK, ATTR_WEBUI,
|
ATTR_STATE, ATTR_TIMEOUT, ATTR_AUTO_UPDATE, ATTR_NETWORK, ATTR_WEBUI,
|
||||||
ATTR_HASSIO_API, ATTR_AUDIO, ATTR_AUDIO_OUTPUT, ATTR_AUDIO_INPUT,
|
ATTR_HASSIO_API, ATTR_AUDIO, ATTR_AUDIO_OUTPUT, ATTR_AUDIO_INPUT,
|
||||||
ATTR_GPIO, ATTR_HOMEASSISTANT_API, ATTR_STDIN, ATTR_LEGACY, ATTR_HOST_IPC,
|
ATTR_GPIO, ATTR_HOMEASSISTANT_API, ATTR_STDIN, ATTR_LEGACY, ATTR_HOST_IPC,
|
||||||
ATTR_HOST_DBUS, ATTR_AUTO_UART, ATTR_DISCOVERY, ATTR_SERVICES)
|
ATTR_HOST_DBUS, ATTR_AUTO_UART, ATTR_DISCOVERY, ATTR_SERVICES,
|
||||||
|
ATTR_SECCOMP, ATTR_APPARMOR, SECURITY_CUSTOM, SECURITY_DISABLE,
|
||||||
|
SECURITY_DEFAULT)
|
||||||
from ..coresys import CoreSysAttributes
|
from ..coresys import CoreSysAttributes
|
||||||
from ..docker.addon import DockerAddon
|
from ..docker.addon import DockerAddon
|
||||||
from ..utils.json import write_json_file, read_json_file
|
from ..utils.json import write_json_file, read_json_file
|
||||||
@ -316,6 +318,29 @@ class Addon(CoreSysAttributes):
|
|||||||
"""Return list of privilege."""
|
"""Return list of privilege."""
|
||||||
return self._mesh.get(ATTR_PRIVILEGED)
|
return self._mesh.get(ATTR_PRIVILEGED)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def seccomp(self):
|
||||||
|
"""Return True if seccomp is enabled."""
|
||||||
|
if not self._mesh.get(ATTR_SECCOMP):
|
||||||
|
return SECURITY_DISABLE
|
||||||
|
elif self.path_seccomp.exists():
|
||||||
|
return SECURITY_CUSTOM
|
||||||
|
return SECURITY_DEFAULT
|
||||||
|
|
||||||
|
@property
|
||||||
|
def apparmor(self):
|
||||||
|
"""Return True if seccomp is enabled."""
|
||||||
|
if not self._mesh.get(ATTR_SECCOMP):
|
||||||
|
return SECURITY_DISABLE
|
||||||
|
elif self.path_apparmor.exists():
|
||||||
|
return SECURITY_CUSTOM
|
||||||
|
return SECURITY_DEFAULT
|
||||||
|
|
||||||
|
@property
|
||||||
|
def seccomp_profile(self):
|
||||||
|
"""Return True if it not use the default profile."""
|
||||||
|
return Path(self.path_location, f"{ATTR_SECCOMP}.json").exists()
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def legacy(self):
|
def legacy(self):
|
||||||
"""Return if the add-on don't support hass labels."""
|
"""Return if the add-on don't support hass labels."""
|
||||||
@ -474,6 +499,16 @@ class Addon(CoreSysAttributes):
|
|||||||
"""Return path to addon changelog."""
|
"""Return path to addon changelog."""
|
||||||
return Path(self.path_location, 'CHANGELOG.md')
|
return Path(self.path_location, 'CHANGELOG.md')
|
||||||
|
|
||||||
|
@property
|
||||||
|
def path_seccomp(self):
|
||||||
|
"""Return path to custom seccomp profile."""
|
||||||
|
return Path(self.path_location, 'seccomp.json')
|
||||||
|
|
||||||
|
@property
|
||||||
|
def path_apparmor(self):
|
||||||
|
"""Return path to custom AppArmor profile."""
|
||||||
|
return Path(self.path_location, 'apparmor')
|
||||||
|
|
||||||
def save_data(self):
|
def save_data(self):
|
||||||
"""Save data of addon."""
|
"""Save data of addon."""
|
||||||
self._addons.data.save_data()
|
self._addons.data.save_data()
|
||||||
|
@ -17,7 +17,8 @@ from ..const import (
|
|||||||
ATTR_AUTO_UPDATE, ATTR_WEBUI, ATTR_AUDIO, ATTR_AUDIO_INPUT, ATTR_HOST_IPC,
|
ATTR_AUTO_UPDATE, ATTR_WEBUI, ATTR_AUDIO, ATTR_AUDIO_INPUT, ATTR_HOST_IPC,
|
||||||
ATTR_AUDIO_OUTPUT, ATTR_HASSIO_API, ATTR_BUILD_FROM, ATTR_SQUASH,
|
ATTR_AUDIO_OUTPUT, ATTR_HASSIO_API, ATTR_BUILD_FROM, ATTR_SQUASH,
|
||||||
ATTR_ARGS, ATTR_GPIO, ATTR_HOMEASSISTANT_API, ATTR_STDIN, ATTR_LEGACY,
|
ATTR_ARGS, ATTR_GPIO, ATTR_HOMEASSISTANT_API, ATTR_STDIN, ATTR_LEGACY,
|
||||||
ATTR_HOST_DBUS, ATTR_AUTO_UART, ATTR_SERVICES, ATTR_DISCOVERY)
|
ATTR_HOST_DBUS, ATTR_AUTO_UART, ATTR_SERVICES, ATTR_DISCOVERY,
|
||||||
|
ATTR_SECCOMP, ATTR_APPARMOR)
|
||||||
from ..validate import NETWORK_PORT, DOCKER_PORTS, ALSA_CHANNEL
|
from ..validate import NETWORK_PORT, DOCKER_PORTS, ALSA_CHANNEL
|
||||||
|
|
||||||
_LOGGER = logging.getLogger(__name__)
|
_LOGGER = logging.getLogger(__name__)
|
||||||
@ -107,6 +108,8 @@ SCHEMA_ADDON_CONFIG = vol.Schema({
|
|||||||
vol.Optional(ATTR_MAP, default=list): [vol.Match(RE_VOLUME)],
|
vol.Optional(ATTR_MAP, default=list): [vol.Match(RE_VOLUME)],
|
||||||
vol.Optional(ATTR_ENVIRONMENT): {vol.Match(r"\w*"): vol.Coerce(str)},
|
vol.Optional(ATTR_ENVIRONMENT): {vol.Match(r"\w*"): vol.Coerce(str)},
|
||||||
vol.Optional(ATTR_PRIVILEGED): [vol.In(PRIVILEGED_ALL)],
|
vol.Optional(ATTR_PRIVILEGED): [vol.In(PRIVILEGED_ALL)],
|
||||||
|
vol.Optional(ATTR_SECCOMP, default=True): vol.Boolean(),
|
||||||
|
vol.Optional(ATTR_APPARMOR, default=True): vol.Boolean(),
|
||||||
vol.Optional(ATTR_AUDIO, default=False): vol.Boolean(),
|
vol.Optional(ATTR_AUDIO, default=False): vol.Boolean(),
|
||||||
vol.Optional(ATTR_GPIO, default=False): vol.Boolean(),
|
vol.Optional(ATTR_GPIO, default=False): vol.Boolean(),
|
||||||
vol.Optional(ATTR_HASSIO_API, default=False): vol.Boolean(),
|
vol.Optional(ATTR_HASSIO_API, default=False): vol.Boolean(),
|
||||||
|
@ -17,7 +17,7 @@ from ..const import (
|
|||||||
ATTR_CHANGELOG, ATTR_HOST_IPC, ATTR_HOST_DBUS, ATTR_LONG_DESCRIPTION,
|
ATTR_CHANGELOG, ATTR_HOST_IPC, ATTR_HOST_DBUS, ATTR_LONG_DESCRIPTION,
|
||||||
ATTR_CPU_PERCENT, ATTR_MEMORY_LIMIT, ATTR_MEMORY_USAGE, ATTR_NETWORK_TX,
|
ATTR_CPU_PERCENT, ATTR_MEMORY_LIMIT, ATTR_MEMORY_USAGE, ATTR_NETWORK_TX,
|
||||||
ATTR_NETWORK_RX, ATTR_BLK_READ, ATTR_BLK_WRITE, ATTR_ICON, ATTR_SERVICES,
|
ATTR_NETWORK_RX, ATTR_BLK_READ, ATTR_BLK_WRITE, ATTR_ICON, ATTR_SERVICES,
|
||||||
ATTR_DISCOVERY,
|
ATTR_DISCOVERY, ATTR_SECCOMP, ATTR_APPARMOR,
|
||||||
CONTENT_TYPE_PNG, CONTENT_TYPE_BINARY, CONTENT_TYPE_TEXT)
|
CONTENT_TYPE_PNG, CONTENT_TYPE_BINARY, CONTENT_TYPE_TEXT)
|
||||||
from ..coresys import CoreSysAttributes
|
from ..coresys import CoreSysAttributes
|
||||||
from ..validate import DOCKER_PORTS
|
from ..validate import DOCKER_PORTS
|
||||||
@ -123,6 +123,8 @@ class APIAddons(CoreSysAttributes):
|
|||||||
ATTR_HOST_IPC: addon.host_ipc,
|
ATTR_HOST_IPC: addon.host_ipc,
|
||||||
ATTR_HOST_DBUS: addon.host_dbus,
|
ATTR_HOST_DBUS: addon.host_dbus,
|
||||||
ATTR_PRIVILEGED: addon.privileged,
|
ATTR_PRIVILEGED: addon.privileged,
|
||||||
|
ATTR_SECCOMP: addon.seccomp,
|
||||||
|
ATTR_APPARMOR: addon.apparmor,
|
||||||
ATTR_DEVICES: self._pretty_devices(addon),
|
ATTR_DEVICES: self._pretty_devices(addon),
|
||||||
ATTR_ICON: addon.with_icon,
|
ATTR_ICON: addon.with_icon,
|
||||||
ATTR_LOGO: addon.with_logo,
|
ATTR_LOGO: addon.with_logo,
|
||||||
|
@ -159,6 +159,8 @@ ATTR_DISCOVERY = 'discovery'
|
|||||||
ATTR_PROTECTED = 'protected'
|
ATTR_PROTECTED = 'protected'
|
||||||
ATTR_CRYPTO = 'crypto'
|
ATTR_CRYPTO = 'crypto'
|
||||||
ATTR_BRANCH = 'branch'
|
ATTR_BRANCH = 'branch'
|
||||||
|
ATTR_SECCOMP = 'seccomp'
|
||||||
|
ATTR_APPARMOR = 'apparmor'
|
||||||
|
|
||||||
SERVICE_MQTT = 'mqtt'
|
SERVICE_MQTT = 'mqtt'
|
||||||
|
|
||||||
@ -202,3 +204,7 @@ SNAPSHOT_FULL = 'full'
|
|||||||
SNAPSHOT_PARTIAL = 'partial'
|
SNAPSHOT_PARTIAL = 'partial'
|
||||||
|
|
||||||
CRYPTO_AES128 = 'aes128'
|
CRYPTO_AES128 = 'aes128'
|
||||||
|
|
||||||
|
SECURITY_CUSTOM = 'custom'
|
||||||
|
SECURITY_DEFAULT = 'default'
|
||||||
|
SECURITY_DISABLE = 'disable'
|
||||||
|
@ -9,7 +9,7 @@ from .interface import DockerInterface
|
|||||||
from ..addons.build import AddonBuild
|
from ..addons.build import AddonBuild
|
||||||
from ..const import (
|
from ..const import (
|
||||||
MAP_CONFIG, MAP_SSL, MAP_ADDONS, MAP_BACKUP, MAP_SHARE, ENV_TOKEN,
|
MAP_CONFIG, MAP_SSL, MAP_ADDONS, MAP_BACKUP, MAP_SHARE, ENV_TOKEN,
|
||||||
ENV_TIME)
|
ENV_TIME, SECURITY_CUSTOM, SECURITY_DISABLE)
|
||||||
from ..utils import process_lock
|
from ..utils import process_lock
|
||||||
|
|
||||||
_LOGGER = logging.getLogger(__name__)
|
_LOGGER = logging.getLogger(__name__)
|
||||||
@ -121,14 +121,21 @@ class DockerAddon(DockerInterface):
|
|||||||
@property
|
@property
|
||||||
def security_opt(self):
|
def security_opt(self):
|
||||||
"""Controlling security opt."""
|
"""Controlling security opt."""
|
||||||
privileged = self.addon.privileged or []
|
security = []
|
||||||
|
|
||||||
# Disable AppArmor sinse it make troubles wit SYS_ADMIN
|
# AppArmor
|
||||||
if 'SYS_ADMIN' in privileged:
|
if self.addon.apparmor == SECURITY_DISABLE:
|
||||||
return [
|
security.append("apparmor:unconfined")
|
||||||
"apparmor:unconfined",
|
elif self.addon.apparmor == SECURITY_DEFAULT:
|
||||||
]
|
security.append(f"apparmor={self.addon.slug}")
|
||||||
return None
|
|
||||||
|
# Seccomp
|
||||||
|
if self.addon.seccomp == SECURITY_DISABLE:
|
||||||
|
security.append("seccomp=unconfined")
|
||||||
|
elif self.addon.seccomp == SECURITY_CUSTOM:
|
||||||
|
security.append(f"seccomp={self.addon.path_seccomp}")
|
||||||
|
|
||||||
|
return security or None
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def tmpfs(self):
|
def tmpfs(self):
|
||||||
|
Loading…
x
Reference in New Issue
Block a user