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 v +---------+ | 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:
- Open a browser window in your
browser
qube and click into the login form's password field - Press
Super+p
, which has a keybinding indom0
to open the passmenu script invault-passwords
- Qrexec will ask you which qube you want to send the password to. In our
example, enter
browser
here and confirm - Now, passmenu opens. Type the name of your desired password into passmenu (e.g. "websites/google.com") and confirm by pressing Enter
vault-passwords
now sends the password to thebrowser
qube over qrexec- The
browser
qube automatically enters the received password into the login form's password field usingxdotool
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
gpg="gpg" ... which gpg2 &>/dev/null && gpg="gpg2"
with
gpg="/usr/bin/qubes-gpg-client-wrapper" ... 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 else pass show "$password" | { IFS= read -r pass; printf %s "$pass"; } | $xdotool fi
with
~/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.
#!/bin/sh xterm -e "echo 'Passmenu started...'; sh" & childpid=$! ~/passmenu 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.
#!/bin/sh 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 \ ~/qubes-passmenu-sender
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.