Convert to RST

This is done using tools at
https://github.com/maiska/qubes-translation-utilz, commit
4c8e2a7f559fd37e29b51769ed1ab1c6cf92e00d.
This commit is contained in:
Marek Marczykowski-Górecki 2025-07-04 14:23:09 +02:00
parent e3db139fe3
commit 7e464d0f40
No known key found for this signature in database
GPG key ID: F32894BE9684938A
428 changed files with 32833 additions and 29703 deletions

View file

@ -1,61 +0,0 @@
---
lang: en
layout: doc
permalink: /doc/anti-evil-maid/
redirect_from:
- /en/doc/anti-evil-maid/
- /doc/AntiEvilMaid/
- /wiki/AntiEvilMaid/
ref: 164
title: Anti evil maid (AEM)
---
Background
----------
Please read [this blog article](https://blog.invisiblethings.org/2011/09/07/anti-evil-maid.html).
Requirements
----------
The current package requires a TPM 1.2 interface and a working Intel TXT engine.
If you cleaned your Intel Management Engine with e.g. [me_cleaner](https://github.com/corna/me_cleaner)
while installing [CoreBoot](https://www.coreboot.org/) then you are out of luck.
For now you have to choose between cleaning your BIOS and deploying Anti Evil Maid.
[Discussion](https://groups.google.com/d/msg/qubes-users/sEmZfOZqYXM/j5rHeex1BAAJ)
Installing
----------
In Dom0 install `anti-evil-maid`:
~~~
sudo qubes-dom0-update anti-evil-maid
~~~
For more information, see the [qubes-antievilmaid](https://github.com/QubesOS/qubes-antievilmaid) repository, which includes a `README`.
Security Considerations
-----------------------
[Qubes security guidelines](https://forum.qubes-os.org/t/19075) dictate that USB devices should never be attached directly to dom0, since this can result in the entire system being compromised.
However, in its default configuration, installing and using AEM requires attaching a USB drive (i.e., [mass storage device](https://en.wikipedia.org/wiki/USB_mass_storage_device_class)) directly to dom0.
(The other option is to install AEM to an internal disk.
However, this carries significant security implications, as explained [here](https://blog.invisiblethings.org/2011/09/07/anti-evil-maid.html).) This presents us with a classic security trade-off: each Qubes user must make a choice between protecting dom0 from a potentially malicious USB drive, on the one hand, and protecting the system from Evil Maid attacks, on the other hand.
Given the practical feasibility of attacks like [BadUSB](https://web.archive.org/web/20160304013434/https://srlabs.de/badusb/) and revelations regarding pervasive government hardware backdoors, this is no longer a straightforward decision.
New, factory-sealed USB drives cannot simply be assumed to be "clean" (e.g., to have non-malicious microcontroller firmware).
Therefore, it is up to each individual Qubes user to evaluate the relative risk of each attack vector against his or her security model.
For example, a user who frequently travels with a Qubes laptop holding sensitive data may be at a much higher risk of Evil Maid attacks than a home user with a stationary Qubes desktop.
If the frequent traveler judges her risk of an Evil Maid attack to be higher than the risk of a malicious USB device, she might reasonably opt to install and use AEM.
On the other hand, the home user might deem the probability of an Evil Maid attack occurring in her own home to be so low that there is a higher probability that any USB drive she purchases is already compromised, in which case she might reasonably opt never to attach any USB devices directly to dom0.
(In either case, users can--and should--secure dom0 against further USB-related attacks through the use of a [USB VM](https://forum.qubes-os.org/t/19075#creating-and-using-a-usbvm).)
For more information, please see [this discussion thread](https://groups.google.com/d/msg/qubes-devel/EBc4to5IBdg/n1hfsHSfbqsJ).
Known issues
------------
- USB 3.0 isn't supported yet
- [AEM is not compatible with having an SSD cache](https://groups.google.com/d/msgid/qubes-users/70021590-fb3a-4f95-9ce5-4b340530ddbf%40petaramesh.org)

View file

@ -0,0 +1,52 @@
====================
Anti evil maid (AEM)
====================
Background
----------
Please read `this blog article <https://blog.invisiblethings.org/2011/09/07/anti-evil-maid.html>`__.
Requirements
------------
The current package requires a TPM 1.2 interface and a working Intel TXT engine. If you cleaned your Intel Management Engine with e.g. `me_cleaner <https://github.com/corna/me_cleaner>`__ while installing `CoreBoot <https://www.coreboot.org/>`__ then you are out of luck. For now you have to choose between cleaning your BIOS and deploying Anti Evil Maid.
`Discussion <https://groups.google.com/d/msg/qubes-users/sEmZfOZqYXM/j5rHeex1BAAJ>`__
Installing
----------
In Dom0 install ``anti-evil-maid``:
.. code:: bash
sudo qubes-dom0-update anti-evil-maid
For more information, see the `qubes-antievilmaid <https://github.com/QubesOS/qubes-antievilmaid>`__ repository, which includes a ``README``.
Security Considerations
-----------------------
`Qubes security guidelines <https://forum.qubes-os.org/t/19075>`__ dictate that USB devices should never be attached directly to dom0, since this can result in the entire system being compromised. However, in its default configuration, installing and using AEM requires attaching a USB drive (i.e., `mass storage device <https://en.wikipedia.org/wiki/USB_mass_storage_device_class>`__) directly to dom0. (The other option is to install AEM to an internal disk. However, this carries significant security implications, as explained `here <https://blog.invisiblethings.org/2011/09/07/anti-evil-maid.html>`__.) This presents us with a classic security trade-off: each Qubes user must make a choice between protecting dom0 from a potentially malicious USB drive, on the one hand, and protecting the system from Evil Maid attacks, on the other hand. Given the practical feasibility of attacks like `BadUSB <https://web.archive.org/web/20160304013434/https://srlabs.de/badusb/>`__ and revelations regarding pervasive government hardware backdoors, this is no longer a straightforward decision. New, factory-sealed USB drives cannot simply be assumed to be “clean” (e.g., to have non-malicious microcontroller firmware). Therefore, it is up to each individual Qubes user to evaluate the relative risk of each attack vector against his or her security model.
For example, a user who frequently travels with a Qubes laptop holding sensitive data may be at a much higher risk of Evil Maid attacks than a home user with a stationary Qubes desktop. If the frequent traveler judges her risk of an Evil Maid attack to be higher than the risk of a malicious USB device, she might reasonably opt to install and use AEM. On the other hand, the home user might deem the probability of an Evil Maid attack occurring in her own home to be so low that there is a higher probability that any USB drive she purchases is already compromised, in which case she might reasonably opt never to attach any USB devices directly to dom0. (In either case, users canand shouldsecure dom0 against further USB-related attacks through the use of a `USB VM <https://forum.qubes-os.org/t/19075#creating-and-using-a-usbvm>`__.)
For more information, please see `this discussion thread <https://groups.google.com/d/msg/qubes-devel/EBc4to5IBdg/n1hfsHSfbqsJ>`__.
Known issues
------------
- USB 3.0 isnt supported yet
- `AEM is not compatible with having an SSD cache <https://groups.google.com/d/msgid/qubes-users/70021590-fb3a-4f95-9ce5-4b340530ddbf%40petaramesh.org>`__

View file

@ -1,144 +0,0 @@
---
lang: en
layout: doc
permalink: /doc/ctap-proxy/
redirect_from: /doc/u2f-proxy/
ref: 167
title: CTAP proxy
---
The [Qubes CTAP Proxy](https://github.com/QubesOS/qubes-app-u2f) is a secure proxy intended to make use of CTAP two-factor authentication devices with web browsers without exposing the browser to the full USB stack, not unlike the [USB keyboard and mouse proxies](/doc/usb/) implemented in Qubes.
## What is CTAP, U2F, FIDO2?
CTAP, U2F, and FIDO2 are all related to authentication protocols and standards developed by the FIDO Alliance. CTAP has two versions: CTAP1 and CTAP2:
1. [CTAP1/U2F](https://en.wikipedia.org/wiki/Universal_2nd_Factor) (Universal 2nd Factor): U2F is an earlier protocol developed by the FIDO Alliance as part of the FIDO U2F standard. It provides a strong second-factor authentication method using dedicated hardware security keys. U2F allows users to authenticate to online services by simply plugging in a U2F-compliant security key and pressing a button, providing a higher level of security compared to traditional passwords.
2. [CTAP2](https://en.wikipedia.org/wiki/Client_to_Authenticator_Protocol) (Client to Authenticator Protocol): CTAP2 is a protocol within the FIDO2 framework that enables communication between a client device (e.g., a computer or smartphone) and an authenticator (e.g., a hardware device). CTAP allows for secure and convenient authentication using public key cryptography and strong authentication factors.
3. [FIDO2](https://en.wikipedia.org/wiki/FIDO_Alliance): FIDO2 is a set of standards and protocols developed by the FIDO Alliance for passwordless and strong authentication. It combines two main components: CTAP (Client to Authenticator Protocol) and WebAuthn (Web Authentication API). FIDO2 enables users to authenticate to online services using various authentication methods, such as biometrics, PINs, or hardware tokens, instead of relying on passwords.
The aim of these protocols is to introduce additional control which provides [good protection](https://krebsonsecurity.com/2018/07/google-security-keys-neutralized-employee-phishing/) in cases in which the passphrase is stolen (e.g. by phishing or keylogging).
While passphrase compromise may not be obvious to the user, a physical device that cannot be duplicated must be stolen to be used outside the owner's control.
Nonetheless, it is important to note at the outset that CTAP cannot guarantee security when the host system is compromised (e.g. a malware-infected operating system under an adversary's control).
The CTAP specification defines protocols for multiple layers from USB to the browser API, and the whole stack is intended to be used with web applications (most commonly websites) in browsers.
In most cases, authenticators are USB dongles.
The protocol is very simple, allowing the devices to store very little state inside (so the tokens may be reasonably cheap) while simultaneously authenticating a virtually unlimited number of services (so each person needs only one token, not one token per application).
The user interface is usually limited to a single LED and a button that is pressed to confirm each transaction, so the devices themselves are also easy to use.
Both CTAP1 and CTAP2 share the same underlying transports: USB Human Interface Device (USB HID), Near Field Communication (NFC), and Bluetooth Smart / Bluetooth Low Energy Technology (BLE).
Currently, the most common form of two-step authentication consists of a numeric code that the user manually types into a web application.
These codes are typically generated by an app on the user's smartphone or sent via SMS.
By now, it is well-known that this form of two-step authentication is vulnerable to phishing and man-in-the-middle attacks due to the fact that the application requesting the two-step authentication code is typically not itself authenticated by the user.
(In other words, users can accidentally give their codes to attackers because they do not always know who is really requesting the code.) In the CTAP model, by contrast, the browser ensures that the token receives valid information about the web application requesting authentication, so the token knows which application it is authenticating (for details, see [here](https://fidoalliance.org/specs/fido-u2f-v1.2-ps-20170411/fido-u2f-overview-v1.2-ps-20170411.html#site-specific-public-private-key-pairs)).
Nonetheless, [some attacks are still possible](https://www.wired.com/story/chrome-yubikey-phishing-webusb/) even with CTAP (more on this below).
## The Qubes approach to CTAP
In a conventional setup, web browsers and the USB stack (to which the authenticator is connected) are all running in the same monolithic OS.
Since the CTAP model assumes that the browser is trustworthy, any browser in the OS is able to access any key stored on the authenticator.
The user has no way to know which keys have been accessed by which browsers for which services.
If any of the browsers are compromised, it should be assumed that all the token's keys have been compromised.
(This problem can be mitigated, however, if the CTAP device has a special display to show the user what's being authenticated.) Moreover, since the USB stack is in the same monolithic OS, the system is vulnerable to attacks like [BadUSB](https://www.blackhat.com/us-14/briefings.html#badusb-on-accessories-that-turn-evil).
In Qubes OS, by contrast, it is possible to securely compartmentalise the browser in one qube and the USB stack in another so that they are always kept separate from each other.
The Qubes CTAP Proxy then allows the token connected to the USB stack in one qube to communicate with the browser in a separate qube.
We operate under the assumption that the USB stack is untrusted from the point of view of the browser and also that the browser is not to be trusted blindly by the token.
Therefore, the token is never in the same qube as the browser.
Our proxy forwards only the data necessary to actually perform the authentication, leaving all unnecessary data out, so it won't become a vector of attack.
This is depicted in the diagram below (click for full size).
[![Qubes CTAP Proxy diagram](/attachment/doc/ctap.svg)](/attachment/doc/ctap.svg)
The Qubes CTAP Proxy has two parts: the frontend and the backend.
The frontend runs in the same qube as the browser and presents a fake USB-like HID device using `uhid`.
The backend runs in `sys-usb` and behaves like a browser.
This is done using the `fido2` reference library.
All of our code was written in Python.
The standard [qrexec](/doc/qrexec3/) policy is responsible for directing calls to the appropriate domains.
The `vault` qube with a dashed line in the bottom portion of the diagram depicts future work in which we plan to implement the Qubes CTAP Proxy with a software token in an isolated qube rather than a physical hardware token.
This is similar to the manner in which [Split GPG](/doc/split-gpg/) allows us to emulate the smart card model without physical smart cards.
One very important assumption of protocol is that the browser verifies every request sent to the authenticator --- in particular, that the web application sending an authentication request matches the application that would be authenticated by answering that request (in order to prevent, e.g., a phishing site from sending an authentication request for your bank's site).
With the WebUSB feature in Chrome, however, a malicious website can [bypass](https://www.wired.com/story/chrome-yubikey-phishing-webusb/) this safeguard by connecting directly to the token instead of using the browser's CTAP API.
The Qubes CTAP Proxy also prevents this class of attacks by implementing an additional verification layer.
This verification layer allows you to enforce, for example, that the web browser in your `twitter` qube can only access the CTAP key associated with `https://twitter.com`.
This means that if anything in your `twitter` qube were compromised --- the browser or even the OS itself --- it would still not be able to access the CTAP keys on your token for any other websites or services, like your email and bank accounts.
This is another significant security advantage over monolithic systems.
(For details and instructions, see the [Advanced usage](#advanced-usage-per-qube-key-access) section below.)
For even more protection, you can combine this with the [Qubes firewall](/doc/firewall/) to ensure, for example, that the browser in your `banking` qube accesses only one website (your bank's website).
By configuring the Qubes firewall to prevent your `banking` qube from accessing any other websites, you reduce the risk of another website compromising the browser in an attempt to bypass CTAP authentication.
## Installation
These instructions assume that there is a `sys-usb` qube that holds the USB stack, which is the default configuration in most Qubes OS installations.
In dom0:
```
$ sudo qubes-dom0-update qubes-ctap-dom0
$ qvm-service --enable work qubes-ctap-proxy
```
The above assumes a `work` qube in which you would like to enable ctap. Repeat the `qvm-service` command for all qubes that should have the client proxy enabled. Alternatively, you can add `qubes-ctap-proxy` in VM settings -> Services in the Qube Manager of each qube you would like to enable the service. Attempting to start the `qubes-ctap-proxy` service in the device-hosting qube (`sys-usb`) will fail.
In Fedora templates:
```
$ sudo dnf install qubes-ctap
```
In Debian templates:
```
$ sudo apt install qubes-ctap
```
As usual with software updates, shut down the templates after installation, then restart `sys-usb` and all qubes that use the proxy.
After that, you may use your CTAP authenticator (but see [Browser support](#template-and-browser-support) below).
## Advanced usage: per-qube key access
If you are using Qubes 4.0, you can further compartmentalise your CTAP keys by restricting each qube's access to specific keys.
For example, you could make it so that your `twitter` qube (and, therefore, all web browsers in your `twitter` qube) can access only the key on your CTAP token for `https://twitter.com`, regardless of whether any of the web browsers in your `twitter` qube or the `twitter` qube itself are compromised.
If your `twitter` qube makes an authentication request for your bank website, it will be denied at the Qubes policy level.
To enable this, create a file in dom0 named `/etc/qubes/policy.d/30-user-ctapproxy.policy` with the following content:
```
policy.RegisterArgument +u2f.Authenticate sys-usb @anyvm allow target=dom0
```
Next, empty the contents of `/etc/qubes-rpc/policy/u2f.Authenticate` so that it is a blank file.
Do not delete the file itself.
(If you do, the default file will be recreated the next time you update, so it will no longer be empty.) Finally, follow your web application's instructions to enroll your token and use it as usual.
(This enrollment process depends on the web application and is in no way specific to Qubes CTAP.)
The default model is to allow a qube to access all and only the keys that were enrolled by that qube.
For example, if your `banking` qube enrolls your banking key, and your `twitter` qube enrolls your Twitter key, then your `banking` qube will have access to your banking key but not your Twitter key, and your `twitter` qube will have access to your Twitter key but not your banking key.
## Non-default USB qube name
If your USB qube is named differently than `sys-usb`, then do the following in the appropriate template(s):
```
systemctl enable qubes-ctapproxy@USB_QUBE.service
systemctl disable qubes-ctapproxy@sys-usb.service
```
Replace `USB_QUBE` with the actual USB qube name.
Do not forget to change the sys-usb qube name in the policy `/etc/qubes/policy.d/30-user-ctapproxy.policy`.
## Template and browser support
The large number of possible combinations of template (Fedora 37, 38; Debian 10, 11) and browser (multiple Google Chrome versions, multiple Chromium versions, multiple Firefox versions) made it impractical for us to test every combination that users are likely to attempt with the Qubes CTAP Proxy.
In some cases, you may be the first person to try a particular combination.
Consequently, (and as with any new feature), users will inevitably encounter bugs.
We ask for your patience and understanding in this regard.
As always, please [report any bugs you encounter](/doc/issue-tracking/).

View file

@ -0,0 +1,125 @@
==========
CTAP proxy
==========
The `Qubes CTAP Proxy <https://github.com/QubesOS/qubes-app-u2f>`__ is a secure proxy intended to make use of CTAP two-factor authentication devices with web browsers without exposing the browser to the full USB stack, not unlike the :doc:`USB keyboard and mouse proxies </user/how-to-guides/how-to-use-usb-devices>` implemented in Qubes.
What is CTAP, U2F, FIDO2?
-------------------------
CTAP, U2F, and FIDO2 are all related to authentication protocols and standards developed by the FIDO Alliance. CTAP has two versions: CTAP1 and CTAP2:
1. `CTAP1/U2F <https://en.wikipedia.org/wiki/Universal_2nd_Factor>`__ (Universal 2nd Factor): U2F is an earlier protocol developed by the FIDO Alliance as part of the FIDO U2F standard. It provides a strong second-factor authentication method using dedicated hardware security keys. U2F allows users to authenticate to online services by simply plugging in a U2F-compliant security key and pressing a button, providing a higher level of security compared to traditional passwords.
2. `CTAP2 <https://en.wikipedia.org/wiki/Client_to_Authenticator_Protocol>`__ (Client to Authenticator Protocol): CTAP2 is a protocol within the FIDO2 framework that enables communication between a client device (e.g., a computer or smartphone) and an authenticator (e.g., a hardware device). CTAP allows for secure and convenient authentication using public key cryptography and strong authentication factors.
3. `FIDO2 <https://en.wikipedia.org/wiki/FIDO_Alliance>`__: FIDO2 is a set of standards and protocols developed by the FIDO Alliance for passwordless and strong authentication. It combines two main components: CTAP (Client to Authenticator Protocol) and WebAuthn (Web Authentication API). FIDO2 enables users to authenticate to online services using various authentication methods, such as biometrics, PINs, or hardware tokens, instead of relying on passwords.
The aim of these protocols is to introduce additional control which provides `good protection <https://krebsonsecurity.com/2018/07/google-security-keys-neutralized-employee-phishing/>`__ in cases in which the passphrase is stolen (e.g. by phishing or keylogging). While passphrase compromise may not be obvious to the user, a physical device that cannot be duplicated must be stolen to be used outside the owners control. Nonetheless, it is important to note at the outset that CTAP cannot guarantee security when the host system is compromised (e.g. a malware-infected operating system under an adversarys control).
The CTAP specification defines protocols for multiple layers from USB to the browser API, and the whole stack is intended to be used with web applications (most commonly websites) in browsers. In most cases, authenticators are USB dongles. The protocol is very simple, allowing the devices to store very little state inside (so the tokens may be reasonably cheap) while simultaneously authenticating a virtually unlimited number of services (so each person needs only one token, not one token per application). The user interface is usually limited to a single LED and a button that is pressed to confirm each transaction, so the devices themselves are also easy to use. Both CTAP1 and CTAP2 share the same underlying transports: USB Human Interface Device (USB HID), Near Field Communication (NFC), and Bluetooth Smart / Bluetooth Low Energy Technology (BLE).
Currently, the most common form of two-step authentication consists of a numeric code that the user manually types into a web application. These codes are typically generated by an app on the users smartphone or sent via SMS. By now, it is well-known that this form of two-step authentication is vulnerable to phishing and man-in-the-middle attacks due to the fact that the application requesting the two-step authentication code is typically not itself authenticated by the user. (In other words, users can accidentally give their codes to attackers because they do not always know who is really requesting the code.) In the CTAP model, by contrast, the browser ensures that the token receives valid information about the web application requesting authentication, so the token knows which application it is authenticating (for details, see `here <https://fidoalliance.org/specs/fido-u2f-v1.2-ps-20170411/fido-u2f-overview-v1.2-ps-20170411.html#site-specific-public-private-key-pairs>`__). Nonetheless, `some attacks are still possible <https://www.wired.com/story/chrome-yubikey-phishing-webusb/>`__ even with CTAP (more on this below).
The Qubes approach to CTAP
--------------------------
In a conventional setup, web browsers and the USB stack (to which the authenticator is connected) are all running in the same monolithic OS. Since the CTAP model assumes that the browser is trustworthy, any browser in the OS is able to access any key stored on the authenticator. The user has no way to know which keys have been accessed by which browsers for which services. If any of the browsers are compromised, it should be assumed that all the tokens keys have been compromised. (This problem can be mitigated, however, if the CTAP device has a special display to show the user whats being authenticated.) Moreover, since the USB stack is in the same monolithic OS, the system is vulnerable to attacks like `BadUSB <https://www.blackhat.com/us-14/briefings.html#badusb-on-accessories-that-turn-evil>`__.
In Qubes OS, by contrast, it is possible to securely compartmentalise the browser in one qube and the USB stack in another so that they are always kept separate from each other. The Qubes CTAP Proxy then allows the token connected to the USB stack in one qube to communicate with the browser in a separate qube. We operate under the assumption that the USB stack is untrusted from the point of view of the browser and also that the browser is not to be trusted blindly by the token. Therefore, the token is never in the same qube as the browser. Our proxy forwards only the data necessary to actually perform the authentication, leaving all unnecessary data out, so it wont become a vector of attack. This is depicted in the diagram below (click for full size).
|Qubes CTAP Proxy diagram|
The Qubes CTAP Proxy has two parts: the frontend and the backend. The frontend runs in the same qube as the browser and presents a fake USB-like HID device using ``uhid``. The backend runs in ``sys-usb`` and behaves like a browser. This is done using the ``fido2`` reference library. All of our code was written in Python. The standard :doc:`qrexec </developer/services/qrexec>` policy is responsible for directing calls to the appropriate domains.
The ``vault`` qube with a dashed line in the bottom portion of the diagram depicts future work in which we plan to implement the Qubes CTAP Proxy with a software token in an isolated qube rather than a physical hardware token. This is similar to the manner in which :doc:`Split GPG </user/security-in-qubes/split-gpg>` allows us to emulate the smart card model without physical smart cards.
One very important assumption of protocol is that the browser verifies every request sent to the authenticator — in particular, that the web application sending an authentication request matches the application that would be authenticated by answering that request (in order to prevent, e.g., a phishing site from sending an authentication request for your banks site). With the WebUSB feature in Chrome, however, a malicious website can `bypass <https://www.wired.com/story/chrome-yubikey-phishing-webusb/>`__ this safeguard by connecting directly to the token instead of using the browsers CTAP API.
The Qubes CTAP Proxy also prevents this class of attacks by implementing an additional verification layer. This verification layer allows you to enforce, for example, that the web browser in your ``twitter`` qube can only access the CTAP key associated with ``https://twitter.com``. This means that if anything in your ``twitter`` qube were compromised — the browser or even the OS itself — it would still not be able to access the CTAP keys on your token for any other websites or services, like your email and bank accounts. This is another significant security advantage over monolithic systems. (For details and instructions, see the `Advanced usage <#advanced-usage-per-qube-key-access>`__ section below.)
For even more protection, you can combine this with the :doc:`Qubes firewall </user/security-in-qubes/firewall>` to ensure, for example, that the browser in your ``banking`` qube accesses only one website (your banks website). By configuring the Qubes firewall to prevent your ``banking`` qube from accessing any other websites, you reduce the risk of another website compromising the browser in an attempt to bypass CTAP authentication.
Installation
------------
These instructions assume that there is a ``sys-usb`` qube that holds the USB stack, which is the default configuration in most Qubes OS installations.
In dom0:
.. code:: bash
$ sudo qubes-dom0-update qubes-ctap-dom0
$ qvm-service --enable work qubes-ctap-proxy
The above assumes a ``work`` qube in which you would like to enable ctap. Repeat the ``qvm-service`` command for all qubes that should have the client proxy enabled. Alternatively, you can add ``qubes-ctap-proxy`` in VM settings -> Services in the Qube Manager of each qube you would like to enable the service. Attempting to start the ``qubes-ctap-proxy`` service in the device-hosting qube (``sys-usb``) will fail.
In Fedora templates:
.. code:: bash
$ sudo dnf install qubes-ctap
In Debian templates:
.. code:: bash
$ sudo apt install qubes-ctap
As usual with software updates, shut down the templates after installation, then restart ``sys-usb`` and all qubes that use the proxy. After that, you may use your CTAP authenticator (but see `Browser support <#template-and-browser-support>`__ below).
Advanced usage: per-qube key access
-----------------------------------
If you are using Qubes 4.0, you can further compartmentalise your CTAP keys by restricting each qubes access to specific keys. For example, you could make it so that your ``twitter`` qube (and, therefore, all web browsers in your ``twitter`` qube) can access only the key on your CTAP token for ``https://twitter.com``, regardless of whether any of the web browsers in your ``twitter`` qube or the ``twitter`` qube itself are compromised. If your ``twitter`` qube makes an authentication request for your bank website, it will be denied at the Qubes policy level.
To enable this, create a file in dom0 named ``/etc/qubes/policy.d/30-user-ctapproxy.policy`` with the following content:
.. code:: bash
policy.RegisterArgument +u2f.Authenticate sys-usb @anyvm allow target=dom0
Next, empty the contents of ``/etc/qubes-rpc/policy/u2f.Authenticate`` so that it is a blank file. Do not delete the file itself. (If you do, the default file will be recreated the next time you update, so it will no longer be empty.) Finally, follow your web applications instructions to enroll your token and use it as usual. (This enrollment process depends on the web application and is in no way specific to Qubes CTAP.)
The default model is to allow a qube to access all and only the keys that were enrolled by that qube. For example, if your ``banking`` qube enrolls your banking key, and your ``twitter`` qube enrolls your Twitter key, then your ``banking`` qube will have access to your banking key but not your Twitter key, and your ``twitter`` qube will have access to your Twitter key but not your banking key.
Non-default USB qube name
-------------------------
If your USB qube is named differently than ``sys-usb``, then do the following in the appropriate template(s):
.. code:: bash
systemctl enable qubes-ctapproxy@USB_QUBE.service
systemctl disable qubes-ctapproxy@sys-usb.service
Replace ``USB_QUBE`` with the actual USB qube name.
Do not forget to change the sys-usb qube name in the policy ``/etc/qubes/policy.d/30-user-ctapproxy.policy``.
Template and browser support
----------------------------
The large number of possible combinations of template (Fedora 37, 38; Debian 10, 11) and browser (multiple Google Chrome versions, multiple Chromium versions, multiple Firefox versions) made it impractical for us to test every combination that users are likely to attempt with the Qubes CTAP Proxy. In some cases, you may be the first person to try a particular combination. Consequently, (and as with any new feature), users will inevitably encounter bugs. We ask for your patience and understanding in this regard. As always, please :doc:`report any bugs you encounter </introduction/issue-tracking>`.
.. |Qubes CTAP Proxy diagram| image:: /attachment/doc/ctap.svg

View file

@ -1,56 +0,0 @@
---
lang: en
layout: doc
permalink: /doc/data-leaks/
redirect_from:
- /en/doc/data-leaks/
- /doc/DataLeaks/
- /wiki/DataLeaks/
ref: 171
title: Data leaks
---
The Role of the Firewall
------------------------
**[Firewalling in Qubes](/doc/firewall/) is not intended to be a leak-prevention mechanism.**
There are several reasons for this, which will be explained below.
However, the main reason is that Qubes cannot prevent an attacker who has compromised one app qube with restrictive firewall rules from leaking data via cooperative covert channels through another compromised app qube with nonrestrictive firewall rules.
For example, suppose you have an `email` app qube.
You have set the firewall rules for `email` such that it can communicate only with your email server.
Now suppose that an attacker sends you a GPG-encrypted message which exploits a hypothetical bug in the GnuPG process.
There are now multiple ways the attacker could proceed to leak data (such as confidential email messages) from `email`.
The most obvious way is by simply emailing the data to himself.
Another possibility is that the attacker has also compromised another one of your app qubes, such as your `netvm`, which is normally assumed to be untrusted and has unrestricted access to the network.
In this case, the attacker might move data from `email` to the `netvm` via a covert channel, such as the CPU cache.
Such covert channels have been described and even implemented in some "lab environments" and might allow for bandwidths of even a few tens of bits/sec.
It is unclear whether such channels could be implemented in a real world system, where multiple VMs are running at the same time, each handling tens or hundreds of processes, all using the same cache memory, but it is worth keeping in mind.
Of course, this would require special malware written specifically to attack Qubes OS, and perhaps even a specific Qubes OS version and/or configuration.
Nevertheless, it might be possible.
Note that physically air-gapped machines are not necessarily immune to this problem.
Covert channels can potentially take many forms (e.g., sneakernet thumb drive, bluetooth, or even microphone and speakers).
For a further discussion of covert channels, see [this thread](https://groups.google.com/d/topic/qubes-users/AqZV65yZLuU/discussion) and [#817](https://github.com/QubesOS/qubes-issues/issues/817).
Types of Data Leaks
-------------------
In order to understand and attempt to prevent data leaks in Qubes, we must distinguish among three different types of relevant data leaks:
1. **Intentional leaks.** Malicious software which actively tries to leak data out of an app qube, perhaps via cooperative covert channels established with other malicious software in another app qube or on some server via networking, if networking, even limited, is allowed for the app qube.
2. **Intentional sniffing.** Malicious software trying to use side channels to, e.g., actively guess some key material used in another VM by some non-malicious software there (e.g., non-leak-proof GPG accidentally leaking out bits of the private key by generating some timing patterns when using this key for some crypto operation).
Such attacks have been described in the academic literature, but it is doubtful that they would succeed in practice in a moderately busy general purpose system like Qubes OS where the attacker normally has no way to trigger the target crypto operation explicitly and it is normally required that the attacker trigger many such operations.
3. **Unintentional leaks.** Non-malicious software which is either buggy or doesn't maintain the privacy of user data, whether by design or accident.
For example, software which automatically sends error reports to a remote server, where these reports contain details about the system which the user did not want to share.
Both Qubes firewall and an empty NetVM (i.e., setting the NetVM of an app qube to "none") can fully protect against leaks of type 3.
However, neither Qubes firewall nor an empty NetVM are guaranteed to protect against leaks of types 1 and 2.
There are few effective, practical policy measures available to end-users today to stop the leaks of type 1.
It is likely that the only way to fully protect against leaks of type 2 is to either pause or shut down all other VMs while performing sensitive operations in the target VM(s) (such as key generation).
For further discussion, see [this thread](https://groups.google.com/d/topic/qubes-users/t0cmNfuVduw/discussion).

View file

@ -0,0 +1,36 @@
==========
Data leaks
==========
The Role of the Firewall
------------------------
:doc:`Firewalling in Qubes </user/security-in-qubes/firewall>` **is not intended to be a leak-prevention mechanism.**
There are several reasons for this, which will be explained below. However, the main reason is that Qubes cannot prevent an attacker who has compromised one app qube with restrictive firewall rules from leaking data via cooperative covert channels through another compromised app qube with nonrestrictive firewall rules.
For example, suppose you have an ``email`` app qube. You have set the firewall rules for ``email`` such that it can communicate only with your email server. Now suppose that an attacker sends you a GPG-encrypted message which exploits a hypothetical bug in the GnuPG process. There are now multiple ways the attacker could proceed to leak data (such as confidential email messages) from ``email``. The most obvious way is by simply emailing the data to himself. Another possibility is that the attacker has also compromised another one of your app qubes, such as your ``netvm``, which is normally assumed to be untrusted and has unrestricted access to the network. In this case, the attacker might move data from ``email`` to the ``netvm`` via a covert channel, such as the CPU cache. Such covert channels have been described and even implemented in some “lab environments” and might allow for bandwidths of even a few tens of bits/sec. It is unclear whether such channels could be implemented in a real world system, where multiple VMs are running at the same time, each handling tens or hundreds of processes, all using the same cache memory, but it is worth keeping in mind. Of course, this would require special malware written specifically to attack Qubes OS, and perhaps even a specific Qubes OS version and/or configuration. Nevertheless, it might be possible.
Note that physically air-gapped machines are not necessarily immune to this problem. Covert channels can potentially take many forms (e.g., sneakernet thumb drive, bluetooth, or even microphone and speakers).
For a further discussion of covert channels, see `this thread <https://groups.google.com/d/topic/qubes-users/AqZV65yZLuU/discussion>`__ and `#817 <https://github.com/QubesOS/qubes-issues/issues/817>`__.
Types of Data Leaks
-------------------
In order to understand and attempt to prevent data leaks in Qubes, we must distinguish among three different types of relevant data leaks:
1. **Intentional leaks.** Malicious software which actively tries to leak data out of an app qube, perhaps via cooperative covert channels established with other malicious software in another app qube or on some server via networking, if networking, even limited, is allowed for the app qube.
2. **Intentional sniffing.** Malicious software trying to use side channels to, e.g., actively guess some key material used in another VM by some non-malicious software there (e.g., non-leak-proof GPG accidentally leaking out bits of the private key by generating some timing patterns when using this key for some crypto operation). Such attacks have been described in the academic literature, but it is doubtful that they would succeed in practice in a moderately busy general purpose system like Qubes OS where the attacker normally has no way to trigger the target crypto operation explicitly and it is normally required that the attacker trigger many such operations.
3. **Unintentional leaks.** Non-malicious software which is either buggy or doesnt maintain the privacy of user data, whether by design or accident. For example, software which automatically sends error reports to a remote server, where these reports contain details about the system which the user did not want to share.
Both Qubes firewall and an empty NetVM (i.e., setting the NetVM of an app qube to “none”) can fully protect against leaks of type 3. However, neither Qubes firewall nor an empty NetVM are guaranteed to protect against leaks of types 1 and 2. There are few effective, practical policy measures available to end-users today to stop the leaks of type 1. It is likely that the only way to fully protect against leaks of type 2 is to either pause or shut down all other VMs while performing sensitive operations in the target VM(s) (such as key generation).
For further discussion, see `this thread <https://groups.google.com/d/topic/qubes-users/t0cmNfuVduw/discussion>`__.

View file

@ -1,74 +0,0 @@
---
lang: en
layout: doc
permalink: /doc/device-handling-security/
ref: 170
title: Device handling security
---
Any additional ability a VM gains is additional attack surface.
It's a good idea to always attach the minimum entity required in a VM.
For example, attaching a full USB-device offers [more attack surface than attaching a single block device](https://blog.invisiblethings.org/2011/05/31/usb-security-challenges.html "ITL blog post on USB security"), while
attaching a full block device (e.g. `sda`) again offers more attack surface than attaching a single partition (e.g. `sda1`), since the targetVM doesn't have to parse the partition-table.
(Attaching a full block device offers the advantage that most file-managers will mount and display them correctly, whereas they don't expect single partitions to be added and therefore don't handle them correctly.)
## PCI Security
Attaching a PCI device to a qube has serious security implications.
It exposes the device driver running in the qube to an external device (and sourceVM, which contains the device - e.g. `sys-usb`).
In many cases a malicious device can choose what driver will be loaded (for example by manipulating device metadata like vendor and product identifiers) - even if the intended driver is sufficiently secure, the device may try to attack a different, less secure driver.
Furthermore that VM has full control of the device and may be able to exploit bugs or malicious implementation of the hardware, as well as plain security problems the hardware may pose.
(For example, if you attach a USB controller, all the security implications of USB passthrough apply as well.)
By default, Qubes requires any PCI device to be resettable from the outside (i.e. via the hypervisor), which completely reinitialises the device.
This ensures that any device that was attached to a compromised VM, even if that VM was able to use bugs in the PCI device to inject malicious code, can be trusted again.
(Or at least as trusted as it was when Qubes booted.)
Some devices do not implement a reset option.
In these cases, Qubes by default does not allow attaching the device to any VM.
If you decide to override this precaution, beware that the device may only be trusted when attached to the first VM.
Afterwards, it should be **considered tainted** until the whole system is shut down.
Even without malicious intent, usage data may be leaked.
In case device reset is disabled for any reason, detaching the device should be considered a risk.
Ideally, devices for which the `no-strict-reset` option is set are attached once to a VM which isn't shut down until the system is shut down.
Additionally, Qubes restricts the config-space a VM may use to communicate with a PCI device.
Only whitelisted registers are accessible.
However, some devices or applications require full PCI access.
In these cases, the whole config-space may be allowed.
You're potentially weakening the device isolation, especially if your system is not equipped with a VT-d Interrupt Remapping unit.
This increases the VM's ability to run a [side channel attack](https://en.wikipedia.org/wiki/Side-channel_attack) and vulnerability to the same.
See [Xen PCI Passthrough: PV guests and PCI quirks](https://wiki.xenproject.org/wiki/Xen_PCI_Passthrough#PV_guests_and_PCI_quirks) and [Software Attacks on Intel VT-d](https://invisiblethingslab.com/resources/2011/Software%20Attacks%20on%20Intel%20VT-d.pdf) \(page 7) for more details.
## USB Security
The connection of an untrusted USB device to dom0 is a security risk since the device can attack an arbitrary USB driver (which are included in the linux kernel), exploit bugs during partition-table-parsing or simply pretend to be a keyboard.
There are many ready-to-use implementations of such attacks, e.g. a [USB Rubber Ducky](https://shop.hak5.org/products/usb-rubber-ducky-deluxe).
The whole USB stack is put to work to parse the data presented by the USB device in order to determine if it is a USB mass storage device, to read its configuration, etc.
This happens even if the drive is then assigned and mounted in another qube.
To avoid this risk, use a [USB qube](/doc/usb-qubes/).
Attaching a USB device to a VM (USB passthrough) will **expose your target qube** to most of the [security issues](https://blog.invisiblethings.org/2011/05/31/usb-security-challenges.html "ITL blog post on USB security") associated with the USB-stack.
If possible, use a method specific for particular device type (for example, block devices described above), instead of this generic one.
## Security Warning On USB Input Devices
If you connect USB input devices (keyboard and mouse) to a VM, that VM will effectively have control over your system.
Because of this, the benefits of using a [USB qube](/doc/usb-qubes/) entrusted with a keyboard or other interface device are much smaller than using a fully untrusted USB qube.
In addition to having control over your system, such a VM can also sniff all the input you enter there (for example, passwords in the case of a USB keyboard).
There is no simple way to protect against sniffing, but you can make it harder to exploit control over input devices.
If you have only a USB mouse connected to a USB qube, but the keyboard is connected directly to dom0 (using a PS/2 connector, for example), you simply need to lock the screen when you are away from your computer (assuming you don't use the virtual keyboard of your screen locker).
You must do this every time you leave your computer unattended, even if there no risk of anyone else having direct physical access to your computer.
This is because you are guarding the system not only against anyone with local access, but also against possible malicious input from a potentially compromised USB qube.
If your keyboard is also connected to a USB qube, things are much harder.
Locking the screen (with a traditional password) does not solve the problem, because the USB qube can simply sniff this password and later easily unlock the screen.
One possibility is to set up the screen locker to require an additional step to unlock (i.e., two-factor authentication).
One way to achieve this is to use a [YubiKey](/doc/YubiKey/), or some other hardware token, or even to manually enter a one-time password.
Support for [two factor authentication](/news/2018/09/11/qubes-u2f-proxy/) was recently added, though there are [issues](https://github.com/QubesOS/qubes-issues/issues/4661).

View file

@ -0,0 +1,46 @@
========================
Device handling security
========================
Any additional ability a VM gains is additional attack surface. Its a good idea to always attach the minimum entity required in a VM.
For example, attaching a full USB-device offers `more attack surface than attaching a single block device <https://blog.invisiblethings.org/2011/05/31/usb-security-challenges.html>`__, while attaching a full block device (e.g. ``sda``) again offers more attack surface than attaching a single partition (e.g. ``sda1``), since the targetVM doesnt have to parse the partition-table. (Attaching a full block device offers the advantage that most file-managers will mount and display them correctly, whereas they dont expect single partitions to be added and therefore dont handle them correctly.)
PCI Security
------------
Attaching a PCI device to a qube has serious security implications. It exposes the device driver running in the qube to an external device (and sourceVM, which contains the device - e.g. ``sys-usb``). In many cases a malicious device can choose what driver will be loaded (for example by manipulating device metadata like vendor and product identifiers) - even if the intended driver is sufficiently secure, the device may try to attack a different, less secure driver. Furthermore that VM has full control of the device and may be able to exploit bugs or malicious implementation of the hardware, as well as plain security problems the hardware may pose. (For example, if you attach a USB controller, all the security implications of USB passthrough apply as well.)
By default, Qubes requires any PCI device to be resettable from the outside (i.e. via the hypervisor), which completely reinitialises the device. This ensures that any device that was attached to a compromised VM, even if that VM was able to use bugs in the PCI device to inject malicious code, can be trusted again. (Or at least as trusted as it was when Qubes booted.)
Some devices do not implement a reset option. In these cases, Qubes by default does not allow attaching the device to any VM. If you decide to override this precaution, beware that the device may only be trusted when attached to the first VM. Afterwards, it should be **considered tainted** until the whole system is shut down. Even without malicious intent, usage data may be leaked.
In case device reset is disabled for any reason, detaching the device should be considered a risk. Ideally, devices for which the ``no-strict-reset`` option is set are attached once to a VM which isnt shut down until the system is shut down.
Additionally, Qubes restricts the config-space a VM may use to communicate with a PCI device. Only whitelisted registers are accessible. However, some devices or applications require full PCI access. In these cases, the whole config-space may be allowed. Youre potentially weakening the device isolation, especially if your system is not equipped with a VT-d Interrupt Remapping unit. This increases the VMs ability to run a `side channel attack <https://en.wikipedia.org/wiki/Side-channel_attack>`__ and vulnerability to the same. See `Xen PCI Passthrough: PV guests and PCI quirks <https://wiki.xenproject.org/wiki/Xen_PCI_Passthrough#PV_guests_and_PCI_quirks>`__ and `Software Attacks on Intel VT-d <https://invisiblethingslab.com/resources/2011/Software%20Attacks%20on%20Intel%20VT-d.pdf>`__ (page 7) for more details.
USB Security
------------
The connection of an untrusted USB device to dom0 is a security risk since the device can attack an arbitrary USB driver (which are included in the linux kernel), exploit bugs during partition-table-parsing or simply pretend to be a keyboard. There are many ready-to-use implementations of such attacks, e.g. a `USB Rubber Ducky <https://shop.hak5.org/products/usb-rubber-ducky-deluxe>`__. The whole USB stack is put to work to parse the data presented by the USB device in order to determine if it is a USB mass storage device, to read its configuration, etc. This happens even if the drive is then assigned and mounted in another qube.
To avoid this risk, use a :doc:`USB qube </user/advanced-topics/usb-qubes>`.
Attaching a USB device to a VM (USB passthrough) will **expose your target qube** to most of the `security issues <https://blog.invisiblethings.org/2011/05/31/usb-security-challenges.html>`__ associated with the USB-stack. If possible, use a method specific for particular device type (for example, block devices described above), instead of this generic one.
Security Warning On USB Input Devices
-------------------------------------
If you connect USB input devices (keyboard and mouse) to a VM, that VM will effectively have control over your system. Because of this, the benefits of using a :doc:`USB qube </user/advanced-topics/usb-qubes>` entrusted with a keyboard or other interface device are much smaller than using a fully untrusted USB qube. In addition to having control over your system, such a VM can also sniff all the input you enter there (for example, passwords in the case of a USB keyboard).
There is no simple way to protect against sniffing, but you can make it harder to exploit control over input devices.
If you have only a USB mouse connected to a USB qube, but the keyboard is connected directly to dom0 (using a PS/2 connector, for example), you simply need to lock the screen when you are away from your computer (assuming you dont use the virtual keyboard of your screen locker). You must do this every time you leave your computer unattended, even if there no risk of anyone else having direct physical access to your computer. This is because you are guarding the system not only against anyone with local access, but also against possible malicious input from a potentially compromised USB qube.
If your keyboard is also connected to a USB qube, things are much harder. Locking the screen (with a traditional password) does not solve the problem, because the USB qube can simply sniff this password and later easily unlock the screen. One possibility is to set up the screen locker to require an additional step to unlock (i.e., two-factor authentication). One way to achieve this is to use a :doc:`YubiKey </user/security-in-qubes/mfa>`, or some other hardware token, or even to manually enter a one-time password.
Support for `two factor authentication <https://www.qubes-os.org/news/2018/09/11/qubes-u2f-proxy/>`__ was recently added, though there are `issues <https://github.com/QubesOS/qubes-issues/issues/4661>`__.

View file

@ -1,481 +0,0 @@
---
lang: en
layout: doc
permalink: /doc/firewall/
redirect_from:
- /doc/qubes-firewall/
- /en/doc/qubes-firewall/
- /doc/QubesFirewall/
- /wiki/QubesFirewall/
ref: 166
title: 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://groups.google.com/group/qubes-devel/browse_thread/thread/9e231b0e14bf9d62)
- [https://blog.invisiblethings.org/2011/09/28/playing-with-qubes-networking-for-fun.html](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.
![r4.0-manager-firewall.png](/attachment/doc/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 [R4.x Updates proxy](/doc/software-update-vm/) for more detail).
Note that if you specify a rule by DNS name it will be resolved to IP(s) *at the moment the rules take effect* (including each time the qube or netvm starts), and not on the fly for each new connection.
This means it will not work reliably for servers that have different IPs at different times as a result of DNS-based load balancing.
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:
```
/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:
```
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):
```
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
~~~
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:
~~~
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:
~~~
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:
~~~
[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`:
~~~
[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)
~~~
qubes.ConnectTCP * untrusted @default allow target=mytcp-service
~~~
- In untrusted, use the Qubes tool `qvm-connect-tcp`:
~~~
[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:
~~~
[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
~~~
qubes.ConnectTCP * untrusted mytcp-service allow
~~~
in `/etc/qubes/policy.d/30-user-networking.policy` and in untrusted, use the tool as follow:
~~~
[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`:
~~~
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`
~~~
[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:
~~~
[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:
~~~
[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:
~~~
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.
Only the first method can be used for `sys-net` to find the external 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.
When writing rules in sys-net, you can use `iif` or `iifname`.
`iif` is faster, but can change where interfaces are dynamically created and destroyed, eg. ppp0.
In that case use `iifname`, like this `iifname ens6`.
`iifname` can also match wildcards - `iifname "eth*"`
In the sys-net VM's Terminal, the first step is to define an nftables 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:
```
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 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
```
nft add rule qubes custom-dnat-qubeDEST iifname 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
```
nft add rule qubes custom-forward iifname 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 steps 2 and 3 above, for each interface. Alternatively, you can leave out the interface completely.
Verify the rules on the sys-net firewall correctly match the packets you want by looking at the counters: check for the counter lines in the chains `custom-forward` and `custom-dnat-qubeDEST`:
```
nft list table ip qubes
```
In this example, we can see 7 packets in the forward rule, and 3 packets in the dnat rule:
```
chain custom-forward {
iifname 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;
iifname 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:
```
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:
```
[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`:
~~~
#!/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 iifname 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 iifname 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 interface of sys-firewall facing sys-net, is eth0.
This is allocated to iifgroup 1.
Furthermore, we assume that the IP address of sys-firewall is 10.137.1.z, and the target VM running the web server has the IP address 10.137.0.xx.
In the sys-firewall Terminal, add a DNAT chain that will contain routing rules:
```
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
```
nft add rule qubes custom-dnat-qubeDEST iifgroup 1 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
```
nft add rule qubes custom-forward iifgroup 1 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`
```
[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`:
~~~
#!/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 iifgroup 1 tcp dport 443 ct state new,established,related counter dnat 10.137.0.xx
# allow forwarded traffic
nft add rule qubes custom-forward iifgroup 1 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:
```
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`:
```
[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 [scripts](/doc/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:
```
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:
```
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:
```
nft flush ruleset && nft -f nft_backup
```

View file

@ -0,0 +1,582 @@
========
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 :doc:`here </user/security-in-qubes/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
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 the rules take effect* (including each time the qube or netvm starts), and not on the fly for each new connection. This means it will not work reliably for servers that have different IPs at different times as a result of DNS-based load balancing.
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 qubes 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 doesnt 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 VMs 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 Bs 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 doesnt 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 firewallVMs ``qubes-firewall-user-script`` script. This script is run when the netvm starts up. You should also write relevant rules in A and Bs ``rc.local`` script which is run when the qube is launched. Heres 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. Only the first method can be used for ``sys-net`` to find the external 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.
When writing rules in sys-net, you can use ``iif`` or ``iifname``. ``iif`` is faster, but can change where interfaces are dynamically created and destroyed, eg. ppp0. In that case use ``iifname``, like this ``iifname ens6``. ``iifname`` can also match wildcards - ``iifname "eth*"``
In the sys-net VMs Terminal, the first step is to define an nftables 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, its 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 iifname 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 iifname 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 steps 2 and 3 above, for each interface. Alternatively, you can leave out the interface completely.
Verify the rules on the sys-net firewall correctly match the packets you want by looking at the 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 {
iifname 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;
iifname 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 iifname 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 iifname 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 interface of sys-firewall facing sys-net, is eth0. This is allocated to iifgroup 1. Furthermore, we assume that the IP address of sys-firewall is 10.137.1.z, and the target VM running the web server has the IP address 10.137.0.xx.
In the sys-firewall 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 iifgroup 1 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 iifgroup 1 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 iifgroup 1 tcp dport 443 ct state new,established,related counter dnat 10.137.0.xx
# allow forwarded traffic
nft add rule qubes custom-forward iifgroup 1 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

View file

@ -1,510 +0,0 @@
---
lang: en
layout: doc
permalink: /doc/firewall_4.1/
redirect_from:
ref: 401
title: Firewall 4.1
---
Introduction
----------------------------------
This page explains use of the firewall in Qubes 4.1, using `iptables`.
From Qubes 4.2, all firewall components use `nftables`. For details of that usage see [here](../firewall/).
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://groups.google.com/group/qubes-devel/browse_thread/thread/9e231b0e14bf9d62)
- [https://blog.invisiblethings.org/2011/09/28/playing-with-qubes-networking-for-fun.html](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.
![r4.0-manager-firewall.png](/attachment/doc/r4.0-manager-firewall.png)
If the qube is running, you can open Settings from the Qube Popup Menu.
*R4.0 note:* ICMP and DNS are no longer 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 [R4.0 Updates proxy](/doc/software-update-vm/) 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:
```
/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 `iptables-restore` called from `/rw/config/rc.local`.
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.0 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: `qvm-prefs <vm> netvm <netvm>`
Normally qubes do not connect directly to the actual NetVM 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): `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 iptables or nftables rules in such qubes.
Instead, you should deploy a network infrastructure such as
~~~
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/configuring-a-proxyvm-vpn-gateway/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/scp/NFS protocols.
In order to allow networking between qubes A and B 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 preferences pane for each qube.
- Start both qubes, and also open a terminal in the firewall VM
- In the firewall VM's terminal enter the following iptables rule:
~~~
sudo iptables -I FORWARD 2 -s <IP address of A> -d <IP address of B> -j ACCEPT
~~~
- In qube B's terminal enter the following iptables rule:
~~~
sudo iptables -I INPUT -s <IP address of A> -j 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 iptables 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:
~~~
[user@sys-firewall ~]$ sudo bash
[root@sys-firewall user]# echo "iptables -I FORWARD 2 -s 10.137.2.25 -d 10.137.2.6 -j ACCEPT" >> /rw/config/qubes-firewall-user-script
[root@sys-firewall user]# chmod +x /rw/config/qubes-firewall-user-script
~~~
- Here is an example how to update `rc.local`:
~~~
[user@B ~]$ sudo bash
[root@B user]# echo "iptables -I INPUT -s 10.137.2.25 -j ACCEPT" >> /rw/config/rc.local
[root@B user]# chmod +x /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)
~~~
qubes.ConnectTCP * untrusted @default allow target=mytcp-service
~~~
- In untrusted, use the Qubes tool `qvm-connect-tcp`:
```
[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:
~~~
[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
~~~
qubes.ConnectTCP * untrusted mytcp-service allow
~~~
in `/etc/qubes/policy.d/30-user-networking.policy` and in untrusted, use the tool as follow:
~~~
[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`:
~~~
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`
~~~
[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:
~~~
[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:
~~~
[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:
~~~
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:
- Allow packets through the qube firewall to reach the service
As an example we can take the use case of a web server listening on port 443 that we want to expose on our physical interface eth0, but only to our local network 192.168.x.0/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 from the Settings Window for the qube, or by running this command in each qube:
`ifconfig | grep -i cast `
Note the IP addresses you will need.
> 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 eth0 in sys-net has the IP address 192.168.x.y and that the IP address of sys-firewall is 10.137.1.z.
In the sys-net VM's Terminal, code a natting firewall rule to route traffic on the outside interface for the service to the sys-firewall VM
```
iptables -t nat -A PREROUTING -i eth0 -p tcp --dport 443 -d 192.168.x.y -j DNAT --to-destination 10.137.1.z
```
Code the appropriate new filtering firewall rule to allow new connections for the service
```
iptables -I FORWARD 2 -i eth0 -d 10.137.1.z -p tcp --dport 443 -m conntrack --ctstate NEW -j ACCEPT
```
- If you want to expose the service on multiple interfaces, repeat the steps described in part 1 for each interface.
- In Qubes R4, at the moment ([QubesOS/qubes-issues#3644](https://github.com/QubesOS/qubes-issues/issues/3644)), nftables is also used which imply that additional rules need to be set in a `qubes-firewall` nft table with a forward chain.
`nft add rule ip qubes-firewall forward meta iifname eth0 ip daddr 10.137.1.z tcp dport 443 ct state new counter accept`
Verify you are cutting through the sys-net VM firewall by looking at its counters (column 2)
```
iptables -t nat -L -v -n
iptables -L -v -n
```
- **Note:** On Qubes R4, you can also check the nft counters
```
nft list table ip qubes-firewall
```
Send a test packet by trying to connect to the service from an external device
```
telnet 192.168.x.y 443
```
Once you have confirmed that the counters increase, store these command in `/rw/config/rc.local` so they get set on sys-net start-up
```
sudo nano /rw/config/rc.local
```
~~~
#!/bin/sh
####################
# My service routing
# Create a new firewall natting chain for my service
if iptables -w -t nat -N MY-HTTPS; then
# Add a natting rule if it did not exist (to avoid clutter if script executed multiple times)
iptables -w -t nat -A MY-HTTPS -j DNAT --to-destination 10.137.1.z
fi
# If no prerouting rule exist for my service
if ! iptables -w -t nat -n -L PREROUTING | grep --quiet MY-HTTPS; then
# add a natting rule for the traffic (same reason)
iptables -w -t nat -A PREROUTING -i eth0 -p tcp --dport 443 -d 192.168.x.y -j MY-HTTPS
fi
######################
# My service filtering
# Create a new firewall filtering chain for my service
if iptables -w -N MY-HTTPS; then
# Add a filtering rule if it did not exist (to avoid clutter if script executed multiple times)
iptables -w -A MY-HTTPS -s 192.168.x.0/24 -j ACCEPT
fi
# If no forward rule exist for my service
if ! iptables -w -n -L FORWARD | grep --quiet MY-HTTPS; then
# add a forward rule for the traffic (same reason)
iptables -w -I FORWARD 2 -d 10.137.1.z -p tcp --dport 443 -m conntrack --ctstate NEW -j MY-HTTPS
fi
~~~
- **Note:** Again in R4 the following needs to be added:
~~~
#############
# In Qubes R4
# If not already present
if nft -nn list table ip qubes-firewall | grep "tcp dport 443 ct state new"; then
# Add a filtering rule
nft add rule ip qubes-firewall forward meta iifname eth0 ip daddr 10.137.1.z tcp dport 443 ct state new 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, code a natting firewall rule to route traffic on its outside interface for the service to the qube
```
iptables -t nat -A PREROUTING -i eth0 -p tcp --dport 443 -d 10.137.1.z -j DNAT --to-destination 10.137.0.xx
```
Code the appropriate new filtering firewall rule to allow new connections for the service
```
iptables -I FORWARD 2 -i eth0 -s 192.168.x.0/24 -d 10.137.0.xx -p tcp --dport 443 -m conntrack --ctstate NEW -j ACCEPT
```
- **Note:** If you do not wish to limit the IP addresses connecting to the service, remove the ` -s 192.168.0.1/24 `
- **Note:** On Qubes R4
```
nft add rule ip qubes-firewall forward meta iifname eth0 ip saddr 192.168.x.0/24 ip daddr 10.137.0.xx tcp dport 443 ct state new counter accept
```
Once you have confirmed that the counters increase, store these command in `/rw/config/qubes-firewall-user-script`
```
sudo nano /rw/config/qubes-firewall-user-script
```
~~~
#!/bin/sh
####################
# My service routing
# Create a new firewall natting chain for my service
if iptables -w -t nat -N MY-HTTPS; then
# Add a natting rule if it did not exist (to avoid clutter if script executed multiple times)
iptables -w -t nat -A MY-HTTPS -j DNAT --to-destination 10.137.0.xx
fi
# If no prerouting rule exist for my service
if ! iptables -w -t nat -n -L PREROUTING | grep --quiet MY-HTTPS; then
# add a natting rule for the traffic (same reason)
iptables -w -t nat -A PREROUTING -i eth0 -p tcp --dport 443 -d 10.137.1.z -j MY-HTTPS
fi
######################
# My service filtering
# Create a new firewall filtering chain for my service
if iptables -w -N MY-HTTPS; then
# Add a filtering rule if it did not exist (to avoid clutter if script executed multiple times)
iptables -w -A MY-HTTPS -s 192.168.x.0/24 -j ACCEPT
fi
# If no forward rule exist for my service
if ! iptables -w -n -L FORWARD | grep --quiet MY-HTTPS; then
# add a forward rule for the traffic (same reason)
iptables -w -I FORWARD 4 -d 10.137.0.xx -p tcp --dport 443 -m conntrack --ctstate NEW -j MY-HTTPS
fi
################
# In Qubes OS R4
# If not already present
if ! nft -nn list table ip qubes-firewall | grep "tcp dport 443 ct state new"; then
# Add a filtering rule
nft add rule ip qubes-firewall forward meta iifname eth0 ip saddr 192.168.x.0/24 ip daddr 10.137.0.xx tcp dport 443 ct state new counter accept
fi
~~~
Finally make this file executable (so it runs at every Firewall VM update)
~~~
sudo chmod +x /rw/config/qubes-firewall-user-script
~~~
If the service should be available to other VMs on the same system, do not forget to specify the additional rules described above.
**4. Allow packets into the qube to reach the service**
Here no routing is required, only filtering.
Proceed in the same way as above but store the filtering rule in the `/rw/config/rc.local` script.
For the following example, we assume that the target VM running the web server has the IP address 10.137.0.xx
```
sudo nano /rw/config/rc.local
```
~~~
######################
# My service filtering
# Create a new firewall filtering chain for my service
if iptables -w -N MY-HTTPS; then
# Add a filtering rule if it did not exist (to avoid clutter if script executed multiple times)
iptables -w -A MY-HTTPS -j ACCEPT
fi
# If no input rule exists for my service
if ! iptables -w -n -L INPUT | grep --quiet MY-HTTPS; then
# add a forward rule for the traffic (same reason)
iptables -w -I INPUT 5 -d 10.137.0.xx -p tcp --dport 443 -m conntrack --ctstate NEW -j MY-HTTPS
fi
~~~
This time testing should allow connectivity to the service as long as the service is up :-)
Where to put firewall rules
---------------------------
Implicit in the above example [scripts](/doc/config-files/), but worth calling attention to: for all qubes *except* those supplying networking, iptables commands should be added to the `/rw/config/rc.local` script.
For app qubes supplying networking (`sys-firewall` inclusive), iptables 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.

View file

@ -0,0 +1,604 @@
============
Firewall 4.1
============
Introduction
------------
| This page explains use of the firewall in Qubes 4.1, using ``iptables``.
| From Qubes 4.2, all firewall components use ``nftables``. For details of that usage see :doc:`here </user/security-in-qubes/firewall/>`.
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
If the qube is running, you can open Settings from the Qube Popup Menu.
*R4.0 note:* ICMP and DNS are no longer 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.0 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 qubes 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 ``iptables-restore`` called from ``/rw/config/rc.local``. 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 doesnt 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.0 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: ``qvm-prefs <vm> netvm <netvm>``
Normally qubes do not connect directly to the actual NetVM 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): ``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 iptables or 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/configuring-a-proxyvm-vpn-gateway/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/scp/NFS protocols.
In order to allow networking between qubes A and B 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 preferences pane for each qube.
- Start both qubes, and also open a terminal in the firewall VM
- In the firewall VMs terminal enter the following iptables rule:
.. code:: bash
sudo iptables -I FORWARD 2 -s <IP address of A> -d <IP address of B> -j ACCEPT
- In qube Bs terminal enter the following iptables rule:
.. code:: bash
sudo iptables -I INPUT -s <IP address of A> -j ACCEPT
- Now you should be able to reach B from A test it using e.g. ping issued from A. Note however, that this doesnt 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 iptables rules into firewallVMs ``qubes-firewall-user-script`` script. This script is run when the netvm starts up. You should also write relevant rules in A and Bs ``rc.local`` script which is run when the qube is launched. Heres an example how to update the script:
.. code:: bash
[user@sys-firewall ~]$ sudo bash
[root@sys-firewall user]# echo "iptables -I FORWARD 2 -s 10.137.2.25 -d 10.137.2.6 -j ACCEPT" >> /rw/config/qubes-firewall-user-script
[root@sys-firewall user]# chmod +x /rw/config/qubes-firewall-user-script
- Here is an example how to update ``rc.local``:
.. code:: bash
[user@B ~]$ sudo bash
[root@B user]# echo "iptables -I INPUT -s 10.137.2.25 -j ACCEPT" >> /rw/config/rc.local
[root@B user]# chmod +x /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:
- Allow packets through the qube firewall to reach the service
As an example we can take the use case of a web server listening on port 443 that we want to expose on our physical interface eth0, but only to our local network 192.168.x.0/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 from the Settings Window for the qube, or by running this command in each qube: ``ifconfig | grep -i cast`` Note the IP addresses you will need.
**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 eth0 in sys-net has the IP address 192.168.x.y and that the IP address of sys-firewall is 10.137.1.z.
In the sys-net VMs Terminal, code a natting firewall rule to route traffic on the outside interface for the service to the sys-firewall VM
.. code:: bash
iptables -t nat -A PREROUTING -i eth0 -p tcp --dport 443 -d 192.168.x.y -j DNAT --to-destination 10.137.1.z
Code the appropriate new filtering firewall rule to allow new connections for the service
.. code:: bash
iptables -I FORWARD 2 -i eth0 -d 10.137.1.z -p tcp --dport 443 -m conntrack --ctstate NEW -j ACCEPT
- If you want to expose the service on multiple interfaces, repeat the steps described in part 1 for each interface.
- In Qubes R4, at the moment (`QubesOS/qubes-issues#3644 <https://github.com/QubesOS/qubes-issues/issues/3644>`__), nftables is also used which imply that additional rules need to be set in a ``qubes-firewall`` nft table with a forward chain.
``nft add rule ip qubes-firewall forward meta iifname eth0 ip daddr 10.137.1.z tcp dport 443 ct state new counter accept``
Verify you are cutting through the sys-net VM firewall by looking at its counters (column 2)
.. code:: bash
iptables -t nat -L -v -n
iptables -L -v -n
- **Note:** On Qubes R4, you can also check the nft counters
.. code:: bash
nft list table ip qubes-firewall
Send a test packet by trying to connect to the service from an external device
.. code:: bash
telnet 192.168.x.y 443
Once you have confirmed that the counters increase, store these command in ``/rw/config/rc.local`` so they get set on sys-net start-up
.. code:: bash
sudo nano /rw/config/rc.local
.. code:: bash
#!/bin/sh
####################
# My service routing
# Create a new firewall natting chain for my service
if iptables -w -t nat -N MY-HTTPS; then
# Add a natting rule if it did not exist (to avoid clutter if script executed multiple times)
iptables -w -t nat -A MY-HTTPS -j DNAT --to-destination 10.137.1.z
fi
# If no prerouting rule exist for my service
if ! iptables -w -t nat -n -L PREROUTING | grep --quiet MY-HTTPS; then
# add a natting rule for the traffic (same reason)
iptables -w -t nat -A PREROUTING -i eth0 -p tcp --dport 443 -d 192.168.x.y -j MY-HTTPS
fi
######################
# My service filtering
# Create a new firewall filtering chain for my service
if iptables -w -N MY-HTTPS; then
# Add a filtering rule if it did not exist (to avoid clutter if script executed multiple times)
iptables -w -A MY-HTTPS -s 192.168.x.0/24 -j ACCEPT
fi
# If no forward rule exist for my service
if ! iptables -w -n -L FORWARD | grep --quiet MY-HTTPS; then
# add a forward rule for the traffic (same reason)
iptables -w -I FORWARD 2 -d 10.137.1.z -p tcp --dport 443 -m conntrack --ctstate NEW -j MY-HTTPS
fi
- **Note:** Again in R4 the following needs to be added:
.. code:: bash
#############
# In Qubes R4
# If not already present
if nft -nn list table ip qubes-firewall | grep "tcp dport 443 ct state new"; then
# Add a filtering rule
nft add rule ip qubes-firewall forward meta iifname eth0 ip daddr 10.137.1.z tcp dport 443 ct state new 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 VMs Terminal, code a natting firewall rule to route traffic on its outside interface for the service to the qube
.. code:: bash
iptables -t nat -A PREROUTING -i eth0 -p tcp --dport 443 -d 10.137.1.z -j DNAT --to-destination 10.137.0.xx
Code the appropriate new filtering firewall rule to allow new connections for the service
.. code:: bash
iptables -I FORWARD 2 -i eth0 -s 192.168.x.0/24 -d 10.137.0.xx -p tcp --dport 443 -m conntrack --ctstate NEW -j ACCEPT
- **Note:** If you do not wish to limit the IP addresses connecting to the service, remove the ``-s 192.168.0.1/24``
- **Note:** On Qubes R4
.. code:: bash
nft add rule ip qubes-firewall forward meta iifname eth0 ip saddr 192.168.x.0/24 ip daddr 10.137.0.xx tcp dport 443 ct state new counter accept
Once you have confirmed that the counters increase, store these command in ``/rw/config/qubes-firewall-user-script``
.. code:: bash
sudo nano /rw/config/qubes-firewall-user-script
.. code:: bash
#!/bin/sh
####################
# My service routing
# Create a new firewall natting chain for my service
if iptables -w -t nat -N MY-HTTPS; then
# Add a natting rule if it did not exist (to avoid clutter if script executed multiple times)
iptables -w -t nat -A MY-HTTPS -j DNAT --to-destination 10.137.0.xx
fi
# If no prerouting rule exist for my service
if ! iptables -w -t nat -n -L PREROUTING | grep --quiet MY-HTTPS; then
# add a natting rule for the traffic (same reason)
iptables -w -t nat -A PREROUTING -i eth0 -p tcp --dport 443 -d 10.137.1.z -j MY-HTTPS
fi
######################
# My service filtering
# Create a new firewall filtering chain for my service
if iptables -w -N MY-HTTPS; then
# Add a filtering rule if it did not exist (to avoid clutter if script executed multiple times)
iptables -w -A MY-HTTPS -s 192.168.x.0/24 -j ACCEPT
fi
# If no forward rule exist for my service
if ! iptables -w -n -L FORWARD | grep --quiet MY-HTTPS; then
# add a forward rule for the traffic (same reason)
iptables -w -I FORWARD 4 -d 10.137.0.xx -p tcp --dport 443 -m conntrack --ctstate NEW -j MY-HTTPS
fi
################
# In Qubes OS R4
# If not already present
if ! nft -nn list table ip qubes-firewall | grep "tcp dport 443 ct state new"; then
# Add a filtering rule
nft add rule ip qubes-firewall forward meta iifname eth0 ip saddr 192.168.x.0/24 ip daddr 10.137.0.xx tcp dport 443 ct state new counter accept
fi
Finally make this file executable (so it runs at every Firewall VM update)
.. code:: bash
sudo chmod +x /rw/config/qubes-firewall-user-script
If the service should be available to other VMs on the same system, do not forget to specify the additional rules described above.
**4. Allow packets into the qube to reach the service**
Here no routing is required, only filtering. Proceed in the same way as above but store the filtering rule in the ``/rw/config/rc.local`` script. For the following example, we assume that the target VM running the web server has the IP address 10.137.0.xx
.. code:: bash
sudo nano /rw/config/rc.local
.. code:: bash
######################
# My service filtering
# Create a new firewall filtering chain for my service
if iptables -w -N MY-HTTPS; then
# Add a filtering rule if it did not exist (to avoid clutter if script executed multiple times)
iptables -w -A MY-HTTPS -j ACCEPT
fi
# If no input rule exists for my service
if ! iptables -w -n -L INPUT | grep --quiet MY-HTTPS; then
# add a forward rule for the traffic (same reason)
iptables -w -I INPUT 5 -d 10.137.0.xx -p tcp --dport 443 -m conntrack --ctstate NEW -j MY-HTTPS
fi
This time testing should allow connectivity to the service as long as 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, iptables commands should be added to the ``/rw/config/rc.local`` script. For app qubes supplying networking (``sys-firewall`` inclusive), iptables 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.

View file

@ -1,408 +0,0 @@
---
lang: en
layout: doc
permalink: /doc/mfa/
redirect_from:
- /doc/yubi-key/
- /en/doc/yubi-key/
- /doc/YubiKey/
- /doc/yubikey/
ref: 169
title: Multi-factor Login
---
## Multi-factor authentication within particular qubes
Most use cases for the hardware tokens can be achieved exactly as described by the
manufacturer or other instructions found online. One usually just needs to
attach the token (e.g. YubiKey) to the corresponding app qube to get the same
result (see the documentation on how to use [USB devices](/doc/how-to-use-usb-devices/)
in Qubes OS accordingly). The recommended way for using CTAP in Qubes is described
[here](https://www.qubes-os.org/doc/ctap-proxy/).
## Multi-factor login for Qubes OS
By default Qubes has two protection mechanisms against attackers.
The first is full disk encryption and the second the user login screen / lockscreen.
This article section concerns only adding multi-factor authentication to the second one.
### Time-based One-time Password (TOTP)
As the name implies, this generates authentication code that is time-dependent. You can save the TOTP secret in a mobile app like [FreeOTP](https://en.wikipedia.org/wiki/FreeOTP)
and then use it as an additional factor to login to your Qubes system.
> **Warning**: remember to keep backup access codes.
1. Download `google-authenticator` in dom0:
```
sudo qubes-dom0-update google-authenticator
```
2. Run google authenticator:
```
google-authenticator
```
3. Walk through the setup instructions which will also generate your QR code for your auth app of choice:
```
Do you want me to update your “/home/user/.google_authenticator” file (y/n) y
Do you want to disallow multiple uses of the same authentication token? This restricts you to one login about every 30s, but it increases your chances to notice or even prevent man-in-the-middle attacks (y/n)
By default, tokens are good for 30 seconds, and to compensate for possible time-skew between the client and the server, we allow an extra token before and after the current time. If you experience problems with poor time synchronization, you can increase the window from its default size of 1:30min to about 4min. Do you want to do so (y/n)
If the computer that you are logging into isnt hardened against brute-force login attempts, you can enable rate-limiting for the authentication module. By default, this limits attackers to no more than 3 login attempts every 30s. Do you want to enable rate-limiting (y/n)
```
> **Warning**: in the next session if incorrectly performed, there is the risk of locking yourself out. Before procedding ensure that you have an up-to-date backup.
>
> For advanced users, to make sure you can quickly recover, you can also open another loging session in a tty. To do this, you do `ctrl` + `alt` + `F2` and login normally. Should anything go wrong, as long as you don't shut the computer down, you can still access this tty by entering the same key combination and reverting the changes. After you've opened this "backup" login, you can get to your graphical desktop with `ctrl` + `alt` + `F1`.
Now we are going to add the authenticator as a login requirement:
1. `sudo authselect create-profile mfa --base-on sssd`
2. Edit the custom system authentication template in `/etc/authselect/custom/mfa/system-auth`.
Add the following line right after `auth required pam_faildelay.so delay=2000000`:
```
auth required pam_google_authenticator.so
```
After the change, the top of the file should look like this:
```
{imply "with-smartcard" if "with-smartcard-required"}
auth required pam_env.so
auth required pam_faildelay.so delay=2000000
auth required pam_google_authenticator.so
```
3. Lastly, activate this authentication method with:
```
sudo authselect select custom/mfa
```
Now you can test by locking the screen with `ctrl` + `alt` + `l` . If it was successful and you are pleased with the results, restart your computer.
**Note**: When logging in. the first thing you put is the TOTP secret and then the password. This is true in the screen locker and as well as the session manager (the login window that shows right after you put the disk encryption passphrase).
After this is done, its recommended to do a backup. This is because as long as you incude dom0 in the backup, your authentication code will be backed up as well.
#### Troubleshooting
The following assumes you haven't restarted your computer since setting up TOTP secret.
1. Switch to TTY2 with `ctrl` + `alt` + `F2` .
2. Revert to the original policy with:
```
sudo authselect select sssd
```
3. Switch back to the graphical desktop with `ctrl` + `alt` + `F1` . You should be able to login normally (without multi-factor authentication).
4. Change the mfa custom policy and apply it again.
#### Lost TOTP / authentication device?
In case you've lost your TOTP authentication device, you have two options.
The first option is backup codes. When generating the TOTP secret you must have saved some recovery codes. Those can be used in place of the TOTP code, but they're discarded after use. So make sure you redo the multi-factor authentications intructions.
The second option is recovery from a backup. It will work as long as you included dom0 in said backup. After restoring the dom0 backup, open a terminal in dom0 and the file should be located in `/home/<USER>/home-restore-<DATE>/dom0-home/<USER>/.google_authenticator`.
### Login with a YubiKey / NitroKey3
The YubiKey / NitroKey3 is a hardware authentication device manufactured by Yubico / NitroKey
to protect access to computers, networks, and online services that supports
one-time passwords (OTP), public-key cryptography, and authentication, and the
Universal 2nd Factor [(U2F)](https://en.wikipedia.org/wiki/Universal_2nd_Factor)
and FIDO2 protocols developed by the [FIDO Alliance](https://en.wikipedia.org/wiki/FIDO_Alliance).
You can use a YubiKey / NitroKey3 to enhance the user authentication in Qubes. The following
instructions explain how to setup the YubiKey / NitroKey3 as an *additional* way to login.
After setting it up, you can login by providing both - a password typed in via
keyboard *and* the YubiKey / NitroKey3 plugged in. Someone eavesdropping your login attempt
would not be able to login by only observing and remembering your password.
Stealing your YubiKey / NitroKey3 would not suffice to login either. Only if an attacker has
both, the password and the Yubikey / NitroKey3, it would be possible to login (it is thus
called [Multi-factor authentication](https://en.wikipedia.org/wiki/Multi-factor_authentication)).
The following instructions keep your current login password untouched and
recommends to define a new, additional password that is used in combination with
the YubiKey / NitroKey3 only. This ensures that you a) do not accidentally lock yourself out
during setup and b) you do not need to fear [shoulder
surfing](https://en.wikipedia.org/wiki/Shoulder_surfing_(computer_security)) so
much (i.e. by not using your standard login password in public).
#### Setup login with YubiKey / NitroKey3
To use the YubiKey / NitroKey3 for multi-factor authentication you need to
* install software for the YubiKey / NitroKey3,
* configure the YubiKey for the
[Challenge-Response](https://en.wikipedia.org/wiki/Challenge%E2%80%93response_authentication)
mode or the NitroKey3 for [HOTP](https://en.wikipedia.org/wiki/HMAC-based_one-time_password) mode,
* store the password for YubiKey / NitroKey3 Login and the Challenge-Response / HOTP secret in
dom0,
* enable YubiKey / NitroKey3 authentication for every service you want to use it for.
All these requirements are described below, step by step, for the YubiKey and NitroKey3.
Note that setting up both a YubiKey and a NitroKey3 is not supported.
1. Install YubiKey / NitroKey3 software in the template on which your USB VM is based.
Without this software the challenge-response / HOTP mechanism won't work.
- **YubiKey**
- For Fedora.
```
sudo dnf install ykpers
```
- For Debian.
```
sudo apt-get install yubikey-personalization
```
- **NitroKey3**
- Follow the installation instructions on the official [NitroKey
website](https://docs.nitrokey.com/software/nitropy/all-platforms/installation).
- **WARNING**: *as of April 2024 the official instructions involve using pipx to
install the pynitrokey package and its dependencies without any GPG
verification! This is not a recommended practice, but will soon be
fixed by NitroKey when they start providing release artifacts with
detached signatures on [their GitHub](https://github.com/Nitrokey/pynitrokey/releases).
Proper packaging and distribution for Debian and perhaps Fedora is
also planned for the mid-long term.*
**Installing packages using pip or pipx is not recommended!**
- **both**
- Shut down your template. Then, either reboot your USB VM (so changes inside
the template take effect in your USB app qube) or install the packages inside
your USB VM as well if you would like to avoid rebooting it.
2. Install [qubes-app-yubikey](https://github.com/QubesOS/qubes-app-yubikey) in
dom0. This provides the program to authenticate with password and YubiKey / NitroKey3.
```
sudo qubes-dom0-update qubes-yubikey-dom0
```
3. Configure your YubiKey / NitroKey3:
- **YubiKey**
- Configure your YubiKey for challenge-response `HMAC-SHA1` mode. This can be
done on any qube, e.g. a disposable (you need to [attach the
YubiKey](https://www.qubes-os.org/doc/how-to-use-usb-devices/) to this app qube
though) or directly on the sys-usb vm. You need to (temporarily) install the package "yubikey-personalization-gui" and
run it by typing `yubikey-personalization-gui` in the command line.
- In the program go to `Challenge-Response`,
- select `HMAC-SHA1`,
- choose `Configuration Slot 2`,
- optional: enable `Require user input (button press)` (recommended),
- use `fixed 64 bit input` for `HMAC-SHA1 mode`,
- insert the YubiKey (if not done already) and make sure that it is attached
to the vm,
- press `Write Configuration` once you are ready.
- **NitroKey3**
- Set up a new NK3 Secrets App HOTP secret by attaching the NitroKey to your
USB qube and running the following commands in it:
```
AESKEY=$(echo -n "your-20-digit-secret" | base32)
nitropy nk3 secrets register --kind hotp --hash sha256 --digits-str 8 --counter-start 1 --touch-button loginxs $AESKEY
```
- Note that the 20 digit sequence can contain any printable ASCII character,
e.g. letters, numbers, punctuation marks. The actual `Secret Key (base 32)`
is the base32 encoded form of that sequence.
- **both**
- We will call the `Secret Key (20 bytes hex)` (YubiKey) or `Secret Key (base 32)` `AESKEY`.
- It is recommended to keep a backup of your `AESKEY` in an offline VM used as a vault.
- Consider keeping a backup of your `AESKEY` on paper and storing it in a safe place.
- If you have multiple YubiKeys for backup purposes (in case one gets
lost, stolen or breaks) you can write the same settings into other
YubiKeys. For YubiKeys you can choose "Program multiple YubiKeys" in the program;
make sure to select `Same secret for all keys` in this case. For NitroKeys you can set up
the secret for multiple of them, but you must always use the same NitroKey, because the
HOTP counter will be incremented in dom0 as well as the used NitroKey whenever you make use
of this method. If you want to switch to a different NitroKey later, delete the file
`/etc/qubes/yk-keys/nk-hotp-counter` in dom0 first to make it work with a fresh NitroKey 3.
Do the same if for some reason your counters get desynchronized (it stops working), e.g. due
to connectivity issues (NitroKey3A Minis are known to wear out quickly).
4. **YubiKey**
- Paste your `AESKEY` into `/etc/qubes/yk-keys/yk-secret-key.hex` in dom0.
Note that if you had previously used a NitroKey3 with this package, you *must* delete
the file `/etc/qubes/yk-keys/nk-hotp-secret` or its content!
- **NitroKey3**
- Create the file `/etc/qubes/yk-keys/nk-hotp-secret` in dom0 and paste your `AESKEY`
(in base 32 format) into it.
5. As mentioned before, you need to define a new password that is only used in
combination with the YubiKey / NitroKey3. You can write this password in plain text into
`/etc/qubes/yk-keys/login-pass` in dom0. This is considered safe as dom0 is
ultimately trusted anyway.
- However, if you prefer you can paste a hashed password instead into
`/etc/qubes/yk-keys/login-pass-hashed.hex` in dom0.
- You can calculate your hashed password using the following two commands.
First run the following command to store your password in a temporary variable `password`.
(This way your password will not leak to the terminal command history file.)
```
read -r password
```
- Now run the following command to calculate your hashed password.
```
echo -n "$password" | openssl dgst -sha1 | cut -f2 -d ' '
```
6. To enable multi-factor authentication for a service, you need to add
```
auth include yubikey
```
(same for YubiKey and NitroKey3) to the corresponding service file in `/etc/pam.d/` in dom0.
This means, if you want to enable the login via YubiKey / NitroKey3 for xscreensaver
(the default screen lock program), you add the line at the beginning of `/etc/pam.d/xscreensaver`.
If you want to use the login for a tty shell, add it to `/etc/pam.d/login`. Add
it to `/etc/pam.d/lightdm` if you want to enable the login for the default
display manager and so on.
It is important, that `auth include yubikey` is added at the beginning of
these files, otherwise it will most likely not work.
7. Adjust the USB VM name in case you are using something other than the default
`sys-usb` by editing `/etc/qubes/yk-keys/vm` in dom0.
#### Usage
When you want to authenticate
1. plug your YubiKey / NitroKey3 into an USB slot,
2. enter the password associated with the YubiKey / NitroKey3,
3. press Enter and
4. press the button of the YubiKey / NitroKey3, if you configured the confirmation
(it will light up or blink).
When everything is ok, your screen will be unlocked.
In any case you can still use your normal login password, but do it in a secure
location where no one can snoop your password.
#### Optional: Enforce YubiKey / NitroKey3 Login
Edit `/etc/pam.d/yubikey` (or appropriate file if you are using other screen locker program) and remove `default=ignore` so the line looks like this.
```
auth [success=done] pam_exec.so expose_authtok quiet /usr/bin/yk-auth
```
#### Optional: Locking the screen when YubiKey / NitroKey3 is removed
You can setup your system to automatically lock the screen when you unplug your YubiKey / NitroKey3.
This will require creating a simple qrexec service which will expose the ability to lock the screen to your USB VM, and then adding a udev hook to actually call that service.
In dom0:
1. First configure the qrexec service.
Create `/etc/qubes-rpc/custom.LockScreen` with a simple command to lock the screen.
In the case of xscreensaver (used in Xfce) it would be:
```
DISPLAY=:0 xscreensaver-command -lock
```
2. Then make `/etc/qubes-rpc/custom.LockScreen` executable.
```
sudo chmod +x /etc/qubes-rpc/custom.LockScreen
```
3. Allow your USB VM to call that service.
Assuming that it's named `sys-usb` it would require creating `/etc/qubes-rpc/policy/custom.LockScreen` with:
```
sys-usb dom0 allow
```
In your USB VM:
1. Create udev hook.
Store it in `/rw/config` to have it persist across VM restarts.
For example name the file `/rw/config/yubikey.rules`.
Add the following line:
```
ACTION=="remove", SUBSYSTEM=="usb", ENV{ID_SECURITY_TOKEN}=="1", RUN+="/usr/bin/qrexec-client-vm dom0 custom.LockScreen"
```
2. Ensure that the udev hook is placed in the right place after VM restart.
Append to `/rw/config/rc.local`:
```
ln -s /rw/config/yubikey.rules /etc/udev/rules.d/
udevadm control --reload
```
3. Then make `/rw/config/rc.local` executable.
```
sudo chmod +x /rw/config/rc.local
```
4. For changes to take effect, you need to call this script manually for the first time.
```
sudo /rw/config/rc.local
```
If you use KDE, the command(s) in first step would be different:
```
# In the case of USB VM being autostarted, it will not have direct access to D-Bus
# session bus, so find its address manually:
kde_pid=`pidof kdeinit4`
export `cat /proc/$kde_pid/environ|grep -ao 'DBUS_SESSION_BUS_ADDRESS=[[:graph:]]*'`
qdbus org.freedesktop.ScreenSaver /ScreenSaver Lock
```

View file

@ -0,0 +1,427 @@
==================
Multi-factor Login
==================
Multi-factor authentication within particular qubes
---------------------------------------------------
Most use cases for the hardware tokens can be achieved exactly as described by the manufacturer or other instructions found online. One usually just needs to attach the token (e.g. YubiKey) to the corresponding app qube to get the same result (see the documentation on how to use :doc:`USB devices </user/how-to-guides/how-to-use-usb-devices>` in Qubes OS accordingly). The recommended way for using CTAP in Qubes is described :doc:`here </user/security-in-qubes/ctap-proxy>`.
Multi-factor login for Qubes OS
-------------------------------
By default Qubes has two protection mechanisms against attackers. The first is full disk encryption and the second the user login screen / lockscreen. This article section concerns only adding multi-factor authentication to the second one.
Time-based One-time Password (TOTP)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
As the name implies, this generates authentication code that is time-dependent. You can save the TOTP secret in a mobile app like `FreeOTP <https://en.wikipedia.org/wiki/FreeOTP>`__ and then use it as an additional factor to login to your Qubes system.
**Warning**: remember to keep backup access codes.
1. Download ``google-authenticator`` in dom0:
.. code:: bash
sudo qubes-dom0-update google-authenticator
2. Run google authenticator:
.. code:: bash
google-authenticator
3. Walk through the setup instructions which will also generate your QR code for your auth app of choice:
.. code:: bash
Do you want me to update your “/home/user/.google_authenticator” file (y/n) y
Do you want to disallow multiple uses of the same authentication token? This restricts you to one login about every 30s, but it increases your chances to notice or even prevent man-in-the-middle attacks (y/n)
By default, tokens are good for 30 seconds, and to compensate for possible time-skew between the client and the server, we allow an extra token before and after the current time. If you experience problems with poor time synchronization, you can increase the window from its default size of 1:30min to about 4min. Do you want to do so (y/n)
If the computer that you are logging into isnt hardened against brute-force login attempts, you can enable rate-limiting for the authentication module. By default, this limits attackers to no more than 3 login attempts every 30s. Do you want to enable rate-limiting (y/n)
**Warning**: in the next session if incorrectly performed, there is the risk of locking yourself out. Before procedding ensure that you have an up-to-date backup.
For advanced users, to make sure you can quickly recover, you can also open another loging session in a tty. To do this, you do ``ctrl`` + ``alt`` + ``F2`` and login normally. Should anything go wrong, as long as you dont shut the computer down, you can still access this tty by entering the same key combination and reverting the changes. After youve opened this “backup” login, you can get to your graphical desktop with ``ctrl`` + ``alt`` + ``F1``.
Now we are going to add the authenticator as a login requirement:
1. ``sudo authselect create-profile mfa --base-on sssd``
2. Edit the custom system authentication template in ``/etc/authselect/custom/mfa/system-auth``.
Add the following line right after ``auth required pam_faildelay.so delay=2000000``:
.. code:: bash
auth required pam_google_authenticator.so
After the change, the top of the file should look like this:
.. code:: bash
{imply "with-smartcard" if "with-smartcard-required"}
auth required pam_env.so
auth required pam_faildelay.so delay=2000000
auth required pam_google_authenticator.so
3. Lastly, activate this authentication method with:
.. code:: bash
sudo authselect select custom/mfa
Now you can test by locking the screen with ``ctrl`` + ``alt`` + ``l`` . If it was successful and you are pleased with the results, restart your computer.
**Note**: When logging in. the first thing you put is the TOTP secret and then the password. This is true in the screen locker and as well as the session manager (the login window that shows right after you put the disk encryption passphrase).
After this is done, its recommended to do a backup. This is because as long as you incude dom0 in the backup, your authentication code will be backed up as well.
Troubleshooting
^^^^^^^^^^^^^^^
The following assumes you havent restarted your computer since setting up TOTP secret.
1. Switch to TTY2 with ``ctrl`` + ``alt`` + ``F2`` .
2. Revert to the original policy with:
.. code:: bash
sudo authselect select sssd
3. Switch back to the graphical desktop with ``ctrl`` + ``alt`` + ``F1`` . You should be able to login normally (without multi-factor authentication).
4. Change the mfa custom policy and apply it again.
Lost TOTP / authentication device?
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
In case youve lost your TOTP authentication device, you have two options.
The first option is backup codes. When generating the TOTP secret you must have saved some recovery codes. Those can be used in place of the TOTP code, but theyre discarded after use. So make sure you redo the multi-factor authentications intructions.
The second option is recovery from a backup. It will work as long as you included dom0 in said backup. After restoring the dom0 backup, open a terminal in dom0 and the file should be located in ``/home/<USER>/home-restore-<DATE>/dom0-home/<USER>/.google_authenticator``.
Login with a YubiKey / NitroKey3
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
The YubiKey / NitroKey3 is a hardware authentication device manufactured by Yubico / NitroKey to protect access to computers, networks, and online services that supports one-time passwords (OTP), public-key cryptography, and authentication, and the Universal 2nd Factor `(U2F) <https://en.wikipedia.org/wiki/Universal_2nd_Factor>`__ and FIDO2 protocols developed by the `FIDO Alliance <https://en.wikipedia.org/wiki/FIDO_Alliance>`__.
You can use a YubiKey / NitroKey3 to enhance the user authentication in Qubes. The following instructions explain how to setup the YubiKey / NitroKey3 as an *additional* way to login.
After setting it up, you can login by providing both - a password typed in via keyboard *and* the YubiKey / NitroKey3 plugged in. Someone eavesdropping your login attempt would not be able to login by only observing and remembering your password. Stealing your YubiKey / NitroKey3 would not suffice to login either. Only if an attacker has both, the password and the Yubikey / NitroKey3, it would be possible to login (it is thus called `Multi-factor authentication <https://en.wikipedia.org/wiki/Multi-factor_authentication>`__).
The following instructions keep your current login password untouched and recommends to define a new, additional password that is used in combination with the YubiKey / NitroKey3 only. This ensures that you a) do not accidentally lock yourself out during setup and b) you do not need to fear `shoulder surfing <https://en.wikipedia.org/wiki/Shoulder_surfing_(computer_security)>`__ so much (i.e. by not using your standard login password in public).
Setup login with YubiKey / NitroKey3
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
To use the YubiKey / NitroKey3 for multi-factor authentication you need to
- install software for the YubiKey / NitroKey3,
- configure the YubiKey for the `Challenge-Response <https://en.wikipedia.org/wiki/Challenge%E2%80%93response_authentication>`__ mode or the NitroKey3 for `HOTP <https://en.wikipedia.org/wiki/HMAC-based_one-time_password>`__ mode,
- store the password for YubiKey / NitroKey3 Login and the Challenge-Response / HOTP secret in dom0,
- enable YubiKey / NitroKey3 authentication for every service you want to use it for.
All these requirements are described below, step by step, for the YubiKey and NitroKey3. Note that setting up both a YubiKey and a NitroKey3 is not supported.
1. Install YubiKey / NitroKey3 software in the template on which your USB VM is based. Without this software the challenge-response / HOTP mechanism wont work.
- **YubiKey**
- For Fedora.
.. code:: bash
sudo dnf install ykpers
- For Debian.
.. code:: bash
sudo apt-get install yubikey-personalization
- **NitroKey3**
- Follow the installation instructions on the official `NitroKey website <https://docs.nitrokey.com/software/nitropy/all-platforms/installation>`__.
- **WARNING**: *as of April 2024 the official instructions involve using pipx to install the pynitrokey package and its dependencies without any GPG verification! This is not a recommended practice, but will soon be fixed by NitroKey when they start providing release artifacts with detached signatures on* `their GitHub <https://github.com/Nitrokey/pynitrokey/releases>`__ *. Proper packaging and distribution for Debian and perhaps Fedora is also planned for the mid-long term.* **Installing packages using pip or pipx is not recommended!**
- **both**
- Shut down your template. Then, either reboot your USB VM (so changes inside the template take effect in your USB app qube) or install the packages inside your USB VM as well if you would like to avoid rebooting it.
2. Install `qubes-app-yubikey <https://github.com/QubesOS/qubes-app-yubikey>`__ in dom0. This provides the program to authenticate with password and YubiKey / NitroKey3.
.. code:: bash
sudo qubes-dom0-update qubes-yubikey-dom0
3. Configure your YubiKey / NitroKey3:
- **YubiKey**
- Configure your YubiKey for challenge-response ``HMAC-SHA1`` mode. This can be done on any qube, e.g. a disposable (you need to :doc:`attach the YubiKey </user/how-to-guides/how-to-use-usb-devices>` to this app qube though) or directly on the sys-usb vm. You need to (temporarily) install the package “yubikey-personalization-gui” and run it by typing ``yubikey-personalization-gui`` in the command line.
- In the program go to ``Challenge-Response``,
- select ``HMAC-SHA1``,
- choose ``Configuration Slot 2``,
- optional: enable ``Require user input (button press)`` (recommended),
- use ``fixed 64 bit input`` for ``HMAC-SHA1 mode``,
- insert the YubiKey (if not done already) and make sure that it is attached to the vm,
- press ``Write Configuration`` once you are ready.
- **NitroKey3**
- Set up a new NK3 Secrets App HOTP secret by attaching the NitroKey to your USB qube and running the following commands in it:
.. code:: bash
AESKEY=$(echo -n "your-20-digit-secret" | base32)
nitropy nk3 secrets register --kind hotp --hash sha256 --digits-str 8 --counter-start 1 --touch-button loginxs $AESKEY
- Note that the 20 digit sequence can contain any printable ASCII character, e.g. letters, numbers, punctuation marks. The actual ``Secret Key (base 32)`` is the base32 encoded form of that sequence.
- **both**
- We will call the ``Secret Key (20 bytes hex)`` (YubiKey) or ``Secret Key (base 32)`` ``AESKEY``.
- It is recommended to keep a backup of your ``AESKEY`` in an offline VM used as a vault.
- Consider keeping a backup of your ``AESKEY`` on paper and storing it in a safe place.
- If you have multiple YubiKeys for backup purposes (in case one gets lost, stolen or breaks) you can write the same settings into other YubiKeys. For YubiKeys you can choose “Program multiple YubiKeys” in the program; make sure to select ``Same secret for all keys`` in this case. For NitroKeys you can set up the secret for multiple of them, but you must always use the same NitroKey, because the HOTP counter will be incremented in dom0 as well as the used NitroKey whenever you make use of this method. If you want to switch to a different NitroKey later, delete the file ``/etc/qubes/yk-keys/nk-hotp-counter`` in dom0 first to make it work with a fresh NitroKey 3. Do the same if for some reason your counters get desynchronized (it stops working), e.g. due to connectivity issues (NitroKey3A Minis are known to wear out quickly).
4. **YubiKey**
- Paste your ``AESKEY`` into ``/etc/qubes/yk-keys/yk-secret-key.hex`` in dom0. Note that if you had previously used a NitroKey3 with this package, you *must* delete the file ``/etc/qubes/yk-keys/nk-hotp-secret`` or its content!
- **NitroKey3**
- Create the file ``/etc/qubes/yk-keys/nk-hotp-secret`` in dom0 and paste your ``AESKEY`` (in base 32 format) into it.
5. As mentioned before, you need to define a new password that is only used in combination with the YubiKey / NitroKey3. You can write this password in plain text into ``/etc/qubes/yk-keys/login-pass`` in dom0. This is considered safe as dom0 is ultimately trusted anyway.
- However, if you prefer you can paste a hashed password instead into ``/etc/qubes/yk-keys/login-pass-hashed.hex`` in dom0.
- You can calculate your hashed password using the following two commands. First run the following command to store your password in a temporary variable ``password``. (This way your password will not leak to the terminal command history file.)
.. code:: bash
read -r password
- Now run the following command to calculate your hashed password.
.. code:: bash
echo -n "$password" | openssl dgst -sha1 | cut -f2 -d ' '
6. To enable multi-factor authentication for a service, you need to add
.. code:: bash
auth include yubikey
(same for YubiKey and NitroKey3) to the corresponding service file in ``/etc/pam.d/`` in dom0. This means, if you want to enable the login via YubiKey / NitroKey3 for xscreensaver (the default screen lock program), you add the line at the beginning of ``/etc/pam.d/xscreensaver``. If you want to use the login for a tty shell, add it to ``/etc/pam.d/login``. Add it to ``/etc/pam.d/lightdm`` if you want to enable the login for the default display manager and so on.
It is important, that ``auth include yubikey`` is added at the beginning of these files, otherwise it will most likely not work.
7. Adjust the USB VM name in case you are using something other than the default ``sys-usb`` by editing ``/etc/qubes/yk-keys/vm`` in dom0.
Usage
^^^^^
When you want to authenticate
1. plug your YubiKey / NitroKey3 into an USB slot,
2. enter the password associated with the YubiKey / NitroKey3,
3. press Enter and
4. press the button of the YubiKey / NitroKey3, if you configured the confirmation (it will light up or blink).
When everything is ok, your screen will be unlocked.
In any case you can still use your normal login password, but do it in a secure location where no one can snoop your password.
Optional: Enforce YubiKey / NitroKey3 Login
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Edit ``/etc/pam.d/yubikey`` (or appropriate file if you are using other screen locker program) and remove ``default=ignore`` so the line looks like this.
.. code:: bash
auth [success=done] pam_exec.so expose_authtok quiet /usr/bin/yk-auth
Optional: Locking the screen when YubiKey / NitroKey3 is removed
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
You can setup your system to automatically lock the screen when you unplug your YubiKey / NitroKey3. This will require creating a simple qrexec service which will expose the ability to lock the screen to your USB VM, and then adding a udev hook to actually call that service.
In dom0:
1. First configure the qrexec service. Create ``/etc/qubes-rpc/custom.LockScreen`` with a simple command to lock the screen. In the case of xscreensaver (used in Xfce) it would be:
.. code:: bash
DISPLAY=:0 xscreensaver-command -lock
2. Then make ``/etc/qubes-rpc/custom.LockScreen`` executable.
.. code:: bash
sudo chmod +x /etc/qubes-rpc/custom.LockScreen
3. Allow your USB VM to call that service. Assuming that its named ``sys-usb`` it would require creating ``/etc/qubes-rpc/policy/custom.LockScreen`` with:
.. code:: bash
sys-usb dom0 allow
In your USB VM:
1. Create udev hook. Store it in ``/rw/config`` to have it persist across VM restarts. For example name the file ``/rw/config/yubikey.rules``. Add the following line:
.. code:: bash
ACTION=="remove", SUBSYSTEM=="usb", ENV{ID_SECURITY_TOKEN}=="1", RUN+="/usr/bin/qrexec-client-vm dom0 custom.LockScreen"
2. Ensure that the udev hook is placed in the right place after VM restart. Append to ``/rw/config/rc.local``:
.. code:: bash
ln -s /rw/config/yubikey.rules /etc/udev/rules.d/
udevadm control --reload
3. Then make ``/rw/config/rc.local`` executable.
.. code:: bash
sudo chmod +x /rw/config/rc.local
4. For changes to take effect, you need to call this script manually for the first time.
.. code:: bash
sudo /rw/config/rc.local
If you use KDE, the command(s) in first step would be different:
.. code:: bash
# In the case of USB VM being autostarted, it will not have direct access to D-Bus
# session bus, so find its address manually:
kde_pid=`pidof kdeinit4`
export `cat /proc/$kde_pid/environ|grep -ao 'DBUS_SESSION_BUS_ADDRESS=[[:graph:]]*'`
qdbus org.freedesktop.ScreenSaver /ScreenSaver Lock

View file

@ -1,157 +0,0 @@
---
lang: en
layout: doc
permalink: /doc/split-gpg-2/
redirect_from:
- /en/doc/split-gpg-2/
- /doc/SplitGpg-2/
- /doc/UserDoc/SplitGpg-2/
- /doc/open-pgp-2/
- /en/doc/open-pgp-2/
- /doc/OpenPGP-2/
- /doc/UserDoc/OpenPGP-2/
ref: 568
title: Split GPG-2
---
Split GPG implements a concept similar to having a smart card with your private GPG keys, except that the role of the "smart card" is played by another Qubes app qube.
This way one not-so-trusted domain, e.g. the one where Thunderbird is running, can delegate all crypto operations -- such as encryption/decryption and signing -- to another, more trusted, network-isolated domain.
This way the compromise of your domain where Thunderbird or another client app is running -- arguably a not-so-unthinkable scenario -- does not allow the attacker to automatically also steal all your keys.
(We should make a rather obvious comment here that the so-often-used passphrases on private keys are pretty meaningless because the attacker can easily set up a simple backdoor which would wait until the user enters the passphrase and steal the key then.)
[![split-gpg-diagram.png](/attachment/doc/split-gpg-diagram.png)](/attachment/doc/split-gpg-diagram.png)
This diagram presents an overview of the Split GPG architecture.
## Advantages of Split GPG vs. traditional GPG with a smart card
It is often thought that the use of smart cards for private key storage guarantees ultimate safety.
While this might be true (unless the attacker can find a usually-very-expensive-and-requiring-physical-presence way to extract the key from the smart card) but only with regards to the safety of the private key itself.
However, there is usually nothing that could stop the attacker from requesting the smart card to perform decryption of all the user documents the attacker has found or need to decrypt.
In other words, while protecting the user's private key is an important task, we should not forget that ultimately it is the user data that are to be protected and that the smart card chip has no way of knowing the requests to decrypt documents are now coming from the attacker's script and not from the user sitting in front of the monitor.
(Similarly the smart card doesn't make the process of digitally signing a document or a transaction in any way more secure -- the user cannot know what the chip is really signing.
Unfortunately this problem of signing reliability is not solvable by Split GPG.)
With Qubes Split GPG this problem is drastically minimized, because each time the key is to be used the user is asked for consent (with a definable time out, 5 minutes by default), plus is always notified each time the key is used via a tray notification from the domain where GPG backend is running.
This way it would be easy to spot unexpected requests to decrypt documents.
## Configuration
Create/Edit `/etc/qubes/policy.d/30-user-gpg2.policy` in dom0, and add a line like this:
```
qubes.Gpg2 + gpg-client-vm @default allow target=gpg-server-vm
```
Import/Generate your secret keys in the server domain.
For example:
```
gpg-server-vm$ gpg --import /path/to/my/secret-keys-export
gpg-server-vm$ gpg --import-ownertrust /path/to/my/ownertrust-export
```
or
```
gpg-server-vm$ gpg --gen-key
```
In dom0 enable the `split-gpg2-client` service in the client domain, for example via the command-line:
```shell
dom0$ qvm-service <SPLIT_GPG2_CLIENT_DOMAIN_NAME> split-gpg2-client on
```
To verify if this was done correctly:
```shell
dom0$ qvm-service <SPLIT_GPG2_CLIENT_DOMAIN_NAME>
```
Output should be:
```shell
split-gpg2-client on
```
Restart the client domain.
Export the **public** part of your keys and import them in the client domain.
Also import/set proper "ownertrust" values.
For example:
```
gpg-server-vm$ gpg --export > public-keys-export
gpg-server-vm$ gpg --export-ownertrust > ownertrust-export
gpg-server-vm$ qvm-copy public-keys-export ownertrust-export
gpg-client-vm$ gpg --import ~/QubesIncoming/gpg-server-vm/public-keys-export
gpg-client-vm$ gpg --import-ownertrust ~/QubesIncoming/gpg-server-vm/ownertrust-export
```
This should be enough to have it running:
```
gpg-client-vm$ gpg -K
/home/user/.gnupg/pubring.kbx
-----------------------------
sec# rsa2048 2019-12-18 [SC] [expires: 2021-12-17]
50C2035AF57B98CD6E4010F1B808E4BB07BA9EFB
uid [ultimate] test
ssb# rsa2048 2019-12-18 [E]
```
If you want change some server option copy `/usr/share/doc/split-gpg2/examples/qubes-split-gpg2.conf.example` to `~/.config/qubes-split-gpg2/qubes-split-gpg2.conf` and change it as desired, it will take precedence over other loaded files, such as the drop-in configuration files with the suffix `.conf` in `~/.config/qubes-split-gpg2/conf.d/`.
If you have a passphrase on your keys and `gpg-agent` only shows the "keygrip" (something like the fingerprint of the private key) when asking for the passphrase, then make sure that you have imported the public key part in the server domain.
## Subkeys vs primary keys
split-gpg2 only knows a hash of the data being signed.
Therefore, it cannot differentiate between e.g. signatures of a piece of data or signatures of another key.
This means that a client can use split-gpg2 to sign other keys, which split-gpg1 did not allow.
To prevent this, split-gpg2 creates a new GnuPG home directory and imports the secret subkeys (**not** the primary key!) to it.
Clients will be able to use the secret parts of the subkeys, but not of the primary key.
If your primary key is able to sign data and certify other keys, and your only subkey can only perform encryption, this means that all signing will fail.
To make signing work again, generate a subkey that is capable of signing but **not** certification.
split-gpg2 does not generate this key for you, so you need to generate it yourself.
If you want to generate a key in software, use the `addkey` command of `gpg2 --edit-key`.
If you want to generate a key on a smartcard or other hardware token, use `addcardkey` instead.
## Advanced usage
There are a few option not described in this README.
See the comments in the example [config and the source code](https://github.com/QubesOS/qubes-app-linux-split-gpg2/blob/main/qubes-split-gpg2.conf.example).
Similar to a smartcard, split-gpg2 only tries to protect the private key.
For advanced usages, consider if a specialized RPC service would be better.
It could do things like checking what data is singed, detailed logging, exposing the encrypted content only to a VM without network, etc.
Using split-gpg2 as the "backend" for split-gpg1 is known to work.
## Allow key generation
By setting `allow_keygen = yes` in `qubes-split-gpg2.conf` you can allow the client to generate new keys.
Normal usage should not need this.
**Warning**: This feature is new and not much tested.
Therefore it's not security supported!
## Copyright
Copyright (C) 2014 HW42 <hw42@ipsumj.de>\
Copyright (C) 2019 Marek Marczykowski-Górecki <marmarek@invisiblethingslab.com>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.

View file

@ -0,0 +1,143 @@
===========
Split GPG-2
===========
Split GPG implements a concept similar to having a smart card with your private GPG keys, except that the role of the “smart card” is played by another Qubes app qube. This way one not-so-trusted domain, e.g. the one where Thunderbird is running, can delegate all crypto operations such as encryption/decryption and signing to another, more trusted, network-isolated domain. This way the compromise of your domain where Thunderbird or another client app is running arguably a not-so-unthinkable scenario does not allow the attacker to automatically also steal all your keys. (We should make a rather obvious comment here that the so-often-used passphrases on private keys are pretty meaningless because the attacker can easily set up a simple backdoor which would wait until the user enters the passphrase and steal the key then.)
|split-gpg-diagram.png|
This diagram presents an overview of the Split GPG architecture.
Advantages of Split GPG vs. traditional GPG with a smart card
-------------------------------------------------------------
It is often thought that the use of smart cards for private key storage guarantees ultimate safety. While this might be true (unless the attacker can find a usually-very-expensive-and-requiring-physical-presence way to extract the key from the smart card) but only with regards to the safety of the private key itself. However, there is usually nothing that could stop the attacker from requesting the smart card to perform decryption of all the user documents the attacker has found or need to decrypt. In other words, while protecting the users private key is an important task, we should not forget that ultimately it is the user data that are to be protected and that the smart card chip has no way of knowing the requests to decrypt documents are now coming from the attackers script and not from the user sitting in front of the monitor. (Similarly the smart card doesnt make the process of digitally signing a document or a transaction in any way more secure the user cannot know what the chip is really signing. Unfortunately this problem of signing reliability is not solvable by Split GPG.)
With Qubes Split GPG this problem is drastically minimized, because each time the key is to be used the user is asked for consent (with a definable time out, 5 minutes by default), plus is always notified each time the key is used via a tray notification from the domain where GPG backend is running. This way it would be easy to spot unexpected requests to decrypt documents.
Configuration
-------------
Create/Edit ``/etc/qubes/policy.d/30-user-gpg2.policy`` in dom0, and add a line like this:
.. code:: bash
qubes.Gpg2 + gpg-client-vm @default allow target=gpg-server-vm
Import/Generate your secret keys in the server domain. For example:
.. code:: bash
gpg-server-vm$ gpg --import /path/to/my/secret-keys-export
gpg-server-vm$ gpg --import-ownertrust /path/to/my/ownertrust-export
or
.. code:: bash
gpg-server-vm$ gpg --gen-key
In dom0 enable the ``split-gpg2-client`` service in the client domain, for example via the command-line:
.. code:: bash
dom0$ qvm-service <SPLIT_GPG2_CLIENT_DOMAIN_NAME> split-gpg2-client on
To verify if this was done correctly:
.. code:: bash
dom0$ qvm-service <SPLIT_GPG2_CLIENT_DOMAIN_NAME>
Output should be:
.. code:: bash
split-gpg2-client on
Restart the client domain.
Export the **public** part of your keys and import them in the client domain. Also import/set proper “ownertrust” values. For example:
.. code:: bash
gpg-server-vm$ gpg --export > public-keys-export
gpg-server-vm$ gpg --export-ownertrust > ownertrust-export
gpg-server-vm$ qvm-copy public-keys-export ownertrust-export
gpg-client-vm$ gpg --import ~/QubesIncoming/gpg-server-vm/public-keys-export
gpg-client-vm$ gpg --import-ownertrust ~/QubesIncoming/gpg-server-vm/ownertrust-export
This should be enough to have it running:
.. code:: bash
gpg-client-vm$ gpg -K
/home/user/.gnupg/pubring.kbx
-----------------------------
sec# rsa2048 2019-12-18 [SC] [expires: 2021-12-17]
50C2035AF57B98CD6E4010F1B808E4BB07BA9EFB
uid [ultimate] test
ssb# rsa2048 2019-12-18 [E]
If you want change some server option copy ``/usr/share/doc/split-gpg2/examples/qubes-split-gpg2.conf.example`` to ``~/.config/qubes-split-gpg2/qubes-split-gpg2.conf`` and change it as desired, it will take precedence over other loaded files, such as the drop-in configuration files with the suffix ``.conf`` in ``~/.config/qubes-split-gpg2/conf.d/``.
If you have a passphrase on your keys and ``gpg-agent`` only shows the “keygrip” (something like the fingerprint of the private key) when asking for the passphrase, then make sure that you have imported the public key part in the server domain.
Subkeys vs primary keys
-----------------------
split-gpg2 only knows a hash of the data being signed. Therefore, it cannot differentiate between e.g. signatures of a piece of data or signatures of another key. This means that a client can use split-gpg2 to sign other keys, which split-gpg1 did not allow.
To prevent this, split-gpg2 creates a new GnuPG home directory and imports the secret subkeys (**not** the primary key!) to it. Clients will be able to use the secret parts of the subkeys, but not of the primary key. If your primary key is able to sign data and certify other keys, and your only subkey can only perform encryption, this means that all signing will fail. To make signing work again, generate a subkey that is capable of signing but **not** certification. split-gpg2 does not generate this key for you, so you need to generate it yourself. If you want to generate a key in software, use the ``addkey`` command of ``gpg2 --edit-key``. If you want to generate a key on a smartcard or other hardware token, use ``addcardkey`` instead.
Advanced usage
--------------
There are a few option not described in this README. See the comments in the example `config and the source code <https://github.com/QubesOS/qubes-app-linux-split-gpg2/blob/main/qubes-split-gpg2.conf.example>`__.
Similar to a smartcard, split-gpg2 only tries to protect the private key. For advanced usages, consider if a specialized RPC service would be better. It could do things like checking what data is singed, detailed logging, exposing the encrypted content only to a VM without network, etc.
Using split-gpg2 as the “backend” for split-gpg1 is known to work.
Allow key generation
--------------------
By setting ``allow_keygen = yes`` in ``qubes-split-gpg2.conf`` you can allow the client to generate new keys. Normal usage should not need this.
**Warning**: This feature is new and not much tested. Therefore its not security supported!
Copyright
---------
| Copyright (C) 2014 HW42 `hw42@ipsumj.de <mailto:hw42@ipsumj.de>`__
| Copyright (C) 2019 Marek Marczykowski-Górecki `marmarek@invisiblethingslab.com <mailto:marmarek@invisiblethingslab.com>`__
This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
.. |split-gpg-diagram.png| image:: /attachment/doc/split-gpg-diagram.png

View file

@ -1,401 +0,0 @@
---
lang: en
layout: doc
permalink: /doc/split-gpg/
redirect_from:
- /en/doc/split-gpg/
- /doc/SplitGpg/
- /doc/UserDoc/SplitGpg/
- /wiki/UserDoc/SplitGpg/
- /doc/open-pgp/
- /en/doc/open-pgp/
- /doc/OpenPGP/
- /doc/UserDoc/OpenPGP/
- /wiki/UserDoc/OpenPGP/
ref: 168
title: Split GPG
---
<div class="alert alert-warning" role="alert">
<i class="fa fa-exclamation-circle"></i>
<b>Note:</b> This information concerns split-gpg.
The implementation has been updated to provide more features in split-gpg-2. Some incomplete information on split-gpg-2 is available <a href="https://www.qubes-os.org/doc/split-gpg-2/">here</a>
</div>
Split GPG implements a concept similar to having a smart card with your private GPG keys, except that the role of the "smart card" is played by another Qubes app qube.
This way one not-so-trusted domain, e.g. the one where Thunderbird is running, can delegate all crypto operations -- such as encryption/decryption and signing -- to another, more trusted, network-isolated domain.
This way the compromise of your domain where Thunderbird or another client app is running -- arguably a not-so-unthinkable scenario -- does not allow the attacker to automatically also steal all your keys.
(We should make a rather obvious comment here that the so-often-used passphrases on private keys are pretty meaningless because the attacker can easily set up a simple backdoor which would wait until the user enters the passphrase and steal the key then.)
[![split-gpg-diagram.png](/attachment/doc/split-gpg-diagram.png)](/attachment/doc/split-gpg-diagram.png)
This diagram presents an overview of the Split GPG architecture.
## Advantages of Split GPG vs. traditional GPG with a smart card
It is often thought that the use of smart cards for private key storage guarantees ultimate safety.
While this might be true (unless the attacker can find a usually-very-expensive-and-requiring-physical-presence way to extract the key from the smart card) but only with regards to the safety of the private key itself.
However, there is usually nothing that could stop the attacker from requesting the smart card to perform decryption of all the user documents the attacker has found or need to decrypt.
In other words, while protecting the user's private key is an important task, we should not forget that ultimately it is the user data that are to be protected and that the smart card chip has no way of knowing the requests to decrypt documents are now coming from the attacker's script and not from the user sitting in front of the monitor.
(Similarly the smart card doesn't make the process of digitally signing a document or a transaction in any way more secure -- the user cannot know what the chip is really signing.
Unfortunately this problem of signing reliability is not solvable by Split GPG.)
With Qubes Split GPG this problem is drastically minimized, because each time the key is to be used the user is asked for consent (with a definable time out, 5 minutes by default), plus is always notified each time the key is used via a tray notification from the domain where GPG backend is running.
This way it would be easy to spot unexpected requests to decrypt documents.
[![r2-split-gpg-1.png](/attachment/doc/r2-split-gpg-1.png)](/attachment/doc/r2-split-gpg-1.png)
[![r2-split-gpg-3.png](/attachment/doc/r2-split-gpg-3.png)](/attachment/doc/r2-split-gpg-3.png)
## Configuring Split GPG
In dom0, make sure the `qubes-gpg-split-dom0` package is installed.
```
[user@dom0 ~]$ sudo qubes-dom0-update qubes-gpg-split-dom0
```
Make sure you have the `qubes-gpg-split` package installed in the template you will use for the GPG domain.
For Debian or Whonix:
```
[user@debian-10 ~]$ sudo apt install qubes-gpg-split
```
For Fedora:
```
[user@fedora-32 ~]$ sudo dnf install qubes-gpg-split
```
### Setting up the GPG backend domain
First, create a dedicated app qube for storing your keys (we will be calling it the GPG backend domain).
It is recommended that this domain be network disconnected (set its netvm to `none`) and only used for this one purpose.
In later examples this app qube is named `work-gpg`, but of course it might have any other name.
Make sure that gpg is installed there.
At this stage you can add the private keys you want to store there, or you can now set up Split GPG and add the keys later.
To check which private keys are in your GPG keyring, use:
```shell_session
[user@work-gpg ~]$ gpg -K
/home/user/.gnupg/secring.gpg
-----------------------------
sec 4096R/3F48CB21 2012-11-15
uid Qubes OS Security Team <security@qubes-os.org>
ssb 4096R/30498E2A 2012-11-15
(...)
```
This is pretty much all that is required.
However, you might want to modify the default timeout: this tells the backend for how long the user's approval for key access should be valid.
(The default is 5 minutes.) You can change this via the `QUBES_GPG_AUTOACCEPT` environment variable.
You can override it e.g. in `~/.profile`:
```shell_session
[user@work-gpg ~]$ echo "export QUBES_GPG_AUTOACCEPT=86400" >> ~/.profile
```
Please note that previously, this parameter was set in ~/.bash_profile.
This will no longer work.
If you have the parameter set in ~/.bash_profile you *must* update your configuration.
Please be aware of the caveat regarding passphrase-protected keys in the [Current limitations](#current-limitations) section.
### Configuring the client apps to use Split GPG backend
Normally it should be enough to set the `QUBES_GPG_DOMAIN` to the GPG backend domain name and use `qubes-gpg-client` in place of `gpg`, e.g.:
```shell_session
[user@work-email ~]$ export QUBES_GPG_DOMAIN=work-gpg
[user@work-email ~]$ gpg -K
[user@work-email ~]$ qubes-gpg-client -K
/home/user/.gnupg/secring.gpg
-----------------------------
sec 4096R/3F48CB21 2012-11-15
uid Qubes OS Security Team <security@qubes-os.org>
ssb 4096R/30498E2A 2012-11-15
(...)
[user@work-email ~]$ qubes-gpg-client secret_message.txt.asc
(...)
```
Note that running normal `gpg -K` in the demo above shows no private keys stored in this app qube.
A note on `gpg` and `gpg2`:
Throughout this guide, we refer to `gpg`, but note that Split GPG uses `gpg2` under the hood for compatibility with programs like Enigmail (which now supports only `gpg2`).
If you encounter trouble while trying to set up Split GPG, make sure you're using `gpg2` for your configuration and testing, since keyring data may differ between the two installations.
### Advanced Configuration
The `qubes-gpg-client-wrapper` script sets the `QUBES_GPG_DOMAIN` variable automatically based on the content of the file `/rw/config/gpg-split-domain`, which should be set to the name of the GPG backend VM. This file survives the app qube reboot, of course.
```shell_session
[user@work-email ~]$ sudo bash
[root@work-email ~]$ echo "work-gpg" > /rw/config/gpg-split-domain
```
Split GPG's default qrexec policy requires the user to enter the name of the app qube containing GPG keys on each invocation. To improve usability for applications like Thunderbird with Enigmail, in `dom0` place the following line at the top of the file `/etc/qubes-rpc/policy/qubes.Gpg`:
```
work-email work-gpg allow
```
where `work-email` is the Thunderbird + Enigmail app qube and `work-gpg` contains your GPG keys.
You may also edit the qrexec policy file for Split GPG in order to tell Qubes your default gpg vm (qrexec prompts will appear with the gpg vm preselected as the target, instead of the user needing to type a name in manually). To do this, append `default_target=<vmname>` to `ask` in `/etc/qubes-rpc/policy/qubes.Gpg`. For the examples given on this page:
```
@anyvm @anyvm ask default_target=work-gpg
```
Note that, because this makes it easier to accept Split GPG's qrexec authorization prompts, it may decrease security if the user is not careful in reviewing presented prompts. This may also be inadvisable if there are multiple app qubes with Split GPG set up.
## Using Thunderbird
### Thunderbird 78 and higher
Starting with version 78, Thunderbird has a built-in PGP feature and no longer requires the Enigmail extension. For users coming from the Enigmail extension, the built-in functionality is more limited currently, including that **public keys must live in your `work-email` qube with Thunderbird rather than your offline `work-gpg` qube**.
In `work-email`, use the Thunderbird config editor (found at the bottom of preferences/options), and search for `mail.openpgp.allow_external_gnupg`. Switch the value to true. Still in config editor, search for `mail.openpgp.alternative_gpg_path`. Set its value to `/usr/bin/qubes-gpg-client-wrapper`. Restart Thunderbird after this change.
[![tb78-1.png](/attachment/doc/tb78-1.png)](/attachment/doc/tb78-1.png)
[![tb78-2.png](/attachment/doc/tb78-2.png)](/attachment/doc/tb78-2.png)
[![tb78-3.png](/attachment/doc/tb78-3.png)](/attachment/doc/tb78-3.png)
You need to obtain your key ID which should be **exactly 16 characters**. Enter the command `qubes-gpg-client-wrapper -K --keyid-format long`:
```
[user@work-email ~]$ qubes-gpg-client-wrapper -K --keyid-format long
/home/user/.gnupg/pubring.kbx
-----------------------------
sec rsa2048/777402E6D301615C 2020-09-05 [SC] [expires: 2022-09-05]
F7D2D4E922DFB7B2589AF3E9777402E6D301615C
uid [ultimate] Qubes test <user@localhost>
ssb rsa2048/370CE932085BA13B 2020-09-05 [E] [expires: 2022-09-05]
```
```
[user@work-email ~]$ qubes-gpg-client-wrapper --armor --export 777402E6D301615C > 777402E6D301615C.asc
```
Open the Account Settings and open the *End-to-End Encryption* tab of the respective email account. Click the *Add Key* button. You'll be offered the choice *Use your external key through GnuPG*. Select it and click Continue.
[![tb78-4.png](/attachment/doc/tb78-4.png)](/attachment/doc/tb78-4.png)
[![tb78-5.png](/attachment/doc/tb78-5.png)](/attachment/doc/tb78-5.png)
The key ID reference you would need here is `777402E6D301615C`. Now paste or type the ID of the secret key that you would like to use. Be careful to enter it correctly, because your input isn't verified. Confirm to save this key ID. Now you can select the key ID to use.
[![tb78-6.png](/attachment/doc/tb78-6.png)](/attachment/doc/tb78-6.png)
[![tb78-7.png](/attachment/doc/tb78-7.png)](/attachment/doc/tb78-7.png)
This key ID will be used to digitally sign or send an encrypted message with your account. For this to work, Thunderbird needs a copy of your public key. At this time, Thunderbird doesn't fetch the public key from `/usr/bin/qubes-gpg-client-wrapper`, you must manually import it. Export the key as follow (assuming the key ID would be `777402E6D301615C`):
[![tb78-8.png](/attachment/doc/tb78-8.png)](/attachment/doc/tb78-8.png)
[![tb78-9.png](/attachment/doc/tb78-9.png)](/attachment/doc/tb78-9.png)
Use Thunderbird's Tools menu to open *OpenPGP Key Management*. In that window, use the File menu to access the *Import Public Key(s) From File* command. Open the file with your public key. After the import was successful, right click on the imported key in the list and select *Key Properties*. You must mark your own key as *Yes, I've verified in person this key has the correct fingerprint*.
Once this is done, you should be able to send an encrypted and signed email by selecting *Require Encryption* or *Digitally Sign This Message* in the compose menu *Options* or *Security* toolbar button. You can try it by sending an email to yourself.
[![tb78-10.png](/attachment/doc/tb78-10.png)](/attachment/doc/tb78-10.png)
For more details about using smart cards/Split GPG with Thunderbird PGP feature, please see [Thunderbird:OpenPGP:Smartcards](https://wiki.mozilla.org/Thunderbird:OpenPGP:Smartcards) from which the above documentation is inspired.
### Older Thunderbird versions
For Thunderbird versions below 78, the traditional Enigmail + Split GPG setup is required.
It is recommended to set up and use `/usr/bin/qubes-gpg-client-wrapper`, as discussed above, in Thunderbird through the Enigmail addon.
**Warning:** Before adding any account, configuring Enigmail with `/usr/bin/qubes-gpg-client-wrapper` is **required**. By default, Enigmail will generate a default GPG key in `work-email` associated with the newly created Thunderbird account. Generally, it corresponds to the email used in `work-gpg` associated to your private key. In consequence, a new, separate private key will be stored in `work-email` but it _does not_ correspond to your private key in `work-gpg`. Comparing the `fingerprint` or `expiration date` will show that they are not the same private key. In order to prevent Enigmail using this default generated local key in `work-email`, you can safely remove it.
On a fresh Enigmail install, your need to change the default `Enigmail Junior Mode`. Go to Thunderbird preferences and then privacy tab. Select `Force using S/MIME and Enigmail`. Then, in the preferences of Enigmail, make it point to `/usr/bin/qubes-gpg-client-wrapper` instead of the standard GnuPG binary:
[![tb-enigmail-split-gpg-settings-2.png](/attachment/doc/tb-enigmail-split-gpg-settings-2.png)](/attachment/doc/tb-enigmail-split-gpg-settings-2.png)
## Using Keybase with Split GPG
Keybase, a security focused messaging and file-sharing app with GPG integration, can be configured to use Split GPG.
The Keybase service does not preserve/pass the `QUBES_GPG_DOMAIN` environment variable through to underlying GPG processes, so it **must** be configured to use `/usr/bin/qubes-gpg-client-wrapper` (as discussed above) rather than `/usr/bin/qubes-gpg-client`.
The following command will configure Keybase to use `/usr/bin/qubes-gpg-client-wrapper` instead of its built-in GPG client:
```
$ keybase config set gpg.command /usr/bin/qubes-gpg-client-wrapper
```
Now that Keybase is configured to use `qubes-gpg-client-wrapper`, you will be able to use `keybase pgp select` to choose a GPG key from your backend GPG app qube and link that key to your Keybase identity.
## Using Git with Split GPG
Git can be configured to utilize Split GPG, something useful if you would like to contribute to the Qubes OS Project as every commit is required to be signed.
The most basic `~/.gitconfig` file enabling Split GPG looks something like this.
```
[user]
name = <YOUR_NAME>
email = <YOUR_EMAIL_ADDRESS>
signingKey = <YOUR_KEY_ID>
[gpg]
program = qubes-gpg-client-wrapper
```
Your key id is the public id of your signing key, which can be found by running `qubes-gpg-client --list-keys`.
In this instance, the key id is E142F75A6B1B610E0E8F874FB45589245791CACB.
```shell_session
[user@work-email ~]$ qubes-gpg-client --list-keys
/home/user/.gnupg/pubring.kbx
-----------------------------
pub ed25519 2022-08-16 [C]
E142F75A6B1B610E0E8F874FB45589245791CACB
uid [ultimate] Qubes User <user@example.com>
sub ed25519 2022-08-16 [S]
sub cv25519 2022-08-16 [E]
sub ed25519 2022-08-16 [A]
```
To sign commits, you now add the "-S" flag to your commit command, which should prompt for Split GPG usage.
If you would like to automatically sign all commits, you can add the following snippet to `~/.gitconfig`.
```
[commit]
gpgSign = true
```
Lastly, if you would like to add aliases to sign and verify tags using the conventions the Qubes OS Project recommends, refer to the [code signing documentation](/doc/code-signing/#using-pgp-with-git).
## Importing public keys
Use `qubes-gpg-import-key` in the client app qube to import the key into the GPG backend VM.
```shell_session
[user@work-email ~]$ export QUBES_GPG_DOMAIN=work-gpg
[user@work-email ~]$ qubes-gpg-import-key ~/Downloads/marmarek.asc
```
A safe, unspoofable user consent dialog box is displayed.
[![r2-split-gpg-5.png](/attachment/doc/r2-split-gpg-5.png)](/attachment/doc/r2-split-gpg-5.png)
Selecting "Yes to All" will add a line in the corresponding [RPC Policy](/doc/rpc-policy/) file.
## Advanced: Using Split GPG with Subkeys
Users with particularly high security requirements may wish to use Split GPG with [subkeys](https://wiki.debian.org/Subkeys).
However, this setup comes at a significant cost: It will be impossible to sign other people's keys with the master secret key without breaking this security model.
Nonetheless, if signing others' keys is not required, then Split GPG with subkeys offers unparalleled security for one's master secret key.
### Setup Description
In this example, the following keys are stored in the following locations (see below for definitions of these terms):
| PGP Key(s) | VM Name |
| ---------- | ------------ |
| `sec` | `vault` |
| `ssb` | `work-gpg` |
| `pub` | `work-email` |
* `sec` (master secret key)
- Depending on your needs, you may wish to create this as a **certify-only (C)** key, i.e., a key which is capable only of signing (a.k.a., "certifying") other keys.
This key may be created *without* an expiration date.
This is for two reasons.
First, the master secret key is never to leave the `vault` VM, so it is extremely unlikely ever to be obtained by an adversary (see below).
Second, an adversary who *does* manage to obtain the master secret key either possesses the passphrase to unlock the key (if one is used) or does not.
An adversary who *does* possess the passphrase can simply use it to legally extend the expiration date of the key (or remove it entirely).
An adversary who does *not* possess the passphrase cannot use the key at all.
In either case, an expiration date provides no additional benefit.
- By the same token, however, having a passphrase on the key is of little value.
An adversary who is capable of stealing the key from your `vault` would almost certainly also be capable of stealing the passphrase as you enter it.
An adversary who obtains the passphrase can then use it in order to change or remove the passphrase from the key.
Therefore, using a passphrase at all should be considered optional.
It is, however, recommended that a **revocation certificate** be created and safely stored in multiple locations so that the master keypair can be revoked in the (exceedingly unlikely) event that it is ever compromised.
* `ssb` (secret subkey)
- Depending on your needs, you may wish to create two different subkeys: one for **signing (S)** and one for **encryption (E)**.
You may also wish to give these subkeys reasonable expiration dates (e.g., one year).
Once these keys expire, it is up to you whether to *renew* these keys by extending the expiration dates or to create *new* subkeys when the existing set expires.
- On the one hand, an adversary who obtains any existing encryption subkey (for example) will be able to use it in order to decrypt all emails (for example) which were encrypted to that subkey.
If the same subkey were to continue to be used--and its expiration date continually extended--only that one key would need to be stolen (e.g., as a result of the `work-gpg` VM being compromised; see below) in order to decrypt *all* of the user's emails.
If, on the other hand, each encryption subkey is used for at most approximately one year, then an adversary who obtains the secret subkey will be capable of decrypting at most approximately one year's worth of emails.
- On the other hand, creating a new signing subkey each year without renewing (i.e., extending the expiration dates of) existing signing subkeys would mean that all of your old signatures would eventually read as "EXPIRED" whenever someone attempts to verify them.
This can be problematic, since there is no consensus on how expired signatures should be handled.
Generally, digital signatures are intended to last forever, so this is a strong reason against regularly retiring one's signing subkeys.
* `pub` (public key)
- This is the complement of the master secret key.
It can be uploaded to keyservers (or otherwise publicly distributed) and may be signed by others.
* `vault`
- This is a network-isolated VM.
The initial master keypair and subkeys are generated in this VM.
The master secret key *never* leaves this VM under *any* circumstances.
No files or text is *ever* [copied](/doc/how-to-copy-and-move-files/#security) or [pasted](/doc/how-to-copy-and-paste-text/#security) into this VM under *any* circumstances.
* `work-gpg`
- This is a network-isolated VM.
This VM is used *only* as the GPG backend for `work-email`.
The secret subkeys (but *not* the master secret key) are [copied](/doc/how-to-copy-and-move-files/#security) from the `vault` VM to this VM.
Files from less trusted VMs are *never* [copied](/doc/how-to-copy-and-move-files/#security) into this VM under *any* circumstances.
* `work-email`
- This VM has access to the mail server.
It accesses the `work-gpg` VM via the Split GPG protocol.
The public key may be stored in this VM so that it can be attached to emails and for other such purposes.
### Security Benefits
In the standard Split GPG setup, there are at least two ways in which the `work-gpg` VM might be compromised.
First, an attacker who is capable of exploiting a hypothetical bug in `work-email`'s [MUA](https://en.wikipedia.org/wiki/Mail_user_agent) could gain control of the `work-email` VM and send a malformed request which exploits a hypothetical bug in the GPG backend (running in the `work-gpg` VM), giving the attacker control of the `work-gpg` VM.
Second, a malicious public key file which is imported into the `work-gpg` VM might exploit a hypothetical bug in the GPG backend which is running there, again giving the attacker control of the `work-gpg` VM.
In either case, such an attacker might then be able to leak both the master secret key and its passphrase (if any is used, it would regularly be input in the work-gpg VM and therefore easily obtained by an attacker who controls this VM) back to the `work-email` VM or to another VM (e.g., the `netvm`, which is always untrusted by default) via the Split GPG protocol or other [covert channels](/doc/data-leaks/).
Once the master secret key is in the `work-email` VM, the attacker could simply email it to himself (or to the world).
In the alternative setup described in this section (i.e., the subkey setup), even an attacker who manages to gain access to the `work-gpg` VM will not be able to obtain the user's master secret key since it is simply not there.
Rather, the master secret key remains in the `vault` VM, which is extremely unlikely to be compromised, since nothing is ever copied or transferred into it.
[^a-note] The attacker might nonetheless be able to leak the secret subkeys from the `work-gpg` VM in the manner described above, but even if this is successful, the secure master secret key can simply be used to revoke the compromised subkeys and to issue new subkeys in their place.
(This is significantly less devastating than having to create a new *master* keypair.)
[^a-note]: In order to gain access to the `vault` VM, the attacker would require the use of, e.g., a general Xen VM escape exploit or a [signed, compromised package which is already installed in the template](/doc/templates/#trusting-your-templates) upon which the `vault` VM is based.
### Subkey Tutorials and Discussions
(Note: Although the tutorials below were not written with Qubes Split GPG in mind, they can be adapted with a few commonsense adjustments.
As always, exercise caution and use your good judgment.)
* ["OpenPGP in Qubes OS" on the qubes-users mailing list](https://groups.google.com/d/topic/qubes-users/Kwfuern-R2U/discussion)
* ["Creating the Perfect GPG Keypair" by Alex Cabal](https://alexcabal.com/creating-the-perfect-gpg-keypair/)
* ["GPG Offline Master Key w/ smartcard" maintained by Abel Luck](https://gist.github.com/abeluck/3383449)
* ["Using GnuPG with QubesOS" by Alex](https://apapadop.wordpress.com/2013/08/21/using-gnupg-with-qubesos/)
## Current limitations
* Current implementation requires importing of public keys to the vault domain.
This opens up an avenue to attack the gpg running in the backend domain via a hypothetical bug in public key importing code.
See ticket [#474](https://github.com/QubesOS/qubes-issues/issues/474) for more details and plans how to get around this problem, as well as the section on [using Split GPG with subkeys](#advanced-using-split-gpg-with-subkeys).
* It doesn't solve the problem of allowing the user to know what is to be signed before the operation gets approved.
Perhaps the GPG backend domain could start a disposable and have the to-be-signed document displayed there? To Be Determined.
* The Split GPG client will fail to sign or encrypt if the private key in the GnuPG backend is protected by a passphrase.
It will give an `Inappropriate ioctl for device` error.
Do not set passphrases for the private keys in the GPG backend domain.
Doing so won't provide any extra security anyway, as explained in the introduction and in [using Split GPG with subkeys](#advanced-using-split-gpg-with-subkeys).
If you are generating a new key pair, or if you have a private key that already has a passphrase, you can use `gpg2 --edit-key <key_id>` then `passwd` to set an empty passphrase.
Note that `pinentry` might show an error when you try to set an empty passphrase, but it will still make the change.
(See [this StackExchange answer](https://unix.stackexchange.com/a/379373) for more information.)
Note: The error shows only if you **do not** have graphical pinentry installed.

View file

@ -0,0 +1,444 @@
=========
Split GPG
=========
.. warning::
**Note:** This information concerns split-gpg. The implementation has been updated to provide more features in split-gpg-2. Some incomplete information on split-gpg-2 is available :doc:`here </user/security-in-qubes/split-gpg-2>`.
Split GPG implements a concept similar to having a smart card with your private GPG keys, except that the role of the “smart card” is played by another Qubes app qube. This way one not-so-trusted domain, e.g. the one where Thunderbird is running, can delegate all crypto operations such as encryption/decryption and signing to another, more trusted, network-isolated domain. This way the compromise of your domain where Thunderbird or another client app is running arguably a not-so-unthinkable scenario does not allow the attacker to automatically also steal all your keys. (We should make a rather obvious comment here that the so-often-used passphrases on private keys are pretty meaningless because the attacker can easily set up a simple backdoor which would wait until the user enters the passphrase and steal the key then.)
|split-gpg-diagram.png|
This diagram presents an overview of the Split GPG architecture.
Advantages of Split GPG vs. traditional GPG with a smart card
-------------------------------------------------------------
It is often thought that the use of smart cards for private key storage guarantees ultimate safety. While this might be true (unless the attacker can find a usually-very-expensive-and-requiring-physical-presence way to extract the key from the smart card) but only with regards to the safety of the private key itself. However, there is usually nothing that could stop the attacker from requesting the smart card to perform decryption of all the user documents the attacker has found or need to decrypt. In other words, while protecting the users private key is an important task, we should not forget that ultimately it is the user data that are to be protected and that the smart card chip has no way of knowing the requests to decrypt documents are now coming from the attackers script and not from the user sitting in front of the monitor. (Similarly the smart card doesnt make the process of digitally signing a document or a transaction in any way more secure the user cannot know what the chip is really signing. Unfortunately this problem of signing reliability is not solvable by Split GPG.)
With Qubes Split GPG this problem is drastically minimized, because each time the key is to be used the user is asked for consent (with a definable time out, 5 minutes by default), plus is always notified each time the key is used via a tray notification from the domain where GPG backend is running. This way it would be easy to spot unexpected requests to decrypt documents.
|r2-split-gpg-1.png| |r2-split-gpg-3.png|
Configuring Split GPG
---------------------
In dom0, make sure the ``qubes-gpg-split-dom0`` package is installed.
.. code:: bash
[user@dom0 ~]$ sudo qubes-dom0-update qubes-gpg-split-dom0
Make sure you have the ``qubes-gpg-split`` package installed in the template you will use for the GPG domain.
For Debian or Whonix:
.. code:: bash
[user@debian-10 ~]$ sudo apt install qubes-gpg-split
For Fedora:
.. code:: bash
[user@fedora-32 ~]$ sudo dnf install qubes-gpg-split
Setting up the GPG backend domain
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
First, create a dedicated app qube for storing your keys (we will be calling it the GPG backend domain). It is recommended that this domain be network disconnected (set its netvm to ``none``) and only used for this one purpose. In later examples this app qube is named ``work-gpg``, but of course it might have any other name.
Make sure that gpg is installed there. At this stage you can add the private keys you want to store there, or you can now set up Split GPG and add the keys later. To check which private keys are in your GPG keyring, use:
.. code:: bash
[user@work-gpg ~]$ gpg -K
/home/user/.gnupg/secring.gpg
-----------------------------
sec 4096R/3F48CB21 2012-11-15
uid Qubes OS Security Team <security@qubes-os.org>
ssb 4096R/30498E2A 2012-11-15
(...)
This is pretty much all that is required. However, you might want to modify the default timeout: this tells the backend for how long the users approval for key access should be valid. (The default is 5 minutes.) You can change this via the ``QUBES_GPG_AUTOACCEPT`` environment variable. You can override it e.g. in ``~/.profile``:
.. code:: bash
[user@work-gpg ~]$ echo "export QUBES_GPG_AUTOACCEPT=86400" >> ~/.profile
Please note that previously, this parameter was set in ~/.bash_profile. This will no longer work. If you have the parameter set in ~/.bash_profile you *must* update your configuration.
Please be aware of the caveat regarding passphrase-protected keys in the `Current limitations <#current-limitations>`__ section.
Configuring the client apps to use Split GPG backend
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Normally it should be enough to set the ``QUBES_GPG_DOMAIN`` to the GPG backend domain name and use ``qubes-gpg-client`` in place of ``gpg``, e.g.:
.. code:: bash
[user@work-email ~]$ export QUBES_GPG_DOMAIN=work-gpg
[user@work-email ~]$ gpg -K
[user@work-email ~]$ qubes-gpg-client -K
/home/user/.gnupg/secring.gpg
-----------------------------
sec 4096R/3F48CB21 2012-11-15
uid Qubes OS Security Team <security@qubes-os.org>
ssb 4096R/30498E2A 2012-11-15
(...)
[user@work-email ~]$ qubes-gpg-client secret_message.txt.asc
(...)
Note that running normal ``gpg -K`` in the demo above shows no private keys stored in this app qube.
A note on ``gpg`` and ``gpg2``:
Throughout this guide, we refer to ``gpg``, but note that Split GPG uses ``gpg2`` under the hood for compatibility with programs like Enigmail (which now supports only ``gpg2``). If you encounter trouble while trying to set up Split GPG, make sure youre using ``gpg2`` for your configuration and testing, since keyring data may differ between the two installations.
Advanced Configuration
^^^^^^^^^^^^^^^^^^^^^^
The ``qubes-gpg-client-wrapper`` script sets the ``QUBES_GPG_DOMAIN`` variable automatically based on the content of the file ``/rw/config/gpg-split-domain``, which should be set to the name of the GPG backend VM. This file survives the app qube reboot, of course.
.. code:: bash
[user@work-email ~]$ sudo bash
[root@work-email ~]$ echo "work-gpg" > /rw/config/gpg-split-domain
Split GPGs default qrexec policy requires the user to enter the name of the app qube containing GPG keys on each invocation. To improve usability for applications like Thunderbird with Enigmail, in ``dom0`` place the following line at the top of the file ``/etc/qubes-rpc/policy/qubes.Gpg``:
.. code:: bash
work-email work-gpg allow
where ``work-email`` is the Thunderbird + Enigmail app qube and ``work-gpg`` contains your GPG keys.
You may also edit the qrexec policy file for Split GPG in order to tell Qubes your default gpg vm (qrexec prompts will appear with the gpg vm preselected as the target, instead of the user needing to type a name in manually). To do this, append ``default_target=<vmname>`` to ``ask`` in ``/etc/qubes-rpc/policy/qubes.Gpg``. For the examples given on this page:
.. code:: bash
@anyvm @anyvm ask default_target=work-gpg
Note that, because this makes it easier to accept Split GPGs qrexec authorization prompts, it may decrease security if the user is not careful in reviewing presented prompts. This may also be inadvisable if there are multiple app qubes with Split GPG set up.
Using Thunderbird
-----------------
Thunderbird 78 and higher
^^^^^^^^^^^^^^^^^^^^^^^^^
Starting with version 78, Thunderbird has a built-in PGP feature and no longer requires the Enigmail extension. For users coming from the Enigmail extension, the built-in functionality is more limited currently, including that **public keys must live in your** ``work-email`` **qube with Thunderbird rather than your offline** ``work-gpg`` **qube**.
In ``work-email``, use the Thunderbird config editor (found at the bottom of preferences/options), and search for ``mail.openpgp.allow_external_gnupg``. Switch the value to true. Still in config editor, search for ``mail.openpgp.alternative_gpg_path``. Set its value to ``/usr/bin/qubes-gpg-client-wrapper``. Restart Thunderbird after this change.
|tb78-1.png| |tb78-2.png| |tb78-3.png|
You need to obtain your key ID which should be **exactly 16 characters**. Enter the command ``qubes-gpg-client-wrapper -K --keyid-format long``:
.. code:: bash
[user@work-email ~]$ qubes-gpg-client-wrapper -K --keyid-format long
/home/user/.gnupg/pubring.kbx
-----------------------------
sec rsa2048/777402E6D301615C 2020-09-05 [SC] [expires: 2022-09-05]
F7D2D4E922DFB7B2589AF3E9777402E6D301615C
uid [ultimate] Qubes test <user@localhost>
ssb rsa2048/370CE932085BA13B 2020-09-05 [E] [expires: 2022-09-05]
.. code:: bash
[user@work-email ~]$ qubes-gpg-client-wrapper --armor --export 777402E6D301615C > 777402E6D301615C.asc
Open the Account Settings and open the *End-to-End Encryption* tab of the respective email account. Click the *Add Key* button. Youll be offered the choice *Use your external key through GnuPG*. Select it and click Continue.
|tb78-4.png| |tb78-5.png|
The key ID reference you would need here is ``777402E6D301615C``. Now paste or type the ID of the secret key that you would like to use. Be careful to enter it correctly, because your input isnt verified. Confirm to save this key ID. Now you can select the key ID to use.
|tb78-6.png| |tb78-7.png|
This key ID will be used to digitally sign or send an encrypted message with your account. For this to work, Thunderbird needs a copy of your public key. At this time, Thunderbird doesnt fetch the public key from ``/usr/bin/qubes-gpg-client-wrapper``, you must manually import it. Export the key as follow (assuming the key ID would be ``777402E6D301615C``):
|tb78-8.png| |tb78-9.png|
Use Thunderbirds Tools menu to open *OpenPGP Key Management*. In that window, use the File menu to access the *Import Public Key(s) From File* command. Open the file with your public key. After the import was successful, right click on the imported key in the list and select *Key Properties*. You must mark your own key as *Yes, Ive verified in person this key has the correct fingerprint*.
Once this is done, you should be able to send an encrypted and signed email by selecting *Require Encryption* or *Digitally Sign This Message* in the compose menu *Options* or *Security* toolbar button. You can try it by sending an email to yourself.
|tb78-10.png|
For more details about using smart cards/Split GPG with Thunderbird PGP feature, please see `Thunderbird:OpenPGP:Smartcards <https://wiki.mozilla.org/Thunderbird:OpenPGP:Smartcards>`__ from which the above documentation is inspired.
Older Thunderbird versions
^^^^^^^^^^^^^^^^^^^^^^^^^^
For Thunderbird versions below 78, the traditional Enigmail + Split GPG setup is required. It is recommended to set up and use ``/usr/bin/qubes-gpg-client-wrapper``, as discussed above, in Thunderbird through the Enigmail addon.
**Warning:** Before adding any account, configuring Enigmail with ``/usr/bin/qubes-gpg-client-wrapper`` is **required**. By default, Enigmail will generate a default GPG key in ``work-email`` associated with the newly created Thunderbird account. Generally, it corresponds to the email used in ``work-gpg`` associated to your private key. In consequence, a new, separate private key will be stored in ``work-email`` but it *does not* correspond to your private key in ``work-gpg``. Comparing the ``fingerprint`` or ``expiration date`` will show that they are not the same private key. In order to prevent Enigmail using this default generated local key in ``work-email``, you can safely remove it.
On a fresh Enigmail install, your need to change the default ``Enigmail Junior Mode``. Go to Thunderbird preferences and then privacy tab. Select ``Force using S/MIME and Enigmail``. Then, in the preferences of Enigmail, make it point to ``/usr/bin/qubes-gpg-client-wrapper`` instead of the standard GnuPG binary:
|tb-enigmail-split-gpg-settings-2.png|
Using Keybase with Split GPG
----------------------------
Keybase, a security focused messaging and file-sharing app with GPG integration, can be configured to use Split GPG.
The Keybase service does not preserve/pass the ``QUBES_GPG_DOMAIN`` environment variable through to underlying GPG processes, so it **must** be configured to use ``/usr/bin/qubes-gpg-client-wrapper`` (as discussed above) rather than ``/usr/bin/qubes-gpg-client``.
The following command will configure Keybase to use ``/usr/bin/qubes-gpg-client-wrapper`` instead of its built-in GPG client:
.. code:: bash
$ keybase config set gpg.command /usr/bin/qubes-gpg-client-wrapper
Now that Keybase is configured to use ``qubes-gpg-client-wrapper``, you will be able to use ``keybase pgp select`` to choose a GPG key from your backend GPG app qube and link that key to your Keybase identity.
Using Git with Split GPG
------------------------
Git can be configured to utilize Split GPG, something useful if you would like to contribute to the Qubes OS Project as every commit is required to be signed. The most basic ``~/.gitconfig`` file enabling Split GPG looks something like this.
.. code:: bash
[user]
name = <YOUR_NAME>
email = <YOUR_EMAIL_ADDRESS>
signingKey = <YOUR_KEY_ID>
[gpg]
program = qubes-gpg-client-wrapper
Your key id is the public id of your signing key, which can be found by running ``qubes-gpg-client --list-keys``. In this instance, the key id is E142F75A6B1B610E0E8F874FB45589245791CACB.
.. code:: bash
[user@work-email ~]$ qubes-gpg-client --list-keys
/home/user/.gnupg/pubring.kbx
-----------------------------
pub ed25519 2022-08-16 [C]
E142F75A6B1B610E0E8F874FB45589245791CACB
uid [ultimate] Qubes User <user@example.com>
sub ed25519 2022-08-16 [S]
sub cv25519 2022-08-16 [E]
sub ed25519 2022-08-16 [A]
To sign commits, you now add the “-S” flag to your commit command, which should prompt for Split GPG usage. If you would like to automatically sign all commits, you can add the following snippet to ``~/.gitconfig``.
.. code:: bash
[commit]
gpgSign = true
Lastly, if you would like to add aliases to sign and verify tags using the conventions the Qubes OS Project recommends, refer to the :ref:`code signing documentation <developer/code/code-signing:using pgp with git>`.
Importing public keys
---------------------
Use ``qubes-gpg-import-key`` in the client app qube to import the key into the GPG backend VM.
.. code:: bash
[user@work-email ~]$ export QUBES_GPG_DOMAIN=work-gpg
[user@work-email ~]$ qubes-gpg-import-key ~/Downloads/marmarek.asc
A safe, unspoofable user consent dialog box is displayed.
|r2-split-gpg-5.png|
Selecting “Yes to All” will add a line in the corresponding :doc:`RPC Policy </user/advanced-topics/rpc-policy>` file.
Advanced: Using Split GPG with Subkeys
--------------------------------------
Users with particularly high security requirements may wish to use Split GPG with `subkeys <https://wiki.debian.org/Subkeys>`__. However, this setup comes at a significant cost: It will be impossible to sign other peoples keys with the master secret key without breaking this security model. Nonetheless, if signing others keys is not required, then Split GPG with subkeys offers unparalleled security for ones master secret key.
Setup Description
^^^^^^^^^^^^^^^^^
In this example, the following keys are stored in the following locations (see below for definitions of these terms):
.. list-table::
:widths: 10 10
:align: center
:header-rows: 1
* - PGP Key(s)
- VM Name
* - ``sec``
- ``vault``
* - ``ssb``
- ``work-gpg``
* - ``pub``
- ``work-email``
- ``sec`` (master secret key)
- Depending on your needs, you may wish to create this as a **certify-only (C)** key, i.e., a key which is capable only of signing (a.k.a., “certifying”) other keys. This key may be created *without* an expiration date. This is for two reasons. First, the master secret key is never to leave the ``vault`` VM, so it is extremely unlikely ever to be obtained by an adversary (see below). Second, an adversary who *does* manage to obtain the master secret key either possesses the passphrase to unlock the key (if one is used) or does not. An adversary who *does* possess the passphrase can simply use it to legally extend the expiration date of the key (or remove it entirely). An adversary who does *not* possess the passphrase cannot use the key at all. In either case, an expiration date provides no additional benefit.
- By the same token, however, having a passphrase on the key is of little value. An adversary who is capable of stealing the key from your ``vault`` would almost certainly also be capable of stealing the passphrase as you enter it. An adversary who obtains the passphrase can then use it in order to change or remove the passphrase from the key. Therefore, using a passphrase at all should be considered optional. It is, however, recommended that a **revocation certificate** be created and safely stored in multiple locations so that the master keypair can be revoked in the (exceedingly unlikely) event that it is ever compromised.
- ``ssb`` (secret subkey)
- Depending on your needs, you may wish to create two different subkeys: one for **signing (S)** and one for **encryption (E)**. You may also wish to give these subkeys reasonable expiration dates (e.g., one year). Once these keys expire, it is up to you whether to *renew* these keys by extending the expiration dates or to create *new* subkeys when the existing set expires.
- On the one hand, an adversary who obtains any existing encryption subkey (for example) will be able to use it in order to decrypt all emails (for example) which were encrypted to that subkey. If the same subkey were to continue to be usedand its expiration date continually extendedonly that one key would need to be stolen (e.g., as a result of the ``work-gpg`` VM being compromised; see below) in order to decrypt *all* of the users emails. If, on the other hand, each encryption subkey is used for at most approximately one year, then an adversary who obtains the secret subkey will be capable of decrypting at most approximately one years worth of emails.
- On the other hand, creating a new signing subkey each year without renewing (i.e., extending the expiration dates of) existing signing subkeys would mean that all of your old signatures would eventually read as “EXPIRED” whenever someone attempts to verify them. This can be problematic, since there is no consensus on how expired signatures should be handled. Generally, digital signatures are intended to last forever, so this is a strong reason against regularly retiring ones signing subkeys.
- ``pub`` (public key)
- This is the complement of the master secret key. It can be uploaded to keyservers (or otherwise publicly distributed) and may be signed by others.
- ``vault``
- This is a network-isolated VM. The initial master keypair and subkeys are generated in this VM. The master secret key *never* leaves this VM under *any* circumstances. No files or text is *ever* :ref:`copied <user/how-to-guides/how-to-copy-and-move-files:security>` or :ref:`pasted <user/how-to-guides/how-to-copy-and-paste-text:security>` into this VM under *any* circumstances.
- ``work-gpg``
- This is a network-isolated VM. This VM is used *only* as the GPG backend for ``work-email``. The secret subkeys (but *not* the master secret key) are :ref:`copied <user/how-to-guides/how-to-copy-and-move-files:security>` from the ``vault`` VM to this VM. Files from less trusted VMs are *never* :ref:`copied <user/how-to-guides/how-to-copy-and-move-files:security>` into this VM under *any* circumstances.
- ``work-email``
- This VM has access to the mail server. It accesses the ``work-gpg`` VM via the Split GPG protocol. The public key may be stored in this VM so that it can be attached to emails and for other such purposes.
Security Benefits
^^^^^^^^^^^^^^^^^
In the standard Split GPG setup, there are at least two ways in which the ``work-gpg`` VM might be compromised. First, an attacker who is capable of exploiting a hypothetical bug in ``work-email``s `MUA <https://en.wikipedia.org/wiki/Mail_user_agent>`__ could gain control of the ``work-email`` VM and send a malformed request which exploits a hypothetical bug in the GPG backend (running in the ``work-gpg`` VM), giving the attacker control of the ``work-gpg`` VM. Second, a malicious public key file which is imported into the ``work-gpg`` VM might exploit a hypothetical bug in the GPG backend which is running there, again giving the attacker control of the ``work-gpg`` VM. In either case, such an attacker might then be able to leak both the master secret key and its passphrase (if any is used, it would regularly be input in the work-gpg VM and therefore easily obtained by an attacker who controls this VM) back to the ``work-email`` VM or to another VM (e.g., the ``netvm``, which is always untrusted by default) via the Split GPG protocol or other :doc:`covert channels </user/security-in-qubes/data-leaks>`. Once the master secret key is in the ``work-email`` VM, the attacker could simply email it to himself (or to the world).
In the alternative setup described in this section (i.e., the subkey setup), even an attacker who manages to gain access to the ``work-gpg`` VM will not be able to obtain the users master secret key since it is simply not there. Rather, the master secret key remains in the ``vault`` VM, which is extremely unlikely to be compromised, since nothing is ever copied or transferred into it. [1]_ The attacker might nonetheless be able to leak the secret subkeys from the ``work-gpg`` VM in the manner described above, but even if this is successful, the secure master secret key can simply be used to revoke the compromised subkeys and to issue new subkeys in their place. (This is significantly less devastating than having to create a new *master* keypair.)
Subkey Tutorials and Discussions
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
(**Note:** Although the tutorials below were not written with Qubes Split GPG in mind, they can be adapted with a few commonsense adjustments. As always, exercise caution and use your good judgment.)
- `“OpenPGP in Qubes OS” on the qubes-users mailing list <https://groups.google.com/d/topic/qubes-users/Kwfuern-R2U/discussion>`__
- `“Creating the Perfect GPG Keypair” by Alex Cabal <https://alexcabal.com/creating-the-perfect-gpg-keypair/>`__
- `“GPG Offline Master Key w/ smartcard” maintained by Abel Luck <https://gist.github.com/abeluck/3383449>`__
- `“Using GnuPG with QubesOS” by Alex <https://apapadop.wordpress.com/2013/08/21/using-gnupg-with-qubesos/>`__
Current limitations
-------------------
- Current implementation requires importing of public keys to the vault domain. This opens up an avenue to attack the gpg running in the backend domain via a hypothetical bug in public key importing code. See ticket `#474 <https://github.com/QubesOS/qubes-issues/issues/474>`__ for more details and plans how to get around this problem, as well as the section on `using Split GPG with subkeys <#advanced-using-split-gpg-with-subkeys>`__.
- It doesnt solve the problem of allowing the user to know what is to be signed before the operation gets approved. Perhaps the GPG backend domain could start a disposable and have the to-be-signed document displayed there? To Be Determined.
- The Split GPG client will fail to sign or encrypt if the private key in the GnuPG backend is protected by a passphrase. It will give an ``Inappropriate ioctl for device`` error. Do not set passphrases for the private keys in the GPG backend domain. Doing so wont provide any extra security anyway, as explained in the introduction and in `using Split GPG with subkeys <#advanced-using-split-gpg-with-subkeys>`__. If you are generating a new key pair, or if you have a private key that already has a passphrase, you can use ``gpg2 --edit-key <key_id>`` then ``passwd`` to set an empty passphrase. Note that ``pinentry`` might show an error when you try to set an empty passphrase, but it will still make the change. (See `this StackExchange answer <https://unix.stackexchange.com/a/379373>`__ for more information.) **Note:** The error shows only if you **do not** have graphical pinentry installed.
.. [1]
In order to gain access to the ``vault`` VM, the attacker would require the use of, e.g., a general Xen VM escape exploit or a :ref:`signed, compromised package which is already installed in the template <user/templates/templates:trusting your templates>` upon which the ``vault`` VM is based.
.. |split-gpg-diagram.png| image:: /attachment/doc/split-gpg-diagram.png
.. |r2-split-gpg-1.png| image:: /attachment/doc/r2-split-gpg-1.png
.. |r2-split-gpg-3.png| image:: /attachment/doc/r2-split-gpg-3.png
.. |tb78-1.png| image:: /attachment/doc/tb78-1.png
.. |tb78-2.png| image:: /attachment/doc/tb78-2.png
.. |tb78-3.png| image:: /attachment/doc/tb78-3.png
.. |tb78-4.png| image:: /attachment/doc/tb78-4.png
.. |tb78-5.png| image:: /attachment/doc/tb78-5.png
.. |tb78-6.png| image:: /attachment/doc/tb78-6.png
.. |tb78-7.png| image:: /attachment/doc/tb78-7.png
.. |tb78-8.png| image:: /attachment/doc/tb78-8.png
.. |tb78-9.png| image:: /attachment/doc/tb78-9.png
.. |tb78-10.png| image:: /attachment/doc/tb78-10.png
.. |tb-enigmail-split-gpg-settings-2.png| image:: /attachment/doc/tb-enigmail-split-gpg-settings-2.png
.. |r2-split-gpg-5.png| image:: /attachment/doc/r2-split-gpg-5.png

View file

@ -1,91 +0,0 @@
---
lang: en
layout: doc
permalink: /doc/vm-sudo/
redirect_from:
- /en/doc/vm-sudo/
- /doc/VMSudo/
- /wiki/VMSudo/
ref: 165
title: Passwordless root access in qubes
---
The background to passswordless root access is summarised in this statement, that used to be found at `/etc/sudoers.d/qubes` in each qube:
```
user ALL=(ALL) NOPASSWD: ALL
# WTF?! Have you lost your mind?!
#
# In Qubes VMs there is no point in isolating the root account from
# the user account. This is because all the user data is already
# accessible from the user account, so there is no direct benefit for
# the attacker if she could escalate to root (there is even no benefit
# in trying to install some persistent rootkits, as the VM's root
# filesystem modifications are lost upon each start of a VM).
#
# One might argue that some hypothetical attacks against the
# hypervisor or the few daemons/backends in Dom0 (so VM escape
# attacks) most likely would require root access in the VM to trigger
# the attack.
#
# That's true, but mere existence of such a bug in the hypervisor or
# Dom0 that could be exploited by a malicious VM, no matter whether
# requiring user, root, or even kernel access in the VM, would be
# FATAL. In such situation (if there was such a bug in Xen) there
# really is no comforting that: "oh, but the mitigating factor was
# that the attacker needed root in VM!" We're not M$, and we're not
# gonna BS our users that there are mitigating factors in that case,
# and for sure, root/user isolation is not a mitigating factor.
#
# Because, really, if somebody could find and exploit a bug in the Xen
# hypervisor -- as of 2016, there have been only three publicly disclosed
# exploitable bugs in the Xen hypervisor from a VM -- then it would be
# highly unlikely if that person couldn't also found a user-to-root
# escalation in VM (which as we know from history of UNIX/Linux
# happens all the time).
#
# At the same time allowing for easy user-to-root escalation in a VM
# is simply convenient for users, especially for update installation.
#
# Currently this still doesn't work as expected, because some idotic
# piece of software called PolKit uses own set of policies. We're
# planning to address this in Beta 2. (Why PolKit is an idiocy? Do a
# simple experiment: start 'xinput test' in one xterm, running as
# user, then open some app that uses PolKit and asks for root
# password, e.g. gpk-update-viewer -- observe how all the keystrokes
# with root password you enter into the "secure" PolKit dialog box can
# be seen by the xinput program...)
#
# joanna.
```
The core of this statement continues to reflect the views of the Qubes developers.
Passwordless root is provided by the `qubes-core-agent-passwordless-root` package.
Details of the implementation are [here](/doc/vm-sudo-implementation).
[Minimal templates](/doc/templates/minimal/), which are intended for use by advanced users, do not have this package installed by default.
Replacing passwordless root access
----------------------------------
Some users may wish to modify their system by enabling user/root isolation in qubes.
We do not support this in any packages, but users are free to remove the qubes-core-agent-passwordless-root package if they wish, using standard packaging tools.
Root access can then be gained from dom0 by (e.g) `qvm-run -u root QUBE qubes-run-terminal`, or `qvm-console-dispvm QUBE`.
Replacing passwordless root access with Dom0 user prompt
--------------------------------------------------------
An alternative approach is to enable user/root isolation by using a dom0 generated prompt.
A list of steps to do so is provided in the [Qubes community guide, Replacing passwordless root with a dom0 prompt](https://forum.qubes-os.org/t/replacing-passwordless-root-with-a-dom0-prompt/19074) **without any guarantee of safety, accuracy, or completeness.
Proceed at your own risk.
Do not rely on this for extra security.**
Dom0 passwordless root access
-----------------------------
There is also passwordless user->root access in dom0.
As stated in the comment in `/etc/sudoers.d/qubes` there is really no point in user/root isolation in dom0, because all user data (and the whole Qubes management interface) is already accessible to the user, so there is nothing more to be gained from the dom0 root account.

View file

@ -0,0 +1,90 @@
=================================
Passwordless root access in qubes
=================================
The background to passswordless root access is summarised in this statement, that used to be found at ``/etc/sudoers.d/qubes`` in each qube:
.. code:: bash
user ALL=(ALL) NOPASSWD: ALL
# WTF?! Have you lost your mind?!
#
# In Qubes VMs there is no point in isolating the root account from
# the user account. This is because all the user data is already
# accessible from the user account, so there is no direct benefit for
# the attacker if she could escalate to root (there is even no benefit
# in trying to install some persistent rootkits, as the VM's root
# filesystem modifications are lost upon each start of a VM).
#
# One might argue that some hypothetical attacks against the
# hypervisor or the few daemons/backends in Dom0 (so VM escape
# attacks) most likely would require root access in the VM to trigger
# the attack.
#
# That's true, but mere existence of such a bug in the hypervisor or
# Dom0 that could be exploited by a malicious VM, no matter whether
# requiring user, root, or even kernel access in the VM, would be
# FATAL. In such situation (if there was such a bug in Xen) there
# really is no comforting that: "oh, but the mitigating factor was
# that the attacker needed root in VM!" We're not M$, and we're not
# gonna BS our users that there are mitigating factors in that case,
# and for sure, root/user isolation is not a mitigating factor.
#
# Because, really, if somebody could find and exploit a bug in the Xen
# hypervisor -- as of 2016, there have been only three publicly disclosed
# exploitable bugs in the Xen hypervisor from a VM -- then it would be
# highly unlikely if that person couldn't also found a user-to-root
# escalation in VM (which as we know from history of UNIX/Linux
# happens all the time).
#
# At the same time allowing for easy user-to-root escalation in a VM
# is simply convenient for users, especially for update installation.
#
# Currently this still doesn't work as expected, because some idotic
# piece of software called PolKit uses own set of policies. We're
# planning to address this in Beta 2. (Why PolKit is an idiocy? Do a
# simple experiment: start 'xinput test' in one xterm, running as
# user, then open some app that uses PolKit and asks for root
# password, e.g. gpk-update-viewer -- observe how all the keystrokes
# with root password you enter into the "secure" PolKit dialog box can
# be seen by the xinput program...)
#
# joanna.
The core of this statement continues to reflect the views of the Qubes developers.
Passwordless root is provided by the ``qubes-core-agent-passwordless-root`` package.
Details of the implementation are :doc:`here </developer/system/vm-sudo>`.
:doc:`Minimal templates </user/templates/minimal-templates>`, which are intended for use by advanced users, do not have this package installed by default.
Replacing passwordless root access
----------------------------------
Some users may wish to modify their system by enabling user/root isolation in qubes.
We do not support this in any packages, but users are free to remove the qubes-core-agent-passwordless-root package if they wish, using standard packaging tools.
Root access can then be gained from dom0 by (e.g) ``qvm-run -u root QUBE qubes-run-terminal``, or ``qvm-console-dispvm QUBE``.
Replacing passwordless root access with Dom0 user prompt
--------------------------------------------------------
An alternative approach is to enable user/root isolation by using a dom0 generated prompt.
A list of steps to do so is provided in the `Qubes community guide, Replacing passwordless root with a dom0 prompt <https://forum.qubes-os.org/t/replacing-passwordless-root-with-a-dom0-prompt/19074>`__ **without any guarantee of safety, accuracy, or completeness. Proceed at your own risk. Do not rely on this for extra security.**
Dom0 passwordless root access
-----------------------------
There is also passwordless user->root access in dom0.
As stated in the comment in ``/etc/sudoers.d/qubes`` there is really no point in user/root isolation in dom0, because all user data (and the whole Qubes management interface) is already accessible to the user, so there is nothing more to be gained from the dom0 root account.