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