Consolidating Secrets in Pass

Background
Like a lot of people I've had a long history managing passwords and secrets over the years. From a little black book, over an Excel sheet, using a GPG encoded secrets file (works really well with Emacs gpg support), 1password (till they racked up their prices), lastpass (till they got bought by the Evil LogMeIn Corp), KeepassXC and lately pass.
I was perfectly happy with KeepassXC for a very long time, except for the command line integration. So I kept ending up with passwords in .envrc files in folders and excluded in the global .gitignore to avoid too many red cheeks. While this does keep secrets out of harms way mostly, it kept nagging that I had them in plain text in those files. In theory there is keepassxc-cli to query the passwords from the command line, but let's say the experience does not spark joy. It has no easy way to cache the password between calls and it is optimized for interactive use. (AFAICT, just the giant size of the command to type gives me dread).
Some day I stumbled over pass and found that after setup I could just
pass snamellit/website
to get the password on stdout. I wrote about
the setup and emacs integration in a previous post. Since it
leverage gpg, password caching is handled by the gpg-agent and my
.envrc files quickly were purged of blasphemous secrets, replace by
pure bliss:
export MY_SECRET=$(pass my/secret)
export OTHER_SECRET=$(pass other/secret)
similarly in emacs I can consistently get my passwords and related info with:
(org-gcal-client-id (auth-source-pass-get 'secret "snamellit/org-gcal-client"))
(org-gcal-client-secret (auth-source-pass-get "id"
"snamellit/org-gcal-client"))
When needed the gpg-agent will launch the appropriate pin-entry program whether in terminal or in the GUI and the caching will not force me to login several times when entering the folder.
So I ended up with my interactive use covered by KeepassXC and automated use by pass.
However, after some time I ended up with hundreds of secrets in KeepassXC, hundreds in pass, it is not always clear whether use is interactive or automated so confusion and duplication starts and things become harder to manage. In addition KeepassXC was using historically Dropbox to make it available on all my devices, recently migrated to Nextcloud, which has issues with dealing with conflicts which occasionally bite me in the behind. On the other hand pass secrets are stored encrypted in git where conflict punch you in the face. I prefer the latter. And started contemplating whether to move everything to pass.
Thanks to the encouragement of SummerEmacs, one of the more enthusiastic SystemCrafters, ensuring the great experience in browsers and iOS mobile devices I had no more excuses to keep postponing it.
Preparation
I started out with keeping my pass passwords as part of my dotfiles. This was convenient when they were few. However this is weird so this will attract weirdness when configuring all integrations I'll need.
Also pass supports a git command to manage the password-store with git which is not really useful when it is part of something else. So the first order of the day is to move all secrets to a separate repository and update the dotfiles to check for presence and clone the repo if missing (and do a gently pull when it is). A quick visit to each of the machines in my machine park to apply this change. Everything still seems to be working.
Migration of the KeepassXC data
I used the pass-import tool which adds in import command to pass which
supports a crazy amount of password managers, including keepassxc. For
keepassxc it need the pykeepass. If you're running on Arch, everything
is a yay -S
away. However on Ubuntu and its derivatives it is the
usual slog we start to get accustomed to. It's all in the pass-import
README , note that on Ubunty the pykeepass library is available with
apt install python3-pykeepass
.
Once it is installed I tried a dry run (with the -d
flag) to see if
basic functionality is working
pass import -a -d keepassxc ~/Nextcloud/Apps/Keepassxc/Passwords.kdbx
Password for /home/pti/Nextcloud/Apps/Keepassxc/Passwords.kdbx:
w Data would be imported from keepassxc to pass
. Passwords imported from: /home/pti/Nextcloud/Apps/Keepassxc/Passwords.kdbx
. Passwords exported to: /home/pti/.password-store
. Number of password imported: 2035
. All data imported
w Weak password detected: eDGQqipE might be weak. Score 2 (100000001 guesses). This estimate is based on the sequence eDGQqipE(bruteforce)
w Weak password detected: eDGQqipE might be weak. Score 2 (100000001 guesses). This estimate is based on the sequence eDGQqipE(bruteforce)
w Weak password detected: eDGQqipE might be weak. Score 2 (100000001 guesses). This estimate is based on the sequence eDGQqipE(bruteforce)
... large list of names of secrets
This asks for the password of the Keepass file and some remarks it has.
This all looks reasonable. So we can try the import. Since the password-store is a git repo no real damage can be done to it (as it is safely pushed somewhere else where the import tool cannot touch it) and any damage done can be reverted....
Now is a good time to check if the mooring lines of your laptop are properly secured as encrypting all the secrets will spin up the propellors if the number is large enough.
I run it again without the -d
flag and after several minutes the
noise dies down and I am left with a lot of additional folders in my
~/.password-store
which match the grouping in KeepassXC. The files
contain the secrets and the expected metadata. This looks good so I
add/commit the things to complete the level.
Integration with iOS for my iPhone
Let's start with the most scary one : the iPhone.
Upon recommendation I had installed passforios which needs to be configured.
Configuring the host, repo and username to use for the git repository is straightforward enough.
I always use ssh to access my repos so we need to add an ssh keypair
for this purpose. There is no support to generate key-pairs in
passforios for reasons, so I have to do it externally and upload the
key. A quick ssh-keygen
, uploading the public key to the forge,
allowing access to the repo and if I can get the private key on my
phone we can access the repo.
passforios has a nice feature to load ascii armored keys via a QR code. A bit digging surfaced the asc-key-to-qr-code-gif tool which was made for this specific purpose. The ssh key is already in the appropriate format so this can be directly converted
./asc-to-gif.sh ~/.ssh/id-passforios ssh-pub.gif
display ssh-pub.gif
Then go to the repository settings, press the circled i on the SSH Key button, select the ASCII-Armor Key and click to scan the QR code. Point the camera to the QR code on the screen and it should appear in the key field in the app.
We have to repeat this 2 more times to get the private and public key for the password-store into the app. First exporting the keys
gpg --export -a 1234ABCD >gpg.pub
gpg --export-secret-key -a 1234ABCD >gpg.key
converting to a gif, displaying them and scanning them in *Settings -> PGP Key -> ASCII-Armor Key in the respective fields.
If, after synching, you go now to the Passwords you should be greeted with a listing of all folders and keys and the secrets should be visible if made visible by tapping the eye icon.
I needed to enable passforios as a source for autofill : Settings -> Passwords -> Autofill Passwords and slide the toggle for Pass. I also disabled the toggle for Strongbox which I was using for integration with the Keepass database.
Now I see the option to select the secrets from the passforios app. It does not narrow down to the right key, but that is a problem for future me.
Ok, the hard part is done. Or at least the most risky part, ... in my eyes... whatever. Moving on...
Integration with FireFox
Checking at the bottom of the pass website we find that passff is the good stuff for integration with FireFox. From previous adventures with KeepassXC and NativeMessaging I assumed there had to be a host part to be installed too.
Indeed we are directed to the passff-host github repo to get an install-script which generates the native messaging json for the different browsers and a small executable python script which contains remarkable clean and no-dependency code. Similarly the install script is straightforward. I do not understand why it support half a dozen browser, mostly chrome based as for the life of me I cannot find an extension which uses this host program. So either I need bigger glasses or there is some knowledge beyond my grasp.
Running the installer, installing the extension, restarting firefox for good luck and the extension appears and offers passwords on the sites I try.
Out of curiosity I check the configuration in ~.mozilla/native-messaging :
pti@tuxedo ~> ls .mozilla/native-messaging-hosts/
org.keepassxc.keepassxc_browser.json passff.json passff.py*
pti@tuxedo ~> cat .mozilla/native-messaging-hosts/passff.json
{
"name": "passff",
"description": "Host for communicating with zx2c4 pass",
"path": "/home/pti/.mozilla/native-messaging-hosts/passff.py",
"type": "stdio",
"allowed_extensions": [ "passff@invicem.pro" ]
}
pti@tuxedo ~> cat .mozilla/native-messaging-hosts/passff.py
#!/usr/bin/python3
"""
Host application of the browser extension PassFF
that wraps around the zx2c4 pass script.
"""
import json
...
Nothing out of the ordinary, the passff.py python is the same as in the repo. My old keepassxc extension support is still there.
Firefox is installed natively on this machine, not with a flatpak which I assume will come with its own challenges.
Chromium Support
Time to tackle the Chrome family. Chrome is required to put food on the table so we have to get that going eventually. But Chrome is distributed as a flatpak (or a snap but I am NOT going to deal with that), and I can install Chromium natively, and apparently native installs are MUCH better supported than the versions in wrappers so let's start with that one first.
From the pass website we find that browserpass is the way to go for the chrome family. The browser extension installs from the usual places without drama and starts promptly complaining it cannot find the native host to talk to.
The native host in question is from the browsaerpass-native sister repo . As usual for all distro's there are packages ready to install but because Ubuntu-derivative I can compile from source. Downloading the source for version 3.1.0 from the releases page. Again this repo refers to all browsers including firefox although I cannot for the life of me find a Firefox Extension supporting this host app.
Then building and installing timelapse :
tar -xzvf ~/Downloads/browserpass-native-3.1.0.tar.gz
cd browserpass-native-3.1.0
ls
less README.md
PREFIX=/usr/local make configure
sudo make PREFIX=/usr/local install
which browserpass
which shows the executable lives at /usr/local/bin/browserpass
and
this totally went fine the first time (NOT!!!!).
The Makefile
has support to install the magic json to enable native
messaging for the different browsers.
PREFIX=/usr/local make hosts-chromium-user
PREFIX=/usr/local make hosts-chrome-user
The second invocation is a hail-mary because I already know the Chrome flatpak does not look in the same places and will require some additional finnagling
For now focus on Chromium and check if the configuration looks reasonable:
pti@tuxedo ~> cd .config/chromium/NativeMessagingHosts/
pti@tuxedo ~/.c/c/NativeMessagingHosts> ls
com.github.browserpass.native.json@
pti@tuxedo ~/.c/c/NativeMessagingHosts> cat com.github.browserpass.native.json
{
"name": "com.github.browserpass.native",
"description": "Browserpass native component for the Chromium extension",
"path": "/usr/local/bin/browserpass",
"type": "stdio",
"allowed_origins": [
"chrome-extension://naepdomgkenhinolocfifgehidddafch/",
"chrome-extension://pjmbgaakjkbhpopmakjoedenlfdmcdgm/",
"chrome-extension://klfoddkbhleoaabpmiigbmpbjfljimgb/"
]
}
Cool, the executable is looked at where it is installed (this is not obvious, don't ask how I know). The rest looks also like how these things should look. Let's try...
The extension settings page is no longer complaining the native host is missing and there are password entries visible. Checking with some website shows the password is injected. yay!.
Level complete, ready for the final boss.
Enabling Chrome Support, now with more Flatpak!
Ok, we have a working chromium support so repo access, host app, native host configuration et al are proven working. We can only focus on jumping over the Flatpak Firewall...
As a good cargo cultist I do a literature study and find that I should
-
find the config location of the flatpak app
-
use
flatpak-spawn
to spawn the native messaging host app -
enable D-Bus Session socket access for chrome
-
Package up the calling of the host app in a single script to configure in the json.
Not necessarily in that order....
For the permission to access D-Bus Session start up flatseal from flathub, navigate to com.google.Chrome and enable the D-Bus Session socket. This should be possible with some additional cursing in the manifest file of Chrome. I cannot find decent reference documentation in a reasonable time, so flatseal it is.
The configuration of the flatpak app is easy too, painful experience seared in my brain that flatpaks look in ~/.var/app/ folder so for Chrome this will be ~/.var/app/com.google.Chrome . From the hail-mary install for chrome done above I know that it just creates a symbolic link to /usr/local/lib/browserpass/hosts/chromium/com.github.browserpass.native so we can start from there. We will have to edit that so copy it. We also need a wrapper to call the native host app
cd ~/.var/app/com.google.Chrome/config/google-chrome/NativeMessagingHosts
cp /usr/local/lib/browserpass/hosts/chromium/com.github.browserpass.native
ec browserpass.sh
Add the content of the wrapper
#!/bin/sh
cd ~
/usr/bin/flatpak-spawn --host /usr/local/bin/browserpass 2>/tmp/browserpass-error.log
I added the optional redirect of stderr to an error logfile because from experience I know nothing ever goes wrong if you enable error reporting beforehand.
chmod +x browserpass.sh
pwd
pwd | wl-copy
ec com.github.browserpass.native.json
Installing the browserpass extension in Chrome after restarting it (I am not superstitious, just careful) and I can bask in the glory of seeing proposals for passwords when trying to log in. Most of the proposals are pretty garbage, but that is a problem for future me.
Conclusion
I have access to my password-store secrets on my phone, my browsers on laptop and desktop, and most importantly Emacs. Narrowing of the proposed secrets is, euhmmm, sub-optimal, but since it is sub-optimal in the same way on all platforms I assume that some TLC in the password-store and cleaning of the migrated secrets will fix that in time.
In the process I gained much more confidence in configuring flatpak apps. I can decommission the keepassxc system including dealing with the sync conflicts (which was admittedly super easy with the merge database feature in KeepassXC). I no longer have to deal with giving the KeepassXC window a place on the desktop and autostarting it.
I am a bit puzzled about the host-apps referring to supporting browsers for which no extensions are available. This probably might warrant some additional investigation.
Big step forward