Tails can be built in a virtual machine that is managed using Vagrant and vagrant-libvirt. Here lies more details on how Tails uses Vagrant, its configuration, and how to create and upload the template virtual machine.

Configuration

Vagrant support files are located in the vagrant directory at the root of the amnesia.git repository.

This directory contains:

  • Vagrantfile: configuration file for Vagrant,
  • provision/setup-tails-builder: idempotent provisioning script that is run inside the virtual machine upon boot,
  • provision/assets/build-tails: build script to be run inside the virtual machine,
  • to build the base box:
    • definitions/tails-builder/generate-tails-builder-box.sh: Script that generates the base box.
    • definitions/tails-builder/postinstall.sh: Script that is run inside the base box before finalizing it, e.g. for installing the packages we need.
    • vagrant/lib/tails_build_settings.rb defines the basebox properties (memory, Debian version, architecture, ...) and the basebox name.

We choose to use the Shell provisioner, as long as we make this script reentrant it will lower the learning curve for contributors not familiar with Puppet or Chef.

The Tails Vagrantfile is configured to share the local clone of the Tails repository inside the running basebox through a 9pfs mount.

Automated basebox creation

While implementing reproducible builds of Tails, we choose to automate the basebox creation. Rather than downloading a big binary, everyone building Tails for the first time will start by generating the approriate basebox if it's not already available locally.

To ensure that the baseboxes are identical enough, we defined a mechanism for its generation:

To freeze the build environment, we use APT snapshots in the same way we do in the Tails build system, by storing the serials for the various APT repositories in vagrant/definitions/tails-builder/config/APT snapshots.d/.

Only the debian-security APT source uses Debian's APT repository, so that we get security fixes. This will probably not influence the reproducibility of the ISO. This is done in the Vagrant provisioning script.

To ensure that changes in the Vagrant build system are still taken into account when using a basebox, we dynamically set the name of the basebox by including the short ID of the last commit in the vagrant directory in the related branch, as well as its date, in the name of the basebox. That's done with vagrant/lib/tails build settings.rb as explained above.

We update the basebox APT snapshots serials at every Tails release.

A new VM is created from the basebox for each build. After the build, the VM is destroyed (#11980 and #11981).

The keeprunning build option can be used so that the VM is kept running and reused for subsequent builds of the same branch.

The VM encodes (in /var/lib/vagrant_box_build_from) the branch for which it has been started for. The ISO build aborts if the branch being built is not the same as the one that is encoded in this file. This prevents the reuse of a running VM to build another branch than the one it has been started for initially.

To ensure that the apt-cacher-ng cache is not lost when the VM is destroyed, it is stored in a dedicated virtual disk, and plugged into every new build VM.

Jenkins

All these features and the basic ones are used by our Jenkins ISO builders. See here for specifics.