Using Unix pass in Qubes OS

Table of Contents

1. Introduction

The Unix program pass is my password manager of choice. It keeps your passwords as gpg-encrypted files in the directory ~/.password-store. There also exists a dmenu script called passmenu that can be bound to a keybinding to easily access your passwords. To get this to work in Qubes OS, you need to put in some work. In this blog post, I share the qrexec service I'm using for this purpose.

2. Architecture

+-----------------+                   +-----------+
| vault-passwords |<----split gpg---->| vault-gpg |
+-----------------+                   +-----------+
	| passmenu qrexec
  | browser |

Above, the qubes and their communication channels used for passmenu under Qubes OS are shown. The qube vault-password contains the gpg-encrypted passwords in ~/.password-store. The qube vault-gpg contains the private PGP key needed to decrypt the passwords. They are set up using Qubes' split gpg feature so that vault-passwords can decrypt the gpg files without having access to the private key itself. Both qubes are set up without internet access.

Then, we have some qube that needs access to the passwords. It might be connected to the internet, which is why we don't want to store our passwords directly in that qube. In this example, I have called this Qube browser. This blog post will describe how the vault-passwords qube can send passwords to the browser qube.

3. Usage

The password access must always come from vault-passwords. We can not allow the browser qube to request passwords from vault-passwords and then have vault-passwords return them, because that could allow a malicious browser qube to potentially request arbitrary passwords.

Instead, using the qrexec service described here works as follows:

  1. Open a browser window in your browser qube and click into the login form's password field
  2. Press Super+p, which has a keybinding in dom0 to open the passmenu script in vault-passwords
  3. Qrexec will ask you which qube you want to send the password to. In our example, enter browser here and confirm
  4. Now, passmenu opens. Type the name of your desired password into passmenu (e.g. "websites/google.com") and confirm by pressing Enter
  5. vault-passwords now sends the password to the browser qube over qrexec
  6. The browser qube automatically enters the received password into the login form's password field using xdotool

4. Prerequisites

In vault-passwords, you need to put modified versions of pass and passmenu into the home directory and ensure they are executable. The scripts are modified as follows:

For pass, replace the lines

which gpg2 &>/dev/null && gpg="gpg2"


which gpg2 &>/dev/null && gpg="/usr/bin/qubes-gpg-client-wrapper"

This makes sure that pass uses our split gpg setup to decrypt the password files. I will not go into how to setup split gpg in this blog post. Confirm the modified script and your split gpg setup are working by executing

$ ./pass your/password

and observing whether the password is successfully shown.

For passmenu, replace the following

if [[ $typeit -eq 0 ]]; then
	pass show -c "$password" 2>/dev/null
	pass show "$password" | { IFS= read -r pass; printf %s "$pass"; } | $xdotool


~/pass show "$password" | {IFS= read -r pass; printf %s "$pass"; }

This makes sure passmenu uses our modified version of pass and that it neither copies the password to the clipboard nor types it, but instead outputs it to stdout. This is necessary so that the password can be sent over qrexec to the browser qube.

5. The qrexec service

In vault-passwords, create ~/qubes-passmenu-sender with the following contents and make it executable.

xterm -e "echo 'Passmenu started...'; sh" &
kill $childpid

This script is basically just supposed to start your modified passmenu script. However, there is the problem that passmenu doesn't grab the focus of your keyboard under Qubes unless you are inside a window of vault-passwords. I've used the hacky solution of starting XTerm to let that grab the focus for passmenu. It's not pretty, but it works.

In the template qube for browser, create /etc/qubes-rpc/qubes.Passmenu with the following contents and make it executable. Also, make sure that xdotool is installed in the template.


read pass
sleep 0.5  # Wait for vault-passwords window to close
xdotool type "$pass"

Finally, create /etc/qubes-rpc/policy/qubes.Passmenu with the following contents:

vault-passwords @anyvm ask
@anyvm @anyvm deny

With this setup, vault-passwords can send passwords to any desired qube and you have to enter the destination qube when starting the qrexec service. Another policy might be more useful to you. For example, you could set

vault-passwords browser allow
@anyvm @anyvm deny

if you always use the same browser qube and want to specify that as the destination qube when configuring the keybinding.

After completing the steps above, confirm the qrexec service is working by running

$ qrexec-client-vm browser qubes.Passmenu ~/qubes-passmenu-sender

in vault-passwords. It should then work as specified in the section Usage.

6. Keybinding

All that is missing now is to set a keybinding in dom0. Head into the keyboard settings and add a keybinding (I use Super+p) for the command

qvm-run vault-passwords qrexec-client-vm default qubes.Passmenu \

7. Final words

I hope this post has been useful. If you happen to find a less hacky solution to let passmenu grab focus, please contact me at keno@goertz-berlin.com.