Skip to content

setting up a hardened ovos-core under QubesOS

License

Notifications You must be signed in to change notification settings

OVOSHatchery/ovos-qubes

Repository files navigation

ovos-qubes

setting up a hardened ovos-core under QubesOS

Logo

Architecture

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

connections

gray - no internet
green - only whitelisted outgoing connections
yellow - internet access
  • sys-ovos-firewall
  • 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

Creating OVOS Qubes

qubes manager

template-ovos-base

  • 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"
    }

ovos-backend

  • create ovos-backend qubes from template-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
  • 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 a identity2.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 independent ovos-XXX qube

  • (optional) setup firewall rules, only allow outgoing connections to the domains of provided services

ovos-bus

  • create ovos-bus qubes from template-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

ovos-audio

  • create ovos-audio qubes from template-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
  • 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

ovos-skills

  • create ovos-skills qubes from template-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)
  • 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

ovos-speech

  • create ovos-speech qubes from template-ovos-base
  • (optional) select sys-ovos-firewall as NetVM
  • (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
  • 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
  • attach microphone

ovos-phal

  • create ovos-phal qubes from template-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)
  • 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

ovos-gui

  • create ovos-gui qubes from template-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

ovos-gui-client

  • 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
  • create ovos-gui-client qubes from focal 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

Connecting the Qubes

We need to open a TCP port to other network-isolated qubes for ovos-bus, ovos-gui and ovos-backend

exposed ports

  • expose port 8181
    • from ovos-bus to ovos-audio
    • from ovos-bus to ovos-speech
    • from ovos-bus to ovos-skills
    • from ovos-bus to ovos-gui
    • from ovos-bus to ovos-gui-client
    • from ovos-bus to ovos-phal
  • expose port 6712
    • from ovos-backend to ovos-skills
    • (optional) from ovos-backend to ovos-speech
      • required if using selene plugin
  • expose port 18181
    • from ovos-gui to ovos-gui-client

Hardening

Firewall ovos-backend

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

backend firewall

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

Choose an offline STT

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

How to

Enable ovos-backend

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

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 ovos-bus to other qubes

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 ovos-backend to other qubes

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 ovos-gui to other qubes

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 

Troubleshooting

No audio in ubuntu template

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

Releases

No releases published

Packages

No packages published