Customize a named disposable using the vm-config feature

Intro

This is a technique for automatically passing custom information to named disposables as they boot up. Our example case will be making a disposable sys-net remember your wifi password, but the same technique can be used for disposable sys-net remembering your static IP address, or other information.

If you are unfamiliar with the “disposable sys-net needs wifi password each time system boots” issue, it’s this:

So lets say that during install, you saw the option for “make sys-net disposable”, thought it sounded good, but then later found out that every time you reboot sys-net that you either:

  • have to enter your wifi password in again (if you use wifi)
  • have to enter your static IP address in again (if you use static IP addresses)

Note: If you are only interested in getting your wireless password entered automatically on boot, and are ok with making a disposable template just for sys-net, then there is already a guide for doing that here: Disposable sys-net: Automatically connect wifi (config file or RPC service)

The technique:

This is a technique for fixing that. It’s actually a general solution that came from @marmarek that I thought could use more publicity. The key is how to hand off the information. For this you can use qvm-features with vm-config.* . The important part is that with qvm-features, you can just make up what you want to come after the vm-config. part!

So you can do like:
qvm-features sys-net vm-config.wifi-1-name NETGEAR1000
qvm-features sys-net vm-config.wifi-1-pass MyWIFIPassword

Then start a shell inside sys-net, and type:
qubesdb-read /vm-config/wifi-1-name
qubesdb-read /vm-config/wifi-1-pass

The official 3 sentances of documentation on this :slight_smile: can be found here: qvm-features – manage domain’s features — Qubes Admin client v4.3.17-0-g019c8aa documentation

Examples:

Example of using the technique to automatically give your wireless password to sys-net each time it starts:

GIven the commands demonstrating the technique shown above, you can make a /rw/config/rc.local file that includes something like:

#!/bin/bash
###Note: setting shell to /bin/bash as /bin/sh had strange results when evaluating conditions###

WIFI_1_NAME=`qubesdb-read /vm-config/wifi-1-name`
WIFI_1_PASS=`qubesdb-read /vm-config/wifi-1-pass`

echo hostname is $(hostname)

if [ $(hostname) = 'sys-net' ]; then
    echo "ok, we are on sys-net, check for the wifi password";
    if [[ `qubesdb-read /vm-config/wifi-1-pass  | wc --bytes` -gt 1 ]]; then
	echo "Found Wifi  password!  configuring now..."

	nmcli device wifi list 2>&1 | tee /tmp/debug.5.1
	date >> tee /tmp/debug.5.1-stamp
	nmcli device wifi scan 2>&1 | tee /tmp/debug.5.2
	date >> tee /tmp/debug.5.2-stamp
	nmcli device wifi rescan 2>&1 | tee /tmp/debug.5.3
	date >> tee /tmp/debug.5.3-stamp
        ###next, try to fix the race condition
	sleep 30;
	nmcli device wifi list 2>&1 | tee /tmp/debug.5.4
	date >> tee /tmp/debug.5.4-stamp
	
	nmcli device wifi connect "$WIFI_1_NAME" password "$WIFI_1_PASS"  | tee /tmp/debug.5.5;
    else
	echo "no password found... moving on"
    fi;
else
    echo "you are not on sys-net... moving on"
fi

(Note: there seems to be some kind of race condition with the above in that it works about 9 out of 10 times (the 30 second pause is attempting to fix that))

Of course, if we put that directly in sys-net, since sys-net is disposable, it’ll be gone next time sys-net reboots. Thus you need to edit the /rw/config/rc.local in the disposable template that sys-net uses. You can find which system this is with: qvm-prefs sys-net template

so with that in the rc.local of the template, and running the the 2 qvm-features sys-net {blah blah blah} commands in dom0, your 802.11 should become persistant.

Other example uses

Static IP address example

Similarly, you could create and set differnt vm-config.* parameters, then call nmcli with other options in the rc.local to configure a static IP address. Something like:
qvm-features sys-net vm-config.ip_address 192.168.0.127
qvm-features sys-net vm-config.gateway 192.168.0.1

with a: qubesdb-read /vm-config/ip_address and qubesdb-read /vm-config/gateway in the rc.local

Securedrop example:

Here is a presentation on how they used the technique in a real world example when developing securedrop!: https://www.youtube.com/watch?v=GIZTeJU0iBY
Higher fidelity copies of the slides are here: https://cfp.3mdeb.com/media/qubes-os-summit-2024/submissions/WDFJFY/resources/PUBLIC_Joys_and_Sorrows_of_Multi-VM_Ap_vP21ScR.pdf

4 Likes

Great tip. This sounds much more general than just WiFi.

Is it even possible to get a whole multi-line shell script into vm-features? We could customise rc.local from Dom0?

