Does anyone use Mirage Firewall on a regular basis?

How stable is Mirage Firewall in daily use?

I found two “guides.” Has anyone used one of them?

https://gist.github.com/100111001/4eca0f78ed69d597d562a1515168fa6c
# How to install the superlight mirage-firewall for Qubes OS by using saltstack
# Tested on Qubes v4.2 and mirage v0.9.5
# No integrity checks are performed. Latest release version of mirage is downloaded and installed into dom0
# After the install, you have to switch your AppVMs to use the mirage firewall vm created by this script
# inspired by: https://github.com/one7two99/my-qubes/tree/master/mirage-firewall

# inspired by: https://github.com/one7two99/my-qubes/tree/master/mirage-firewall

# default template + dispvm template are used. Possible optimization is to use min-dvms
{% set DownloadVMTemplate = salt['cmd.shell']("qubes-prefs default_template") %}
{% set DispVM = salt['cmd.shell']("qubes-prefs default_dispvm") %}

{% set DownloadVM = "DownloadVmMirage" %}
{% set MirageFW = "sys-mirage-fw" %}
{% set GithubUrl = "https://github.com/mirage/qubes-mirage-firewall" %}
{% set Filename = "qubes-firewall.xen" %}
{% set MirageInstallDir = "/var/lib/qubes/vm-kernels/mirage-firewall" %}

