Building Qubes

Published on November 21st, 2017

I'm working with the Freedom of the Press Foundation these days, migrating the journalist interface of SecureDrop away from a processes involving mutiple laptops running tails to a single machine running Qubes. It's been exciting work, especially since Qubes is in the middle of releasing a new major version, which we've decided we want to target.

In its prerelease state, Qubes 4 has been a little shaky. We've been exercising some of its new features pretty hard and have stumbled over some bugs in the process (all of which the Qubes folks have been very responsive in addressing). I'd love to understand some of the Qubes internals a bit better so I can submit PRs instead of just bug reports. Marek gave me some pointers about how to get started, and I'm going to try to document my (sure-to-be-stumbling) process and discoveries here.

I'm working on a machine that's up-to-date with the Qubes 4.0 testing repos as of today (November 21, 2017).

Installing qubes-builder

The Qubes development workflow documentation (which I'll be following closely) indicates the first step is installing qubes-builder. Let's give it a shot. This is going to crib from both the Qubes document and the Arch document.

Build a devel VM

I'll be building qubes-builder in a new, standalone qubes-devel VM based on the Fedora-25 template. Use the GUI or cli to create that VM, and be sure to give it plenty of private disk space (the Qubes docs recommend at least 25GB). In its settings window, add at least a terminal to its list of applications.

Open a terminal and install your favorite editor. Edit /etc/yum.repos.d/qubes-r4.repo to ensure enabled is set under [qubes-vm-r4.0-current-testing]. Bring your VM up to date with all the fresh new code with:

$ sudo dnf update

Install depdendencies

Install the qubes-builder build dependencies with

$ sudo dnf install git createrepo rpm-build make wget rpmdevtools python-sh dialog rpm-sign gnupg

Do some crypto

Configure GPG to use the sks keyservers, and fetch the Qubes master key:

$ mkdir certs ; cd certs
$ curl -O ; cd ~

You may want to verify the sks pool's cert. Compare the output of

$ openssl x509 -noout -in ~/certs/sks-keyservers.netCA.pem -fingerprint -sha1

with the fingerprint published at If they match, get the Qubes master key:

$ printf "keyserver hkps://\nkeyserver-options ca-cert-file=/home/user/certs/sks-keyservers.netCA.pem" > ~/.gnupg/gpg.conf
$ gpg --recv-keys 0x427F11FD0FAA4B080123F01CDDFA1A3E36879494

Then configure GPG to set that key as ultimately trusted, so it can be used to verify all the keys it signs. This is described at, and outlined below. In particular, verify that the fingerprint you see matches the one displayed below (and confirm against the fingerprints shown in the link above).

$ gpg --edit-key 0x36879494
gpg (GnuPG) 1.4.18; Copyright (C) 2014 Free Software Foundation, Inc.
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.

pub  4096R/36879494  created: 2010-04-01  expires: never       usage: SC
                     trust: unknown       validity: unknown
[ unknown] (1). Qubes Master Signing Key

gpg> fpr
pub   4096R/36879494 2010-04-01 Qubes Master Signing Key
 Primary key fingerprint: 427F 11FD 0FAA 4B08 0123  F01C DDFA 1A3E 3687 9494

gpg> trust
pub  4096R/36879494  created: 2010-04-01  expires: never       usage: SC
                     trust: unknown       validity: unknown
[ unknown] (1). Qubes Master Signing Key

Please decide how far you trust this user to correctly verify other users' keys
(by looking at passports, checking fingerprints from different sources, etc.)

  1 = I don't know or won't say
  2 = I do NOT trust
  3 = I trust marginally
  4 = I trust fully
  5 = I trust ultimately
  m = back to the main menu

Your decision? 5
Do you really want to set this key to ultimate trust? (y/N) y

pub  4096R/36879494  created: 2010-04-01  expires: never       usage: SC
                     trust: ultimate      validity: unknown
[ unknown] (1). Qubes Master Signing Key
Please note that the shown key validity is not necessarily correct
unless you restart the program.

gpg> q

Finally, let's import the Qubes developers' keys.

$ curl -O
$ gpg --import qubes-developers-keys.asc

Running gpg --list-keys should now show a number of public keys.

Install the qubes-builder code

Now we can install the qubes-builder code with confidence. Let's first get the code. I generally do development from my ~/projects/ directory, so you may need to adjust for taste.

$ mkdir ~/projects ; cd ~/projects
$ git clone git:// qubes-builder

Copy your gpg keyring into the repo:

$ mkdir -p ~/projects/qubes-builder/keyrings/git
$ cp .gnupg/pubring.gpg ~/projects/qubes-builder/keyrings/git/
$ cp .gnupg/trustdb.gpg ~/projects/qubes-builder/keyrings/git/

Finally, verify the integrity of the downloaded repository. The last line should read gpg: Good signature from...

$ cd ~/projects/qubes-builder
$ git tag -v `git describe`

Configure the builder

In the root of the project, run setup.

$ cd ~/projects/qubes-builder
$ ./setup

This will start a nice console progam. On the first screen ("Choose Which Qubes Release..."), choose "Qubes Release 4.0". On the next screen, choose "Stable". On the third screen, choose "No" (in order to do a complete build).

On the "Builder Plugins Selection" page, choose the default builder-fedora and mgmt-salt selections. On the "Distribution" page, unselect options until only the fc25 option is selected.

Fetch the source for everything

When the setup script is done, do make install-deps. This'll be pretty quick.


$ make get-sources

This'll take a while.


The source code for the entire universe has been checked out in qubes-builder/qubes-src. Go there and make all the bugfixes and magical features you can.


The Makefile in the root of a project is ... comprehensive. It's able to build everything from a single project to a full iso- try make help for the full rundown. In my current case, I'm going to be working in a single component (core-agent-linux), so I was hopeful that simply running make core-agent-linux would work, but sadly it fails.

It turns out that (unsurprisingly) components depend on each other and there's an order in which they should be built. Reading this configuration file shows us that order. So, makeing each component in turn until you've made the one you're working on seems like a fine way to proceed. Of course, subsequent builds of the component you're working on won't require rebuilding dependencies.

So, in my case, I run make for each of these components in turn: vmm-xen, core-libvert, core-vchan-xen, core-qubesdb, linux-utils, core-admin, core-admin-client, core-admin-linux, and finally core-agent-linux.

Once the core-admin-linux component is built, new rpms are left in qubes-src/core-agent-linux/pkgs/fc25/x86_64/. In my case I'll copy those to a new template VM where I'm testing my new agent code.

❤️ Me on Twitter, Me on Mastodon ❤️