setting up a hardened ovos-core under QubesOS
The aim here is to bring maximum isolation between services and reduce the chance that a misbehaved component can mess with the system
Considerations:
- one ovos service corresponds to one qube
- whenever possible a service is disconnected from the internet
- whenever possible a service is firewalled to only allow specific outgoing connections
gray - no internet
green - only whitelisted outgoing connections
yellow - internet access
- sys-ovos-firewall
- DispVM
- set firewall rules
- can be connected sys-vpn
- can use mirage firewall unikernel
- all networked ovos qubes connect here
- template-ovos-base
- templateVM
- /etc/mycroft/mycroft.conf lives here
- system packages installed/updated here
- ovos-backend
- AppVM
- ovos-local-backend installed as user
- sys-ovos-firewall needed for API services / remote STT
- 6712 port exposed to other ovos qubes
- can be configured as a selene proxy if desired
- ovos-bus
- AppVM
- ovos-bus installed as user
- sys-ovos-firewall not needed
- 8181 port exposed to other ovos qubes
- ovos-gui
- AppVM
- ovos-gui installed as user
- sys-ovos-firewall not needed
- 18181 port exposed to ovos-gui-client qubes
- ovos-audio
- AppVM
- ovos-audio installed as user
- sys-ovos-firewall needed for stream playback / remote TTS
- ovos-speech
- AppVM
- ovos-speech installed as user
- sys-ovos-firewall needed for remote STT
- mic needs to be explicitly attached
- ovos-skills
- AppVM
- ovos-skills installed as user
- sys-ovos-firewall needed for internet skills
- ovos-phal
- AppVM
- ovos-PHAL installed as user
- dedicated plugins for qubes need to be written
⚠️
- ovos-gui-client
- StandaloneVM
- based on ubuntu template
- mycroft-gui installed as user from source
- sys-ovos-firewall needed for stream playback / web browsing / remote pictures
- clone a debian template VM as
template-ovos-base
- debloat the image
sudo apt purge firefox-esr thunderbird keepassxc nautilus sudo apt purge emacs* sudo apt purge vim* sudo apt autoremove
- install system packages
sudo apt-get install python3-pip swig libfann-dev portaudio19-dev libpulse-dev libespeak-ng1 sudo apt-get install qubes-core-agent-dom0-updates qubes-core-agent-passwordless-root
- create mycroft.conf
sudo mkdir /etc/mycroft sudo nano /etc/mycroft/mycroft.conf
- configure to your liking
{ "lang": "en-us", "time_format": "full", "date_format": "DMY", "gui": { "extension": "smartspeaker", "idle_display_skill": "skill-ovos-homescreen.openvoiceos" }, "stt": {"module": "ovos-stt-plugin-vosk"}, "tts": {"module": "ovos-tts-plugin-mimic3"}, "padatious": {"regex_only": true}, "server": { "disabled": true }, "debug": true, "log_level": "DEBUG" }
-
create
ovos-backend
qubes fromtemplate-ovos-base
-
select
sys-ovos-firewall
as NetVM -
(optional) make this qube launch on boot
-
install ovos-local-backend (no sudo!)
pip install git+https://github.com/OpenVoiceOS/OVOS-local-backend
-
install extra STT plugins
- system dependencies (if any) need to be installed in
template-ovos-base
- install recommended plugins
pip install ovos-stt-plugin-server pip install ovos-stt-plugin-vosk
- system dependencies (if any) need to be installed in
-
configure backend
nano ~/.config/json_database/ovos_backend.json
{ "stt": { "module": "ovos-stt-plugin-server", "ovos-stt-plugin-server": {"url": "https://stt.openvoiceos.com/stt"} }, "selene": { "enabled": false, "proxy_pairing": true }, "backend_port": 6712, "skip_auth": true, "geolocate": true, "override_location": false, "api_version": "v1", "data_path": "~", "record_utterances": false, "record_wakewords": false, "wolfram_key": "$KEY", "owm_key": "$KEY", "lang": "en-us", "date_format": "DMY", "system_unit": "metric", "time_format": "full", "default_location": { "city": {"...": "..."}, "coordinate": {"...": "..."}, "timezone": {"...": "..."} } }
⚠️ only ovos-skills will have aidentity2.json
,"skip_auth"
needs to be set, pairing is not shared across ovos qubes⚠️ -
create auto_start.sh
nano auto-start.sh
/home/user/.local/bin/ovos-local-backend >> /home/user/backend.log 2>&1 &
-
create .desktop file to autostart ovos-backend when the VM boots
nano /home/user/.config/autostart/ovos-backend.desktop
[Desktop Entry] Name=OVOS Local Backend Exec=bash /home/user/auto-start.sh Type=Application StartupNotify=true NoDisplay=true
-
Enable ovos-backend in
template-ovos-base
or in every independentovos-XXX
qube -
(optional) setup firewall rules, only allow outgoing connections to the domains of provided services
- create
ovos-bus
qubes fromtemplate-ovos-base
- set none as NetVM, this service does not need to reach to the internet
- (optional) make this qube launch on boot
- install ovos-bus (no sudo!)
pip install ovos-core[bus]
- create auto_start.sh
nano auto-start.sh
/home/user/.local/bin/mycroft-messagebus >> /home/user/bus.log 2>&1 &
- create .desktop file to autostart ovos-bus when the VM
boots
nano /home/user/.config/autostart/mycroft-messagebus.desktop
[Desktop Entry] Name=OVOS Messagebus Exec=bash /home/user/auto-start.sh Type=Application StartupNotify=true NoDisplay=true
- (optional) disable ovos-backend
- create
ovos-audio
qubes fromtemplate-ovos-base
- select
sys-ovos-firewall
as NetVM - (optional) make this qube launch on boot
- install ovos-audio (no sudo!)
pip install ovos-core[audio,tts,audio_backend]
- install extra TTS plugins
- system dependencies (if any) need to be installed in
template-ovos-base
- install recommended plugins
pip install ovos-tts-plugin-marytts pip install ovos-tts-plugin-mimic3
- system dependencies (if any) need to be installed in
- create auto_start.sh
nano auto-start.sh
/home/user/.local/bin/mycroft-audio >> /home/user/audio.log 2>&1 &
- create .desktop file to autostart ovos-audio when the VM
boots
nano /home/user/.config/autostart/mycroft-audio.desktop
[Desktop Entry] Name=OVOS Audio Service Exec=bash /home/user/auto-start.sh Type=Application StartupNotify=true NoDisplay=true
- expose ovos-bus to ovos-audio
- (optional) Enable ovos-backend
- you need to copy identity2.json from ovos-skills to keep the device uuid
- (optional) setup firewall rules, only allow outgoing connections to the domains of remote TTS
- create
ovos-skills
qubes fromtemplate-ovos-base
- select
sys-ovos-firewall
as NetVM - (optional) make this qube launch on boot
- install ovos-skills (no sudo!)
pip install ovos-core[skills]
- install skills
- system dependencies (if any) need to be installed in
template-ovos-base
- install recommended skills (TODO add list)
- system dependencies (if any) need to be installed in
- create auto_start.sh
nano auto-start.sh
/home/user/.local/bin/mycroft-skills >> /home/user/skills.log 2>&1 &
- create .desktop file to autostart ovos-skills when the VM
boots
nano /home/user/.config/autostart/mycroft-skills.desktop
[Desktop Entry] Name=OVOS Skills Service Exec=bash /home/user/auto-start.sh Type=Application StartupNotify=true NoDisplay=true
- expose ovos-bus to ovos-skills
- (optional) Enable ovos-backend
- create
ovos-speech
qubes fromtemplate-ovos-base
- (optional) select
sys-ovos-firewall
as NetVM- not needed if you choose an offline STT
- (optional) make this qube launch on boot
- install ovos-speech (no sudo!)
pip install ovos-core[stt]
- install extra STT plugins
- system dependencies (if any) need to be installed in
template-ovos-base
- install recommended plugins
pip install ovos-stt-plugin-selene pip install ovos-stt-plugin-vosk pip install ovos-stt-plugin-chromium
- system dependencies (if any) need to be installed in
- create auto_start.sh
nano auto-start.sh
/home/user/.local/bin/mycroft-speech-client >> /home/user/stt.log 2>&1 &
- create .desktop file to autostart ovos-speech when the VM
boots
nano /home/user/.config/autostart/mycroft-stt.desktop
[Desktop Entry] Name=OVOS Speech Client Exec=bash /home/user/auto-start.sh Type=Application StartupNotify=true NoDisplay=true
- expose ovos-bus to ovos-speech
- (optional) Enable ovos-backend
- integrates with selene stt plugin
- if using selene stt plugin you can set NetVM to none
- you need to copy identity2.json from ovos-skills to keep the device uuid
- integrates with selene stt plugin
- attach microphone
- create
ovos-phal
qubes fromtemplate-ovos-base
- select
sys-ovos-firewall
as NetVM- depending on plugins installed this may be set to None
- (optional) make this qube launch on boot
- install ovos-phal (no sudo!)
pip install ovos-phal
- install phal plugins
- system dependencies (if any) need to be installed in
template-ovos-base
- install recommended plugins (TODO add list)
- system dependencies (if any) need to be installed in
- create auto_start.sh
nano auto-start.sh
/home/user/.local/bin/ovos_PHAL >> /home/user/phal.log 2>&1 &
- create .desktop file to autostart ovos-phal when the VM boots
nano /home/user/.config/autostart/PHAL.desktop
[Desktop Entry] Name=OVOS PHAL Service Exec=bash /home/user/auto-start.sh Type=Application StartupNotify=true NoDisplay=true
- expose ovos-bus to ovos-phal
- (optional) disable ovos-backend
- create
ovos-gui
qubes fromtemplate-ovos-base
- set none as NetVM, this service does not need to reach to the internet
- (optional) make this qube launch on boot
- install ovos-gui (no sudo!)
pip install ovos-core[gui]
- create auto_start.sh
nano auto-start.sh
/home/user/.local/bin/mycroft-gui-service >> /home/user/gui.log 2>&1 &
- create .desktop file to autostart ovos-gui when the VM
boots
nano /home/user/.config/autostart/mycroft-gui-messagebus.desktop
[Desktop Entry] Name=OVOS GUI Messagebus Exec=bash /home/user/auto-start.sh Type=Application StartupNotify=true NoDisplay=true
- expose ovos-bus to ovos-gui
- (optional) disable ovos-backend
- install community ubuntu template in dom0
- download here to some qube, eg
dl_qube
- copy downloaded file to
dom0
qvm-run --pass-io dl_qube 'cat /home/user/Downloads/focal.rpm' > /home/user/focal.rpm
- install
sudo dnf install focal.rpm
⚠️ Fix no audio bug
- download here to some qube, eg
- create
ovos-gui-client
qubes fromfocal
as a StandaloneVM - select
sys-ovos-firewall
as NetVM - install mycroft-gui
git clone https://github.com/MycroftAI/mycroft-gui cd mycroft-gui ./dev_setup.sh
- expose ovos-bus to ovos-gui-client
- expose ovos-gui to ovos-gui-client
- launch
mycroft-gui-app
from this qube when wanted- (optional) launch on qube on boot
- (optional) launch mycroft gui on VM startup
We need to open a TCP port to other network-isolated qubes for ovos-bus, ovos-gui and ovos-backend
- expose port 8181
- from
ovos-bus
toovos-audio
- from
ovos-bus
toovos-speech
- from
ovos-bus
toovos-skills
- from
ovos-bus
toovos-gui
- from
ovos-bus
toovos-gui-client
- from
ovos-bus
toovos-phal
- from
- expose port 6712
- from
ovos-backend
toovos-skills
- (optional) from
ovos-backend
toovos-speech
- required if using selene plugin
- from
- expose port 18181
- from
ovos-gui
toovos-gui-client
- from
ovos-backend can be restricted to only allow certain outgoing connections, this is a very good idea since we know exactly which services this qube needs to connect and why
service | domain | used for | required by | disabled by |
---|---|---|---|---|
IPify | api.ipify.org | ip geolocation | "geolocate": true |
"override_location": true |
OpenWeatherMap | api.openweathermap.org | weather api | "owm_key": "your_key" |
"proxy_weather": true |
OpenStreetMap | nominatim.openstreetmap.org | geolocation api | default | "proxy_geolocation": true |
WolframAlpha | api.wolframalpha.com | wolfram alpha api | "wolfram_key": "your_key" |
"proxy_wolfram": true |
OpenVoiceOS | openvoiceos.com | free microservice proxies | default | "xxx_key": "your_key" or "proxy_xxx": true (wolfram + weather) |
Email Service | ? | SMTP email server | "email": {"..."} |
"proxy_email": true |
STT Service | ? | remote STT transcription | some stt plugins | default |
Selene | api.mycroft.ai | selene proxy integration | "selene": {"enabled": true} |
default |
There are some offline STT options listed below, if any of those is acceptable to you then you should configure ovos-qubes to use it, this way your speech will never leave your computer
Option 1 - directly in ovos-speech
- configure
~/.config/mycroft/mycroft.conf
to use your offline-stt-plugin - ensure ovos-speech has no NetVM
- (optional) disable ovos-backend
- ovos-backend only needed if you want metrics upload
Option 2 - in ovos-backend
- configure
~/.config/mycroft/mycroft.conf
to use your ovos-backend - configure
~/.config/mycroft/mycroft.conf
to use your selene-plugin - configure
~/.config/json_database/ovos_backend.json
to use your offline-stt-plugin - expose ovos-backend to ovos-speech
- ensure ovos-speech has no NetVM
- ovos-backend will still be available
By default ovos-core does not use a backend, we need to explicitly enable ovos-backend in mycroft.conf
to enable ovos-backend edit mycroft.conf in the desired qubes with the following
{
"server": {
"disabled": false,
"url": "http://0.0.0.0:6712",
"version": "v1",
"update": true,
"metrics": true
},
"listener": {
"wake_word_upload": {
"url": "http://0.0.0.0:6712/precise/upload"
}
},
"opt_in": true
}
to disable backend edit mycroft.conf with the following
{
"server": {
"disabled": true
}
}
Option 1 - globally, in template-ovos-base
- edit
/etc/mycroft/mycroft.conf
- expose ovos-backend to every ovos-XXX qubes
Option 2 - selectively, per qube
- edit
~/.config/mycroft/mycroft.conf
in ovos-XXX - enable backend in ovos-skills
- expose ovos-backend to ovos-skills
- needed for pairing process
- needed for metrics
- needed for device configuration via backend (location, preferences, skill settings)
- needed for skills that use the microservices (email, geolocation, weather, wolfram alpha)
- (optional) enable backend in ovos-audio
- expose ovos-backend to ovos-audio
- needed for metrics
- needed for tts configuration via backend
- copy identity2.json from ovos-skills or enable
skip_auth
in backend config
- (optional) enable backend in ovos-speech
- expose ovos-backend to ovos-speech
- needed for metrics
- needed for wake word configuration via backend
- needed for ovos-stt-plugin-selene
- needed for wake word upload
- needed for utterance upload
- copy identity2.json from ovos-skills or enable
skip_auth
in backend config
- disable backend in ovos-bus, it's not used
- disable backend in ovos-gui, it's not used
- disable backend in ovos-phal, it's not used
expose port 8181 from ovos-bus
to ovos-XXX
qube
- open a terminal in
dom0
sudo nano /etc/qubes-rpc/policy/qubes.ConnectTCP
- add a new line with
ovos-XXX @default allow, target=ovos-bus
for every ovos qube - a reboot will needed for change to take effect
open a terminal in ovos-XXX
and create the system services to open a socket and connect to ovos-bus on launch
- create bus.socket
sudo nano /rw/config/bus.socket
[Unit]
Description=ovos-bus-service
[Socket]
ListenStream=127.0.0.1:8181
Accept=true
[Install]
WantedBy=sockets.target
- create bus.service
sudo nano bus@.service
[Unit]
Description=ovos-bus
[Service]
ExecStart=qrexec-client-vm '' qubes.ConnectTCP+8181
StandardInput=socket
StandardOutput=inherit
- edit rc.local to launch the service on qube launch
sudo /rw/config/rc.local
#!/bin/sh
# This script will be executed at every VM startup, you can place your own
# custom commands here. This includes overriding some configuration in /etc,
# starting services etc.
cp -r /rw/config/bus.socket /rw/config/bus@.service /lib/systemd/system/
systemctl daemon-reload
systemctl start bus.socket
expose port 6712 from ovos-backend
to ovos-XXX
qube
- open a terminal in
dom0
sudo nano /etc/qubes-rpc/policy/qubes.ConnectTCP
- add a new line with
ovos-XXX @default allow, target=ovos-backend
for every ovos qube - a reboot will needed for change to take effect
open a terminal in ovos-XXX
and create the system services to open a socket and connect to ovos-backend on launch
- create backend.socket
sudo nano /rw/config/backend.socket
[Unit]
Description=ovos-backend-service
[Socket]
ListenStream=127.0.0.1:6712
Accept=true
[Install]
WantedBy=sockets.target
- create backend.service
sudo nano backend@.service
[Unit]
Description=ovos-backend
[Service]
ExecStart=qrexec-client-vm '' qubes.ConnectTCP+6712
StandardInput=socket
StandardOutput=inherit
- edit rc.local to launch the service on qube launch
sudo /rw/config/rc.local
#!/bin/sh
# This script will be executed at every VM startup, you can place your own
# custom commands here. This includes overriding some configuration in /etc,
# starting services etc.
cp -r /rw/config/backend.socket /rw/config/backend@.service /lib/systemd/system/
systemctl daemon-reload
systemctl start backend.socket
expose port 18181 from ovos-gui
to ovos-XXX
qube
- open a terminal in
dom0
sudo nano /etc/qubes-rpc/policy/qubes.ConnectTCP
- add a new line with
ovos-XXX @default allow, target=ovos-gui
- a reboot will needed for change to take effect
open a terminal in ovos-gui-client
and create the system service to open a socket and connect to ovos-gui on launch
- create gui.socket
sudo nano /rw/config/gui.socket
[Unit]
Description=ovos-gui-service
[Socket]
ListenStream=127.0.0.1:18181
Accept=true
[Install]
WantedBy=sockets.target
- create gui.service
sudo nano gui@.service
[Unit]
Description=ovos-gui
[Service]
ExecStart=qrexec-client-vm '' qubes.ConnectTCP+18181
StandardInput=socket
StandardOutput=inherit
- edit rc.local to launch the service on qube launch
sudo /rw/config/rc.local
#!/bin/sh
# This script will be executed at every VM startup, you can place your own
# custom commands here. This includes overriding some configuration in /etc,
# starting services etc.
cp -r /rw/config/gui.socket /rw/config/gui@.service /lib/systemd/system/
systemctl daemon-reload
systemctl start gui.socket
There seems to be a bug in the ubuntu template recommended above
To fix this open a terminal in your ubuntu template + standaloneVMs and run
sudo ln -s /lib/pulse-13.99/modules/module-vchan-sink.so /lib/pulse-13.99.1/modules/module-vchan-sink.so