#download and install fixed version
{# % set Release = "v0.8.4" % #}
#or latest version
#command to get the latest version: Release=`curl --silent --location -o /dev/null -w %{url_effective} $GithubUrl/releases/latest | rev | cut -d "/" -f 1 | rev` 

{% set Release = salt['cmd.shell']("qvm-run --dispvm " ~ DispVM ~ " --pass-io \"curl --silent --location -o /dev/null -w %{url_effective} " ~ GithubUrl ~ "/releases/latest | rev | cut -d \"/\" -f 1 | rev\"") %}

{# % set sha2FromLastBuild = salt['cmd.shell']("qvm-run --pass-io --dispvm " ~ DispVM ~ " \"curl -s https://raw.githubusercontent.com/mirage/qubes-mirage-firewall/refs/heads/main/qubes-firewall-release.sha256  | cut -d\' \' -f1 \" ") % #}

{% if Release != salt['cmd.shell']("[ ! -f " ~ MirageInstallDir ~ "/version.txt" ~ " ] && touch " ~ MirageInstallDir ~ "/version.txt" ~ ";cat " ~ MirageInstallDir ~ "/version.txt") %}

create-downloader-VM:
  qvm.vm:
     - name: {{ DownloadVM }}
     - present:
       - template: {{ DownloadVMTemplate }}
       - label: red
     - prefs:
       - template: {{ DownloadVMTemplate }}
       - include-in-backups: false

{% set DownloadBinary = GithubUrl ~ "/releases/download/" ~ Release ~ "/" ~ Filename %}

download-and-unpack-in-DownloadVM4mirage:
  cmd.run: 
    - names:
      - qvm-run --pass-io {{ DownloadVM }} {{ "curl -L -O " ~ DownloadBinary }}
    - require: 
      - create-downloader-VM


check-checksum-in-DownloadVM:
  cmd.run: 
    - names:
      - qvm-run --pass-io {{ DownloadVM }} {{ "\"echo \\\"Checksum of last build on github:\\\";curl -s https://raw.githubusercontent.com/mirage/qubes-mirage-firewall/refs/heads/main/qubes-firewall-release.sha256  | cut -d\' \' -f1 \"" }}
      - qvm-run --pass-io {{ DownloadVM }} {{ "\"echo \\\"Checksum of downloaded local file:\\\";sha256sum ~/" ~ Filename ~ " | cut -d\' \' -f1\"" }}
      - qvm-run --pass-io {{ DownloadVM }} {{ "\"diff <(curl -s https://raw.githubusercontent.com/mirage/qubes-mirage-firewall/refs/heads/main/qubes-firewall-release.sha256  | cut -d\' \' -f1 ) <(sha256sum ~/" ~ Filename ~ " | cut -d\' \' -f1) && echo \\\"Checksums DO match.\\\" || (echo \\\"Checksums do NOT match.\\\";exit 101)\"" }} #~/mirage-firewall/modules.img
    - require: 
      - download-and-unpack-in-DownloadVM4mirage

copy-mirage-kernel-to-dom0:
  cmd.run: 
    - name: mkdir -p {{ MirageInstallDir }}; qvm-run --pass-io --no-gui {{ DownloadVM }} " {{ "cat ~/" ~ Filename }} " > {{ MirageInstallDir ~ "/vmlinuz" }}
    - require: 
      - download-and-unpack-in-DownloadVM4mirage
      - check-checksum-in-DownloadVM

create-initramfs:
  cmd.run: 
    - names: 
      - gzip -n9 < /dev/null > {{ MirageInstallDir ~ "/initramfs" }}
      - echo {{ Release }} > {{ MirageInstallDir ~ "/version.txt" }}
    - require: 
      - copy-mirage-kernel-to-dom0

create-sys-mirage-fw:
  qvm.vm:
    - name: {{ MirageFW }}
    - present:
      - class: StandaloneVM
      - label: black
    - prefs:
      - kernel: mirage-firewall
      - kernelopts:
      - include-in-backups: False
      - memory: 32
      - maxmem: 32
      - netvm: sys-net
      - provides-network: True
      - vcpus: 1
      - virt-mode: pvh
    - features:
      - enable:
        - qubes-firewall
        - no-default-kernelopts
    - require: 
      - copy-mirage-kernel-to-dom0


cleanup-in-DownloadVM:
  cmd.run:
   - names:
      - qvm-run -a --pass-io --no-gui {{ DownloadVM }} "{{ "rm " ~ Filename ~ "; rm -R ~/mirage-firewall" }}"
   - require: 
     - create-initramfs

remove-DownloadVM4mirage:
  qvm.absent:
    - name: {{ DownloadVM }}
    - require: 
      - cleanup-in-DownloadVM

{% endif %}
https://privsec.dev/posts/qubes/firewalling-with-mirageos-on-qubes-os/

Installing the unikernel

To deploy MirageOS, you need to copy the vmlinuz and initramfs files from their releases page to /var/lib/qubes/vm-kernels/mirage-firewall in dom0.

TemplateVM

Create a TemplateVM:

qvm-create \
  --property kernel=mirage-firewall \
  --property kernelopts='' \
  --property memory=64 \
  --property maxmem=64 \
  --property vcpus=1 \
  --property virt_mode=pvh \
  --label=black \
  --class TemplateVM \
  your_template_name

Don’t worry if the TemplateVM doesn’t launch — we don’t need it to.

Disposable Template

Next, create a disposable template based on the TemplateVM you have just created.

qvm-create \
  --property template=your_template_name \
  --property provides_network=True \
  --property template_for_dispvms=True \
  --label=orange \
  --class AppVM \
  your_disposable_template_name

qvm-features your_disposable_template_name qubes-firewall 1
qvm-features your_disposable_template_name no-default-kernelopts 1

Your disposable templates should now launch and shut down properly.

Disposable FirewallVMs

You can now create disposable FirewallVMs based on your disposable template. I recommend replacing sys-firewall with a disposable Mirage firewall. If you use ProxyVMs like sys-whonix, I recommend that you add a disposable Mirage Firewall after the ProxyVM as well, and use it as the net qube for your AppVMs.

qvm-create \
  --property template=your_disposable_template_name \
  --property provides_network=True \
  --property netvm=your_net_qube_name \
  --label=orange \
  --class DispVM \
  your_firwall_name

Or what other instructions did you use?

I use and promote use of Mirage across the board. It’s fine for
everyday use.
I package mirage for a simple install -
https://qubes.3isec.org/tasks.html

I never presume to speak for the Qubes team.
When I comment in the Forum I speak for myself.

1 Like

I tested it recently and it broke the internet for the non-VPN disposable VM. So I reverted back to normal firewall.

@alannis What are non-VPN disposable VMs?

Casually injecting marketing for GitHub - kuhbs/qubes-snitch: qubes-snitch is a firewall that runs in a Qubes OS NetVM, and is designed similar to Little Snitch/OpenSnitch. It uses nftables to force VM traffic through userspace prompting, with separate handling for DNS queries and connection decisions, and saves allow/reject rules per source and destination. · GitHub :wink:

While I see the advantages of mirage, you have to know all the firewall rules in advance, which I think is unrealistic for desktop-app firewalling. The only approach that makes sense for a firewall for desktop-apps is confirm/reject while connections appear.

Right now, the only reason Mirage Firewall interests me is because it uses less RAM.

Mirage processes the standard Qubes firewall rules, and is a drop in
replacement for sys-firewall, so there’s nothing particular here about
mirage.
I’ve tried using snitch in Qubes before, and frankly found it unusable.
Ordinary users with a few standard qubes are fine, (if they understand the
prompts), but mix in multiple qubes, disposables, etc, and prompt
overload hits fairly soon, and at that stage it’s worse than nothing.

I never presume to speak for the Qubes team.
When I comment in the Forum I speak for myself.

1 Like

@unman Qubes-Snitch is something I wrote recently, its explicitly for Qubes.

mix in multiple qubes, disposables, etc

Qubes-Snitch can manage that. I use it with “kuhbs”, the Qubes config management system for appusers I’m working on rn (think appstore), so you can setup firewall rules for something like Signal-Desktop (AppVM) or “browser” (unnamed disposable) and alike.

Qubes-Snitch isn’t ready for production yet, but certainly worth a look.

Less RAM

That is a solid point, yes.

Mirage processes the standard Qubes firewall rules

Ah true, I forgot about that.

But still, I find that to be utterly unusable. If you have something like Signal-Desktop for example, that wants to talk to a new IP every now and then because CDNs and alike.. I find the classic qvm-firewall managed model to be not flexible enough.

Approving / denying traffic as it comes gives for much more flexibility, which imho is kind of required for desktop applications.

Static firewalls are more of a server thing, imho.

1 Like

I’ll be interested to see how it manages this.

I never presume to speak for the Qubes team.
When I comment in the Forum I speak for myself.

  1. connection or DNS request arrives
  2. you say accept or reject

Rules are stored in yml files, from which nftables rules are generated. DNS is processed in dnspython (yes yes I know, but I think its ok). So you can reject DNS as well, but has to be over udp/53 and has to be half way sane DNS (I don’t parse all of it, but most of whats half way sane).

Not to much more to it. It has a DNS cache in memory, so you can accept a whole block of IPs in an A record (saves time like nuts).

It really is very simple to use. For DispVMs you can either create rules that are deleted after the VM disappears, or you can use rule-templates based on the AppVM.

It wants a bit of info via qrexec so it understands which IP belongs to which VM name, so it can store the rules you create before or on-demand.

There is a thread to it too: Please let your fancy AIs scan my Qubes-Snitch code to find bugs

Right now I’m just using it myself for a while to see if it fucks up at some point, after this I’ll make a thread for it to advertise for it.

1 Like

It works perfectly fine. The only part that doesn’t work perfectly is switching mirage firewall’s netvm - that often requires a reboot of the VM.

3 Likes

If you mean usability, I highly disagree. In order to even know what you put into the allow-list you need to tcpdump/wireshark applications. Thats very user-unfriendly.

It does work, yes, but its expert level only.

All my AppVMs run behind an VPN-VM. When I replaced sys-firewall with mirage-firewall, AppVMs behind a VPN worked. But the disposable VMs with direct internet access no longer had internet access. I don’t know why and can’t figure out the problem myself. I reverted back to sys-firewall.

1 Like

I use a bunch of mirage firewalls and I think it’s a great service. A tenth the memory footprint of a minimized sys-firewall, instant boot and shutdown. There are a couple gotchas (throughput, and need to reboot sometimes) but otherwise it’s a free, significant resource win.

3 Likes

You do the sniffing on sys-net or sys-vpn, after the Mirage or plain sys-firewall. Then adjust the firewall settings and check that the undesired traffic is really not getting through anymore.

It seems like you have found an old gist for qubes 4.2, why don’t just use the state and documentation from mirage firewall repository?

2 Likes

You do the sniffing on sys-net or sys-vpn, after the Mirage or plain sys-firewall. Then adjust the firewall settings and check that the undesired traffic is really not getting through anymore.

Correct. I find that utterly user-unfriendly. I know how this works, and I have the tech-skills to do so, but pretty much no regular Linux (end) user has, and newbies to Qubes can simply not make use of the firewall at all.

You can not expect people to mess with tcpdump/wireshark to setup a firewall. Thats a high-skill level thing.

And IMHO that is so severe a security “flaw” that I would almost call it a bug. Hence I wrote Qubes-Snitch.

Mirage is MUCH cooler than Qubes-Snitch because its so tiny (ressources), but not usable for (almost) everybody except tech savy people (same as the regular Qubes OS firewall).

You can give Qubes-Snitch to an enduser, explain for a few minutes how “traffic” and “DNS” works in an abstracted way, and they are ready to use it.

Give mirage to an enduser and ask him to configure it :stuck_out_tongue:

Don’t get me wrong, Mirage firewall is fucking amazing, but I’m a bit on a quest to get regular users onto Qubes. They deserve good security too. And its not just that. So many things - setting up a good firewall is a PRIME example imho, are just to annoyingly complicated in qubes. I don’t want to f-ing wireshark around to setup a firewall. This has to be faster and simpler.

I have the tech skills for this, I’ve been using Qubes since I think Qubes 2 or so, and I LOVE it, but some things are just annoying. Firewall is one of my favorite examples.

1 Like

Reboot of mirage or netvm?

How often does that happen during the week?

Good question! I was just looking at the GitHub Issues. Thanks for pointing that out!

When I change mirage’s netvm it will require such a reboot sometimes. I’m not sure how often exactly, but it does happen (this is not something I do on a consistent basis).

2 Likes

The throughput is definitely a major negative!