Looks like some overlap with the following:

1 Like

As @ephile said, it could be appropriate to move this guide along the methods listed in the other guide.

It’s an interesting solution. I’m not a bash expert but it would be great to support multiple entries (/vm-config.wifi-1-name, /vm-config.wifi-2-name, etc.) and check which one is available through nmcli device wifi list before connecting.

Could it be possible to store the password hashed with this setup?

wpa_passphrase from wpa_supplicant can generate the configuration for wpa_supplicant and will store the hashed version of the password.

1 Like

Yes, you are correct. It’s much more general then just wifi.

I have not tested it, but it would probably work for a “custom rc.local” command for disposables if you did this:
qvm-features sys-net vm-config.rclocal "echo 'rc.local is running stuff passed with the qvm-features command!!!' > /tmp/rclocal.message; echo 'who knows how many characters can be passed this way?' > /tmp/rclocal.message.2 "
then in rc.local of the disposable template do:

#!/bin/bash

RCLOCALCOMMANDS=`qubesdb-read /vm-config/rclocal`
echo "about to run: $RCLOCALCOMMANDS"
$RCLOCALCOMMANDS

Notes:

  • I have not tested the above
  • There is probably a limit to the number of characters you can pass through the qvm-features command, but i don’t know what it is
  • It would be up to you to think through if there were any security implications of doing that.
1 Like

Thanks. I edited and added a link to that.

2 Likes

This guide is more about the making the technique known then about wifi passwords (i did not know about the wifi password guide), but people are welcome to copy whatever portions of this that you want into the wifi password specific guide linked above as a second technique. People are also free to change the copy however they want.

(Note to future readers: I changed the title of this and the intro to this after he wrote this comment, so know that his comment was spot on at the time that he wrote it)

2 Likes

Yes, such a thing should be possible to do. It would just require figuring out what the sequence of nmcli device wifi {blah blah} commands would be.
my knowledge of nmcli is minimal.

Oh, if it’s not obvious, nmcli stands for “netmanager” which is the red networking icon you get in the system tray. So nmcli is the command line way of doing the same network configuration things you can do manually through that widget.

2 Likes

I am not sure. My knowledge of wifi (and nmcli) is fairly minimal.

I’m assuming that you are saying that there is a way to use a hash to authenticate with wifi instead of using the wifi password directly.

So the question would be if that can be done through the nmcli commands, which i do not know the answer to.

note that the nmcli command is the cli version of “netmanager” (which is the gui widget that is used to manually configure networking)

I feel like I may not have given a useful answer to you here, so feel to try again if so. :slight_smile:

Now this is new to me. I’ve been using tags, sometimes, to set things for a VM that weren’t defined keys. But that (as far as I knew) could only be used by dom0 as a way of taking notes; the VM can’t (as far as I know) determine what tags it has set. (I’ve also noticed that it can take almost a full second to set and remove tags–not bad when it’s once, but I have a situation where I delete one tag and add two in a Python script, and the multi-second delay is noticeable and annoying.)

It appeas that a VM can read its features via qubesdb-read; this may simplify things a lot for me (some of those tags I have been setting might be better replaced with features).

1 Like

https://dev.qubes-os.org/projects/core-admin-client/en/latest/manpages/qvm-features.html#vm-config

This is new to me too :slight_smile:

1 Like

Apparently this only works for vm-config.* features. But even so that’s new to me.

My earlier statement that I was using tags for bookkeeping was partially correct, I was indeed using features as well, and contrary to what I said people can name them anything (I didn’t think you could when I made my comment). (The ones I use to manage build processes are builds.; I may go see what I’m doing with those and decide I can better build some things from within the vm and use vm-config. instead.)

I had never seen that page btw, so thank you for that! (I think it should be alphabetized.)

1 Like

Thanks. Added link to the instructions above.

1 Like

I’m just curious about this: where did you get that from @marmarek in the first place?

And now your title is too long :slight_smile:

The title is a mouth full. However, I would save this guide.

Thanks for making this more visible, it is very nice. It’s actually something we’re using in the SecureDrop Workstation for on-boot configuration of various qubes (including disposables) also using qubes-services.

We mentioned this in our Qubes Summit 2024 presentation. It should also be up on youtube on the 3mdeb channel.

2 Likes

He casually mentioned it as a solution for a github issue, and when I finally figured out what he was saying to do, I’m like “Why does nobody know about this???”. lol

Wecome. I’m happy people are getting excited about it.

Neat! I didn’t know anyone was using it. I’ll add a link to your talk.

The title looks very familiar. I’m wondering if I saw this before I understood what qubesdb was. :slight_smile:

3 Likes