This guide adapts Opensnitch Nodes for Qubes OS from scratch. One offline “Server” qube running the Opensnitch GUI can filter the traffic of multiple “Node” qubes, the latter requiring only the Opensnitch daemon service. Communication is achieved by way of the qubes.ConnectTCP
service. The particular setup described below maintains compartmentalization at the expense of GUI effectiveness, so may not be the ideal setup for all use cases. It is nevertheless effective as an interactive filter.
About Opensnitch
an application firewall that allows for interactive outbound connections filtering. While the Opensnitch GUI is available for individual qubes, Opensnitch offers a server(GUI)/node(daemon) setup that is potentially better suited for filtering traffic originating from multiple qubes simultaneously.
Network-isolated Opensnitch GUI server
Opensnitch GUI Server template
1. Update & clone debian-12-minimal
If you only want a single GUI Server qube, it’s worth considering the latest release of Opensnitch in a Fedora minimal standalone. We’ll employ the Debian minimal template here.
in dom0 terminal:
$ sudo qubesctl --skip-dom0 --targets=debian-12-minimal --show-output state.sls update.qubes-vm
$ qvm-clone debian-12-minimal <DEBIAN-12-SERVER-TEMPLATE>
Note on `<ALLCAPS>`
indicates one is free to choose, in this case the name of the template.
2. Install Opensnitch
Newer releases are available on Github, including rpm packages, but we’ll install the older version available in the Debian stable repos. Once installed, Opensnitch will run automatically on startup, so it’s necessary to disable Opensnitch in the template and later enable it to run automatically in the Server and Node qubes.
in dom0 terminal:
$ qvm-run -u root --pass-io --no-gui <DEBIAN-12-SERVER-TEMPLATE> 'apt install opensnitch -y'
$ qvm-run -u root --pass-io --no-gui <DEBIAN-12-SERVER-TEMPLATE> 'systemctl stop opensnitch && systemctl disable opensnitch'
3. Verify Opensnitch is disabled in the template (optional)
Restart the template. You should see a grey cloud icon appear in the system tray. A black cloud would indicate that Opensnitch is enabled, which is undesireable in the template.
4. Modify the Opensnitch config files
In the template, modify Opensnitch daemon config files to listen on port 50051, rather than the default, which is to filter traffic originating from the Server qube itself. The configuration also defaults to iptables
, which should be changed to nftables
as of Qubes OS R4.2. These changes will be inherited by the GUI Server qube.
in <debian-12-server-template> root terminal:
# sed -i 's/iptables/nftables/g' /etc/opensnitchd/default-config.json
# sed -i 's/unix:\/\/\/tmp\/osui.sock/[::]:50051/g' /etc/opensnitchd/default-config.json
Close the template.
Opensnitch GUI Server qube setup
1. Create GUI Server app qube
The GUI Server qube does not require network access, so assign it a null netvm
.
in dom0 terminal:
$ qvm-create --template <DEBIAN-12-SERVER-TEMPLATE> --label <COLOR> <GUI-SERVER-QUBE>
$ qvm-prefs <GUI-SERVER-QUBE> netvm ""
2. Configure GUI Server qube
Since Opensnitch is disabled in the template, we have to reenable it in the app qube.
We also want the GUI to listen for the Node qubes. In the GUI config file, insert a line to specify a value for the variable server_address
under [global]
. In this case (below), we find that the end of the [global]
table is at line 10, so we insert it there (ymmv). This modification should tell the GUI to listen for Node qubes on port 50051.*
in <gui-server-qube> root terminal:
# echo "systemctl enable --now opensnitch" >> /rw/config/rc.local
# less -N /home/user/.config/opensnitch/settings.conf
# sed -i '10i server_address=[::]:50051' /home/user/.config/opensnitch/settings.conf
* should, but does not...
Despite our config change, the server address will still default to
unix:///tmp/osui.sock
, as hard coded in theopensnitch-ui
. A greyed out Opensnitch icon in the sys tray will result. It’s possible that we have not specified theserver_address
variable correctly, but I was unable to find example (s) in Github.
I’ll happily update this guide if anyone can identify a working specification forserver_address
, but until I have a fix, the next step will at least get it working.
3. Hack to modify Opensnitch default server address
Modify the executable in the template (modification in the GUI Server qube will not persist).
in <debian-12-server-template> root terminal:
# sed -i 's/unix:\/\/\/tmp\/osui.sock/[::]:50051/g' /usr/bin/opensnitch-ui
*
The Opensnitch GUI Server should now behave as expected on reboot, so we just need to set up our upstream app qubes to act as Opensnitch nodes.
Disposable Opensnitch Node qubes
Node template for app qubes and disposable templates
1. Update & clone debian-12-xfce
in dom0 terminal:
$ sudo qubesctl --skip-dom0 --targets=debian-12-xfce --show-output state.sls update.qubes-vm
$ qvm-clone debian-12-xfce <DEBIAN-12-NODE-TEMPLATE>
2. Install Opensnitch daemon
We can use the no-install-recommends
flag to install the Opensnitch daemon without the GUI and its dependencies.
in dom0 terminal:
$ qvm-run -u root --pass-io --no-gui <DEBIAN-12-NODE-TEMPLATE> 'apt install --no-install-recommends opensnitch -y'
$ qvm-run -u root --pass-io --no-gui <DEBIAN-12-NODE-TEMPLATE> 'systemctl stop opensnitch && systemctl disable opensnitch'
3. Modify Opensnitch config files
In the template, modify the Opensnitch daemon config files to use nftables
and to use the centralized GUI Server as the interactive filter. These changes will be inherited by the disposable template (or app qubes).
in <debian-12-node-template> root terminal:
# sed -i 's/iptables/nftables/g' /etc/opensnitchd/default-config.json
# sed -i 's/unix:\/\/\/tmp\/osui.sock/localhost:50051/g' /etc/opensnitchd/default-config.json
Close the template.
Disposable template for Node qubes
1. Create disposable template
in dom0 terminal:
$ qvm-create --template <DEBIAN-12-NODE-TEMPLATE> --label <COLOR> <DVM-NODE-TEMPLATE>
$ qvm-prefs <DVM-NODE-TEMPLATE> template_for_dispvms True
$ qvm-prefs <DVM-NODE-TEMPLATE> netvm <NETVM>
$ qvm-features <DVM-NODE-TEMPLATE> appmenus-dispvm 1
Refreshing applications under the Applications tab of the Settings Manager will allow you to show selected applications in the <dvm-node-template>
app menu.
2. Expose TCP port and enable Opensnitch
Allow the (disposable) Node qubes to communicate on port 50051 at startup. Note, the RPC service qubes.ConnectTCP
does not require networking between qubes.(2)
in <dvm-node-template> root terminal:
# echo "qvm-connect-tcp ::50051" >> /rw/config/rc.local
# echo "systemctl enable --now opensnitch" >> /rw/config/rc.local
Close <dvm-node-template>
.
3. Set the RPC policy
Allow communication between the GUI Server and (disposable) Node qubes by tagging <dvm-node-template>
and establishing the minimal necessary qubes RPC policy.
in dom0 terminal:
$ qvm-tags <DVM-NODE-TEMPLATE> add snitch
$ echo "qubes.ConnectTCP +50051 @tag:snitch @default allow target=<GUI-SERVER-QUBE>" >> /etc/qubes/policy.d/30-user.policy
With these settings, the Opensnitch GUI Server should run automatically in <gui-server-qube>
and filter traffic whenever a disposable Node qube is spawned from <dvm-node-template>
.
Opensnitch Rules
Rules generated in the GUI Server are saved and enforced locally in /etc/opensnitchd/rules/
of the disposable client Node. Hence, these rules will be lost when the disposable is closed. To preserve these rules, and lessen the human interaction with Opensnitch, they should be copied to <dvm-node-template>
. To make them available in the Node qubes, create a new directory in the disposable template where the JSON files can persist and have them automatically copied into the default rules path.(1)
in <dvm-node-template>
# mkdir -p /rw/config/opensnitchd/rules
# echo "sudo cp /rw/config/opensnitchd/rules/* /etc/opensnitchd/rules/" >> /rw/config/rc.local
(Notes)
Some notes and observed behaviors:
(1)
Syncthing, or similar, might be helpful here.
Opensnitch releases after v1.6.5 allow modification of the rules path via the config file, so one could simply use/rw/config/opensnitchd/rules/
. Since Debian Bookworm is on an older release, copying the rules into the default location will at least allow one to edit the rules in the GUI.
(2)
Use of thequbes.ConnectTCP
service in multiple Node qubes appears to confuse the GUI a bit. The GUI will only list the last node opened and if that disposable is closed, it will treat all nodes as offline, which causes the GUI to not display any new events. Nevertheless, the Opensnitch daemon(s) will continue to filter as expected.
(3)
The node for each rule will be listed as thelocalhost
. As a result, the rules created by any open Node qube will be applied to every other Node qube.
(4)
The rules are editable in the GUI, but within the GUI there will be some ambiguity about the identity of the Node qube that originated the rule and hence where any local changes will be applied. However, once saved, the changes will be reflected immediately in the JSON files.
(5)
Not sure if (4) matters in practice given (3).
While this setup is a good proof of concept, there appears to be some room for improvement, or at least alternative tradeoffs between GUI function and compartmentalization between the GUI Server qube and the Node qubes. GUI identification of nodes according to each qube’s
actual IP address
, rather than lumping them all together as127.0.0.1
would be a significant improvement, but presumably at some cost… Any helpful feedback is appreciated.