We have talked about wrapping AutoFirma into its own VM to prevent it from modifying the host’s keychain and to keep it properly packaged and configured. I liked the approach and I have recently extended it to a few more things: I now use WhatsApp and Signal in single-app VMs in ChromeOS. Through this setup I’ll be able to access those services as long as I have one of my hardware keys and a recent-enough VM backup.

When I started playing around with the idea, I wanted to achieve the equivalent of passkey-based logins to services and apps that don’t natively support passkeys. Both WhatsApp and Signal, for instance, require scanning a QR code with the corresponding mobile app to link a desktop client. I wanted something different: to be able to leave my main devices behind and still be able to access those services. I wanted to authenticate through a Yubikey and to securely get online even from a device that had just been wiped.

The solution I came up with builds on ChromeOS VMs and Yubikeys:

  • Through nixos-crostini, I can easily configure and build multiple flavors of NixOS VMs that run on the Chromebook through Baguette.
  • Two of the VM flavors that I prepared run a Firefox browser (for WhatsApp Web) and the Signal desktop app. Each VM builds on a base configuration that is moderately hardened and turns off as many services as possible. The VM is configured to boot from an immutable filesystem: writes go to ephemeral storage, except for state that needs to survive reboots.
  • ChromeOS provides the trusted computing base. It can run VMs out of the box and provides a generally secure environment in its default configuration. My threat model generally trusts ChromeOS; it assumes that an individual VM can be compromised, but that an attacker inside the VM wouldn’t be able to reach the host.
  • I configure one VM per service in ChromeOS. I launch each and perform the initial configuration by linking its client to the corresponding mobile app.
  • Then I export the whole VM disk (usually small, around 1 GB) and I make sure that the backup destination isn’t shared with any other VM. I use age-browser to encrypt it using one or more Yubikeys.
  • I then upload the encrypted backup somewhere where I can authenticate with a Yubikey passkey (e.g., Google Drive) and destroy the ChromeOS VM and its local backups.

When I need one of these services, I authenticate to the drive through the Yubikey, pull the backup, decrypt it through the browser, and restore the VM. I recently tested this process while on a business trip and was pretty happy with it.

A few caveats: I suspect that neither Signal nor WhatsApp would support copies of the same client running at the same time; I haven’t tried that. In addition, device “links” expire after being inactive for a while. This means that the VM backup needs to be prepared close enough to when it will be needed. On the other hand, it means that encrypted backups forgotten on the drive would not be useful to reconnect to the services after some time; I think that’s a nice thing.

Somewhat cheekily, I think of this setup as a poor man’s Qubes OS. The resulting security posture is weaker, for instance because firewalls run inside each VM and clipboard and file sharing can weaken isolation. On the other hand, it relies on mainstream technologies and is convenient to both set up and use. Chromebooks are also both cheap and easily available: as long as I can access a Chromebook and one of my Yubikeys, I’ll be able to get back online.