mirror of
https://github.com/QubesOS/qubes-doc.git
synced 2025-01-03 03:31:04 -05:00
726 lines
22 KiB
ReStructuredText
726 lines
22 KiB
ReStructuredText
|
========
|
|||
|
Firewall
|
|||
|
========
|
|||
|
|
|||
|
|
|||
|
Introduction
|
|||
|
------------
|
|||
|
|
|||
|
| This page explains use of the firewall in Qubes 4.2, using
|
|||
|
``nftables``.
|
|||
|
| In Qubes 4.1, all firewall components used ``iptables``. For details
|
|||
|
of that usage see `here <../firewall_4.1/>`__
|
|||
|
|
|||
|
|
|||
|
Understanding firewalling in Qubes
|
|||
|
----------------------------------
|
|||
|
|
|||
|
|
|||
|
Every qube in Qubes is connected to the network via a FirewallVM, which
|
|||
|
is used to enforce network-level policies. By default there is one
|
|||
|
default FirewallVM, but the user is free to create more, if needed.
|
|||
|
|
|||
|
For more information, see the following:
|
|||
|
|
|||
|
- https://groups.google.com/group/qubes-devel/browse_thread/thread/9e231b0e14bf9d62
|
|||
|
|
|||
|
- https://blog.invisiblethings.org/2011/09/28/playing-with-qubes-networking-for-fun.html
|
|||
|
|
|||
|
|
|||
|
|
|||
|
How to edit rules
|
|||
|
-----------------
|
|||
|
|
|||
|
|
|||
|
In order to edit rules for a given qube, select it in the Qube Manager
|
|||
|
and press the “firewall” button.
|
|||
|
|
|||
|
.. figure:: /attachment/doc/r4.0-manager-firewall.png
|
|||
|
:alt: r4.0-manager-firewall.png
|
|||
|
|
|||
|
r4.0-manager-firewall.png
|
|||
|
|
|||
|
If the qube is running, you can open Settings from the Qube Popup Menu.
|
|||
|
|
|||
|
ICMP and DNS are not accessible in the GUI, but can be changed via
|
|||
|
``qvm-firewall`` described below. Connections to Updates Proxy are not
|
|||
|
made over a network so can not be allowed or blocked with firewall
|
|||
|
rules, but are controlled using the relevant policy file (see :doc:`R4.x Updates proxy </user/how-to-guides/how-to-install-software>` for more detail).
|
|||
|
|
|||
|
Note that if you specify a rule by DNS name it will be resolved to IP(s)
|
|||
|
*at the moment of applying the rules*, and not on the fly for each new
|
|||
|
connection. This means it will not work for servers using load
|
|||
|
balancing, and traffic to complex web sites which draw from many servers
|
|||
|
will be difficult to control.
|
|||
|
|
|||
|
Instead of using the firewall GUI, you can use the ``qvm-firewall``
|
|||
|
command in Dom0 to edit the firewall rules by hand. This gives you
|
|||
|
greater control than by using the GUI.
|
|||
|
|
|||
|
The firewall rules for each qube are saved in an XML file in that qube’s
|
|||
|
directory in dom0:
|
|||
|
|
|||
|
.. code:: bash
|
|||
|
|
|||
|
/var/lib/qubes/appvms/<vm-name>/firewall.xml
|
|||
|
|
|||
|
|
|||
|
|
|||
|
Rules are implemented on the netvm.
|
|||
|
|
|||
|
You can also manually create rules in the qube itself using standard
|
|||
|
firewalling controls. See `Where to put firewall rules <#where-to-put-firewall-rules>`__. In complex cases, it might be
|
|||
|
appropriate to load a ruleset using ``nft -f /path/to/ruleset`` called
|
|||
|
from ``/rw/config/rc.local``, the ruleset file can be populated from the
|
|||
|
current ruleset using ``nft list ruleset > /path/to/ruleset``, you
|
|||
|
should add ``flush ruleset`` at the top of the file to remove all
|
|||
|
existing rules before loading them. if you do this, be aware that
|
|||
|
``rc.local`` is called *after* the network is up, so local rules should
|
|||
|
not be relied upon to block leaks.
|
|||
|
|
|||
|
Reconnecting qubes after a NetVM reboot
|
|||
|
---------------------------------------
|
|||
|
|
|||
|
|
|||
|
Normally Qubes doesn’t let the user stop a NetVM if there are other
|
|||
|
qubes running which use it as their own NetVM. But in case the NetVM
|
|||
|
stops for whatever reason (e.g. it crashes, or the user forces its
|
|||
|
shutdown via qvm-kill via terminal in Dom0), Qubes R4.x will often
|
|||
|
automatically repair the connection. If it does not, then there is an
|
|||
|
easy way to restore the connection to the NetVM by issuing in dom0:
|
|||
|
|
|||
|
.. code:: bash
|
|||
|
|
|||
|
qvm-prefs <vm> netvm <netvm>
|
|||
|
|
|||
|
|
|||
|
|
|||
|
Normally qubes do not connect directly to the actual NetVM (sys-net by
|
|||
|
default) which has networking devices, but rather to the default
|
|||
|
sys-firewall first, and in most cases it would be the NetVM that will
|
|||
|
crash, e.g. in response to S3 sleep/restore or other issues with WiFi
|
|||
|
drivers. In that case it is only necessary to issue the above command
|
|||
|
once, for the sys-firewall (this assumes default VM-naming used by the
|
|||
|
default Qubes installation):
|
|||
|
|
|||
|
.. code:: bash
|
|||
|
|
|||
|
qvm-prefs sys-firewall netvm sys-net
|
|||
|
|
|||
|
|
|||
|
|
|||
|
Network service qubes
|
|||
|
---------------------
|
|||
|
|
|||
|
|
|||
|
Qubes does not support running any networking services (e.g. VPN, local
|
|||
|
DNS server, IPS, …) directly in a qube that is used to run the Qubes
|
|||
|
firewall service (usually sys-firewall) for good reasons. In particular,
|
|||
|
if you want to ensure proper functioning of the Qubes firewall, you
|
|||
|
should not tinker with nftables rules in such qubes.
|
|||
|
|
|||
|
Instead, you should deploy a network infrastructure such as
|
|||
|
|
|||
|
.. code:: bash
|
|||
|
|
|||
|
sys-net <--> sys-firewall-1 <--> network service qube <--> sys-firewall-2 <--> [client qubes]
|
|||
|
|
|||
|
|
|||
|
|
|||
|
Thereby sys-firewall-1 is only needed if you have other client qubes
|
|||
|
connected there, or you want to manage the traffic of the local network
|
|||
|
service qube. The sys-firewall-2 proxy ensures that:
|
|||
|
|
|||
|
1. Firewall changes done in the network service qube cannot render the
|
|||
|
Qubes firewall ineffective.
|
|||
|
|
|||
|
2. Changes to the Qubes firewall by the Qubes maintainers cannot lead to
|
|||
|
unwanted information leakage in combination with user rules deployed
|
|||
|
in the network service qube.
|
|||
|
|
|||
|
3. A compromise of the network service qube does not compromise the
|
|||
|
Qubes firewall.
|
|||
|
|
|||
|
|
|||
|
|
|||
|
If you adopt this model, you should be aware that all traffic will
|
|||
|
arrive at the ``network service qube`` appearing to originate from the
|
|||
|
IP address of ``sys-firewall-2``.
|
|||
|
|
|||
|
For the VPN service please also look at the `VPN documentation <https://forum.qubes-os.org/t/19061>`__.
|
|||
|
|
|||
|
Enabling networking between two qubes
|
|||
|
-------------------------------------
|
|||
|
|
|||
|
|
|||
|
Normally any networking traffic between qubes is prohibited for security
|
|||
|
reasons. However, in special situations, you might want to selectively
|
|||
|
allow specific qubes to establish networking connectivity between each
|
|||
|
other. For example, this might be useful in some development work, when
|
|||
|
you want to test networking code, or to allow file exchange between HVM
|
|||
|
domains (which do not have Qubes tools installed) via SMB/SSH/NFS
|
|||
|
protocols.
|
|||
|
|
|||
|
In order to allow networking from qube A (client) to qube B (server)
|
|||
|
follow these steps:
|
|||
|
|
|||
|
- Make sure both A and B are connected to the same firewall vm (by
|
|||
|
default all VMs use the same firewall VM).
|
|||
|
|
|||
|
- Note the Qubes IP addresses assigned to both qubes. This can be done
|
|||
|
using the ``qvm-ls -n`` command, or via the Qubes Manager using the
|
|||
|
IP column.
|
|||
|
|
|||
|
- Start both qubes, and also open a terminal in the firewall VM
|
|||
|
|
|||
|
- In the firewall VM’s terminal enter the following nftables rule:
|
|||
|
|
|||
|
|
|||
|
|
|||
|
.. code:: bash
|
|||
|
|
|||
|
sudo nft add rule ip qubes custom-forward ip saddr <IP address of A> ip daddr <IP address of B> ct state new,established,related counter accept
|
|||
|
|
|||
|
|
|||
|
|
|||
|
- In qube B’s terminal enter the following nftables rule:
|
|||
|
|
|||
|
|
|||
|
|
|||
|
.. code:: bash
|
|||
|
|
|||
|
sudo nft add rule qubes custom-input ip saddr <IP address of A> ct state new,established,related counter accept
|
|||
|
|
|||
|
|
|||
|
|
|||
|
- Now you should be able to reach B from A – test it using e.g. ping
|
|||
|
issued from A. Note however, that this doesn’t allow you to reach A
|
|||
|
from B – for this you would need two more rules, with A and B
|
|||
|
swapped.
|
|||
|
|
|||
|
- If everything works as expected, then you should write the above
|
|||
|
nftables rules into firewallVM’s ``qubes-firewall-user-script``
|
|||
|
script. This script is run when the netvm starts up. You should also
|
|||
|
write relevant rules in A and B’s ``rc.local`` script which is run
|
|||
|
when the qube is launched. Here’s an example how to update the
|
|||
|
script:
|
|||
|
|
|||
|
|
|||
|
|
|||
|
.. code:: bash
|
|||
|
|
|||
|
[user@sys-firewall ~]$ sudo -i
|
|||
|
[root@sys-firewall user]# echo "nft add rule ip qubes custom-forward ip saddr 10.137.2.25 ip daddr 10.137.2.6 ct state new,established,related counter accept" >> /rw/config/qubes-firewall-user-script
|
|||
|
|
|||
|
|
|||
|
|
|||
|
- Here is an example how to update ``rc.local``:
|
|||
|
|
|||
|
|
|||
|
|
|||
|
.. code:: bash
|
|||
|
|
|||
|
[user@B ~]$ sudo -i
|
|||
|
[root@B user]# echo "nft add rule qubes custom-input ip saddr 10.137.2.25 accept" >> /rw/config/rc.local
|
|||
|
|
|||
|
|
|||
|
|
|||
|
Opening a single TCP port to other network-isolated qube
|
|||
|
--------------------------------------------------------
|
|||
|
|
|||
|
|
|||
|
In the case where a specific TCP port needs to be exposed from a qubes
|
|||
|
to another one, you do not need to enable networking between them but
|
|||
|
you can use the qubes RPC service ``qubes.ConnectTCP``.
|
|||
|
|
|||
|
**1. Simple port binding**
|
|||
|
|
|||
|
Consider the following example. ``mytcp-service`` qube has a TCP service
|
|||
|
running on port ``444`` and ``untrusted`` qube needs to access this
|
|||
|
service.
|
|||
|
|
|||
|
- In dom0, add the following to
|
|||
|
``/etc/qubes/policy.d/30-user-networking.policy``: (it could be
|
|||
|
``another-other-name.policy`` – just remember to keep it consistent)
|
|||
|
|
|||
|
.. code:: bash
|
|||
|
|
|||
|
qubes.ConnectTCP * untrusted @default allow target=mytcp-service
|
|||
|
|
|||
|
|
|||
|
|
|||
|
- In untrusted, use the Qubes tool ``qvm-connect-tcp``:
|
|||
|
|
|||
|
.. code:: bash
|
|||
|
|
|||
|
[user@untrusted #]$ qvm-connect-tcp 444:@default:444
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
Note: The syntax is the same as SSH tunnel handler. The first ``444``
|
|||
|
correspond to the localport destination of ``untrusted``,
|
|||
|
``@default`` the remote machine and the second ``444`` to the remote
|
|||
|
machine port.
|
|||
|
|
|||
|
The service of ``mytcp-service`` running on port ``444`` is now
|
|||
|
accessible in ``untrusted`` as ``localhost:444``.
|
|||
|
|
|||
|
Here ``@default`` is used to hide the destination qube which is
|
|||
|
specified in the Qubes RPC policy by ``target=mytcp-service``.
|
|||
|
Equivalent call is to use the tool as follow:
|
|||
|
|
|||
|
.. code:: bash
|
|||
|
|
|||
|
[user@untrusted #]$ qvm-connect-tcp ::444
|
|||
|
|
|||
|
|
|||
|
|
|||
|
which means to use default local port of ``unstrusted`` as the same of
|
|||
|
the remote port and unspecified destination qube is ``@default`` by
|
|||
|
default in ``qrexec`` call.
|
|||
|
|
|||
|
**2. Binding remote port on another local port**
|
|||
|
|
|||
|
Consider now the case where someone prefers to specify the destination
|
|||
|
qube and use another port in untrusted, for example ``10044``. Instead
|
|||
|
of previous case, add
|
|||
|
|
|||
|
.. code:: bash
|
|||
|
|
|||
|
qubes.ConnectTCP * untrusted mytcp-service allow
|
|||
|
|
|||
|
|
|||
|
|
|||
|
in ``/etc/qubes/policy.d/30-user-networking.policy`` and in untrusted,
|
|||
|
use the tool as follow:
|
|||
|
|
|||
|
.. code:: bash
|
|||
|
|
|||
|
[user@untrusted #]$ qvm-connect-tcp 10444:mytcp-service:444
|
|||
|
|
|||
|
|
|||
|
|
|||
|
The service of ``mytcp-service`` running on port ``444`` is now
|
|||
|
accessible in ``untrusted`` as ``localhost:10444``.
|
|||
|
|
|||
|
**3. Binding to different qubes using RPC policies**
|
|||
|
|
|||
|
One can go further than the previous examples by redirecting different
|
|||
|
ports to different qubes. For example, let assume that another qube
|
|||
|
``mytcp-service-bis`` with a TCP service is running on port ``445``. If
|
|||
|
someone wants ``untrusted`` to be able to reach this service but port
|
|||
|
``445`` is reserved to ``mytcp-service-bis`` then, in dom0, add the
|
|||
|
following to ``/etc/qubes/policy.d/30-user-networking.policy``:
|
|||
|
|
|||
|
.. code:: bash
|
|||
|
|
|||
|
qubes.ConnectTCP +445 untrusted @default allow target=mytcp-service-bis
|
|||
|
|
|||
|
|
|||
|
|
|||
|
In that case, calling ``qvm-connect-tcp`` like previous examples, will
|
|||
|
still bind TCP port ``444`` of ``mytcp-service`` to ``untrusted`` but
|
|||
|
now, calling it with port ``445``
|
|||
|
|
|||
|
.. code:: bash
|
|||
|
|
|||
|
[user@untrusted #]$ qvm-connect-tcp ::445
|
|||
|
|
|||
|
|
|||
|
|
|||
|
will restrict the binding to only the corresponding TCP port of
|
|||
|
``mytcp-service-bis``.
|
|||
|
|
|||
|
**4. Permanent port binding**
|
|||
|
|
|||
|
For creating a permanent port bind between two qubes, ``systemd`` can be
|
|||
|
used. We use the case of the first example. In ``/rw/config`` (or any
|
|||
|
place you find suitable) of qube ``untrusted``, create
|
|||
|
``my-tcp-service.socket`` with content:
|
|||
|
|
|||
|
.. code:: bash
|
|||
|
|
|||
|
[Unit]
|
|||
|
Description=my-tcp-service
|
|||
|
|
|||
|
[Socket]
|
|||
|
ListenStream=127.0.0.1:444
|
|||
|
Accept=true
|
|||
|
|
|||
|
[Install]
|
|||
|
WantedBy=sockets.target
|
|||
|
|
|||
|
|
|||
|
|
|||
|
and ``my-tcp-service@.service`` with content:
|
|||
|
|
|||
|
.. code:: bash
|
|||
|
|
|||
|
[Unit]
|
|||
|
Description=my-tcp-service
|
|||
|
|
|||
|
[Service]
|
|||
|
ExecStart=qrexec-client-vm '' qubes.ConnectTCP+444
|
|||
|
StandardInput=socket
|
|||
|
StandardOutput=inherit
|
|||
|
|
|||
|
|
|||
|
|
|||
|
In ``/rw/config/rc.local``, append the lines:
|
|||
|
|
|||
|
.. code:: bash
|
|||
|
|
|||
|
cp -r /rw/config/my-tcp-service.socket /rw/config/my-tcp-service@.service /lib/systemd/system/
|
|||
|
systemctl daemon-reload
|
|||
|
systemctl start my-tcp-service.socket
|
|||
|
|
|||
|
|
|||
|
|
|||
|
When the qube ``unstrusted`` has started (after a first reboot), you can
|
|||
|
directly access the service of ``mytcp-service`` running on port ``444``
|
|||
|
as ``localhost:444``.
|
|||
|
|
|||
|
Port forwarding to a qube from the outside world
|
|||
|
------------------------------------------------
|
|||
|
|
|||
|
|
|||
|
In order to allow a service present in a qube to be exposed to the
|
|||
|
outside world in the default setup (where the qube has ``sys-firewall``
|
|||
|
as network VM, which in turn has ``sys-net`` as network VM) the
|
|||
|
following needs to be done:
|
|||
|
|
|||
|
- In the sys-net VM:
|
|||
|
|
|||
|
- Route packets from the outside world to the sys-firewall VM
|
|||
|
|
|||
|
- Allow packets through the sys-net VM firewall
|
|||
|
|
|||
|
|
|||
|
|
|||
|
- In the sys-firewall VM:
|
|||
|
|
|||
|
- Route packets from the sys-net VM to the VM
|
|||
|
|
|||
|
- Allow packets through the sys-firewall VM firewall
|
|||
|
|
|||
|
|
|||
|
|
|||
|
- In the qube QubeDest:
|
|||
|
|
|||
|
- Allow packets through the qube firewall to reach the service
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
As an example we can take the use case of qube QubeDest running a web
|
|||
|
server listening on port 443 that we want to expose on our physical
|
|||
|
interface ens6, but only to our local network 192.168.x.y/24.
|
|||
|
|
|||
|
Note: To have all interfaces available and configured, make sure the
|
|||
|
3 qubes are up and running
|
|||
|
|
|||
|
Note: `Issue #4028 <https://github.com/QubesOS/qubes-issues/issues/4028>`__
|
|||
|
discusses adding a command to automate exposing the port.
|
|||
|
|
|||
|
**1. Identify the IP addresses you will need to use for sys-net, sys-firewall and the destination qube.**
|
|||
|
|
|||
|
You can get this information using various methods, but only the first
|
|||
|
one can be used for ``sys-net`` outside world IP:
|
|||
|
|
|||
|
- by running this command in each qube: ``ip -4 -br a | grep UP``
|
|||
|
|
|||
|
- using ``qvm-ls -n``
|
|||
|
|
|||
|
- in the Qubes Manager window using the column IP
|
|||
|
|
|||
|
- from the Settings Window for the qube
|
|||
|
|
|||
|
|
|||
|
|
|||
|
Note the IP addresses you will need, they will be required in the next
|
|||
|
steps.
|
|||
|
|
|||
|
Note: The vifx.0 interface is the one used by qubes connected to this
|
|||
|
netvm so it is *not* an outside world interface.
|
|||
|
|
|||
|
**2. Route packets from the outside world to the FirewallVM**
|
|||
|
|
|||
|
For the following example, we assume that the physical interface ens6 in
|
|||
|
sys-net is on the local network 192.168.x.y with the IP 192.168.x.n, and
|
|||
|
that the IP address of sys-firewall is 10.137.1.z.
|
|||
|
|
|||
|
In the sys-net VM’s Terminal, the first step is to define an ntables
|
|||
|
chain that will receive DNAT rules to relay the network traffic on a
|
|||
|
given port to the qube NetVM, we recommend to define a new chain for
|
|||
|
each destination qube to ease rules management:
|
|||
|
|
|||
|
.. code:: bash
|
|||
|
|
|||
|
nft add chain qubes custom-dnat-qubeDEST '{ type nat hook prerouting priority filter +1 ; policy accept; }'
|
|||
|
|
|||
|
|
|||
|
|
|||
|
Note: the name ``custom-dnat-qubeDST`` is arbitrary
|
|||
|
|
|||
|
Note: while we use a DNAT chain for a single qube, it’s totally
|
|||
|
possible to have a single DNAT chain for multiple qubes
|
|||
|
|
|||
|
Second step, code a natting firewall rule to route traffic on the
|
|||
|
outside interface for the service to the sys-firewall VM
|
|||
|
|
|||
|
.. code:: bash
|
|||
|
|
|||
|
nft add rule qubes custom-dnat-qubeDEST iif == "ens6" ip saddr 192.168.x.y/24 tcp dport 443 ct state new,established,related counter dnat 10.137.1.z
|
|||
|
|
|||
|
|
|||
|
|
|||
|
Third step, code the appropriate new filtering firewall rule to allow
|
|||
|
new connections for the service
|
|||
|
|
|||
|
.. code:: bash
|
|||
|
|
|||
|
nft add rule qubes custom-forward iif == "ens6" ip saddr 192.168.x.y/24 ip daddr 10.137.1.z tcp dport 443 ct state new,established,related counter accept
|
|||
|
|
|||
|
|
|||
|
|
|||
|
Note: If you do not wish to limit the IP addresses connecting to the
|
|||
|
service, remove ``ip saddr 192.168.x.y/24`` from the rules
|
|||
|
|
|||
|
If you want to expose the service on multiple interfaces, repeat the
|
|||
|
steps 2 and 3 described above, for each interface. Alternatively, you
|
|||
|
can leave out the interface completely.
|
|||
|
|
|||
|
Verify the rules on sys-net firewall correctly match the packets you
|
|||
|
want by looking at its counters, check for the counter lines in the
|
|||
|
chains ``custom-forward`` and ``custom-dnat-qubeDEST``:
|
|||
|
|
|||
|
.. code:: bash
|
|||
|
|
|||
|
nft list table ip qubes
|
|||
|
|
|||
|
|
|||
|
|
|||
|
In this example, we can see 7 packets in the forward rule, and 3 packets
|
|||
|
in the dnat rule:
|
|||
|
|
|||
|
.. code:: bash
|
|||
|
|
|||
|
chain custom-forward {
|
|||
|
iif "ens6" ip saddr 192.168.x.y/24 ip daddr 10.137.1.z tcp dport 443 ct state new,established,related counter packets 7 bytes 448 accept
|
|||
|
}
|
|||
|
|
|||
|
chain custom-dnat-qubeDEST {
|
|||
|
type nat hook prerouting priority filter + 1; policy accept;
|
|||
|
iif "ens6" ip saddr 192.168.x.y/24 tcp dport 443 ct state new,established,related counter packets 3 bytes 192 dnat to 10.138.33.59
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
|
|||
|
(Optional) You can send a test packet by trying to connect to the
|
|||
|
service from an external device using the following command:
|
|||
|
|
|||
|
.. code:: bash
|
|||
|
|
|||
|
telnet 192.168.x.n 443
|
|||
|
|
|||
|
|
|||
|
|
|||
|
Once you have confirmed that the counters increase, store the commands
|
|||
|
used in the previous steps in ``/rw/config/qubes-firewall-user-script``
|
|||
|
so they get set on sys-net start-up:
|
|||
|
|
|||
|
.. code:: bash
|
|||
|
|
|||
|
[user@sys-net user]$ sudo -i
|
|||
|
[root@sys-net user]# nano /rw/config/qubes-firewall-user-script
|
|||
|
|
|||
|
|
|||
|
|
|||
|
Content of ``/rw/config/qubes-firewall-user-script`` in ``sys-net``:
|
|||
|
|
|||
|
.. code:: bash
|
|||
|
|
|||
|
#!/bin/sh
|
|||
|
|
|||
|
# create the dnat chain for qubeDEST if it doesn't already exist
|
|||
|
if nft add chain qubes custom-dnat-qubeDEST '{ type nat hook prerouting priority filter +1 ; policy accept; }'
|
|||
|
then
|
|||
|
# create the dnat rule
|
|||
|
nft add rule qubes custom-dnat-qubeDEST iif == "ens6" saddr 192.168.x.y/24 tcp dport 443 ct state new,established,related counter dnat 10.137.1.z
|
|||
|
|
|||
|
# allow forwarded traffic
|
|||
|
nft add rule qubes custom-forward iif == "ens6" ip saddr 192.168.x.y/24 ip daddr 10.137.1.z tcp dport 443 ct state new,established,related counter accept
|
|||
|
fi
|
|||
|
|
|||
|
|
|||
|
|
|||
|
**3. Route packets from the FirewallVM to the VM**
|
|||
|
|
|||
|
For the following example, we use the fact that the physical interface
|
|||
|
of sys-firewall, facing sys-net, is eth0. Furthermore, we assume that
|
|||
|
the target VM running the web server has the IP address 10.137.0.xx and
|
|||
|
that the IP address of sys-firewall is 10.137.1.z.
|
|||
|
|
|||
|
In the sys-firewall VM’s Terminal, add a DNAT chain that will contain
|
|||
|
routing rules:
|
|||
|
|
|||
|
.. code:: bash
|
|||
|
|
|||
|
nft add chain qubes custom-dnat-qubeDEST '{ type nat hook prerouting priority filter +1 ; policy accept; }'
|
|||
|
|
|||
|
|
|||
|
|
|||
|
Second step, code a natting firewall rule to route traffic on the
|
|||
|
outside interface for the service to the destination qube
|
|||
|
|
|||
|
.. code:: bash
|
|||
|
|
|||
|
nft add rule qubes custom-dnat-qubeDEST iif == "eth0" ip saddr 192.168.x.y/24 tcp dport 443 ct state new,established,related counter dnat 10.137.0.xx
|
|||
|
|
|||
|
|
|||
|
|
|||
|
Third step, code the appropriate new filtering firewall rule to allow
|
|||
|
new connections for the service
|
|||
|
|
|||
|
.. code:: bash
|
|||
|
|
|||
|
nft add rule qubes custom-forward iif == "eth0" ip saddr 192.168.x.y/24 ip daddr 10.137.0.xx tcp dport 443 ct state new,established,related counter accept
|
|||
|
|
|||
|
|
|||
|
|
|||
|
Note: If you do not wish to limit the IP addresses connecting to the
|
|||
|
service, remove ``ip saddr 192.168.x.y/24`` from the rules
|
|||
|
|
|||
|
Once you have confirmed that the counters increase, store these commands
|
|||
|
in the script ``/rw/config/qubes-firewall-user-script``
|
|||
|
|
|||
|
.. code:: bash
|
|||
|
|
|||
|
[user@sys-net user]$ sudo -i
|
|||
|
[root@sys-net user]# nano /rw/config/qubes-firewall-user-script
|
|||
|
|
|||
|
|
|||
|
|
|||
|
Content of ``/rw/config/qubes-firewall-user-script`` in
|
|||
|
``sys-firewall``:
|
|||
|
|
|||
|
.. code:: bash
|
|||
|
|
|||
|
#!/bin/sh
|
|||
|
|
|||
|
# create the dnat chain for qubeDEST if it doesn't already exist
|
|||
|
if nft add chain qubes custom-dnat-qubeDEST '{ type nat hook prerouting priority filter +1 ; policy accept; }'
|
|||
|
then
|
|||
|
# create the dnat rule
|
|||
|
nft add rule qubes custom-dnat-qubeDEST iif == "eth0" tcp dport 443 ct state new,established,related counter dnat 10.137.0.xx
|
|||
|
|
|||
|
# allow forwarded traffic
|
|||
|
nft add rule qubes custom-forward iif == "eth0" ip saddr 192.168.x.y/24 ip daddr 10.137.0.xx tcp dport 443 ct state new,established,related counter accept
|
|||
|
fi
|
|||
|
|
|||
|
|
|||
|
|
|||
|
If the service should be available to other VMs on the same system, do
|
|||
|
not forget to specify the additional rules described earlier in this
|
|||
|
guide.
|
|||
|
|
|||
|
**4. Allow packets into the qube to reach the service**
|
|||
|
|
|||
|
No routing is required in the destination qube, only filtering.
|
|||
|
|
|||
|
For the following example, we assume that the target VM running the web
|
|||
|
server has the IP address 10.137.0.xx
|
|||
|
|
|||
|
The according rule to allow the traffic is:
|
|||
|
|
|||
|
.. code:: bash
|
|||
|
|
|||
|
nft add rule qubes custom-input tcp dport 443 ip daddr 10.137.0.xx ct state new,established,related counter accept
|
|||
|
|
|||
|
|
|||
|
|
|||
|
To make it persistent, you need to add this command in the script
|
|||
|
``/rw/config/rc.local``:
|
|||
|
|
|||
|
.. code:: bash
|
|||
|
|
|||
|
[user@qubeDEST user]$ sudo -i
|
|||
|
[root@qubeDEST user]# echo 'nft add rule qubes custom-input tcp dport 443 ip daddr 10.137.0.xx ct state new,established,related counter accept' >> /rw/config/rc.local
|
|||
|
|
|||
|
|
|||
|
|
|||
|
This time testing should allow connectivity to the service as long
|
|||
|
qubeDEST is running and the service is up :-)
|
|||
|
|
|||
|
Where to put firewall rules
|
|||
|
---------------------------
|
|||
|
|
|||
|
|
|||
|
Implicit in the above example :doc:`scripts </user/advanced-topics/config-files>`, but
|
|||
|
worth calling attention to: for all qubes *except* those supplying
|
|||
|
networking, nftables commands should be added to the
|
|||
|
``/rw/config/rc.local`` script. For service qubes supplying networking
|
|||
|
(``sys-firewall`` and ``sys-net`` inclusive), nftables commands should
|
|||
|
be added to ``/rw/config/qubes-firewall-user-script``.
|
|||
|
|
|||
|
Firewall troubleshooting
|
|||
|
------------------------
|
|||
|
|
|||
|
|
|||
|
Firewall logs are stored in the systemd journal of the qube the firewall
|
|||
|
is running in (probably ``sys-firewall``). You can view them by running
|
|||
|
``sudo journalctl -u qubes-firewall.service`` in the relevant qube.
|
|||
|
Sometimes these logs can contain useful information about errors that
|
|||
|
are preventing the firewall from behaving as you would expect.
|
|||
|
|
|||
|
An effective console utility to troubleshoot network is
|
|||
|
`tcpdump <https://www.tcpdump.org/>`__, it can be used to display
|
|||
|
network packets entering or leaving network interfaces.
|
|||
|
|
|||
|
For instance, if you want to check if your network interface ``eth0`` is
|
|||
|
receiving packets on port TCP 443 from the network 192.168.x.y, you can
|
|||
|
run this command:
|
|||
|
|
|||
|
.. code:: bash
|
|||
|
|
|||
|
tcpdump -i eth0 -nn dst port 443 and src net 192.168.x.y/24
|
|||
|
|
|||
|
|
|||
|
|
|||
|
This can be used effectively in a destination qube and its Network VM to
|
|||
|
see if forwarding / NAT rules are working.
|
|||
|
|
|||
|
Nftables tips
|
|||
|
-------------
|
|||
|
|
|||
|
|
|||
|
A simple way to experiment changes with your ruleset can be achieved by
|
|||
|
saving the current working ruleset in two files, one for backup and the
|
|||
|
other for making changes.
|
|||
|
|
|||
|
By adding ``flush ruleset`` at the top of the file, you can achieve
|
|||
|
atomic update, which mean the new ruleset would replace the current one
|
|||
|
only if it fully succeed to load.
|
|||
|
|
|||
|
You can dump the ruleset in two files using the following command:
|
|||
|
|
|||
|
.. code:: bash
|
|||
|
|
|||
|
nft list ruleset | tee nft_backup | tee nft_new_ruleset
|
|||
|
|
|||
|
|
|||
|
|
|||
|
Then, edit ``nft_new_ruleset``, add ``flush ruleset`` on top and make
|
|||
|
changes, load it with ``nft -f nft_new_ruleset``.
|
|||
|
|
|||
|
You can revert to the original ruleset with the following commands:
|
|||
|
|
|||
|
.. code:: bash
|
|||
|
|
|||
|
nft flush ruleset && nft -f nft_backup
|
|||
|
|
|||
|
|