add consolidating secrets in pass post
Some checks failed
/ build (push) Failing after 1m0s

This commit is contained in:
Peter Tillemans 2025-06-28 17:36:36 +02:00
parent b3a5af5182
commit ab33b9a1c1

View file

@ -0,0 +1,416 @@
+++
title = "Consolidating Secrets in Pass"
author = ["Peter Tillemans"]
date = 2025-06-28T13:15:00+02:00
tags = ["emacs", "linux", "security"]
categories = ["shell", "apps"]
draft = false
[taxonomies]
tags = ["emacs", "linux", "security"]
categories = ["shell", "apps"]
+++
## Background {#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](https://passwordstore.org).
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](https://www.snamellit.com/blog/20240624t104859-secrets-management-using-unix-password-store-pass-linux-osx-sysadmin/). 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:
```shell
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:
```elisp
(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 {#preparation}
I started out with keeping my pass passwords as part of my
dotfiles. This was convenient when they were few. However this is
<span class="underline">weird</span> so this will attract <span class="underline">weirdness</span> 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 {#migration-of-the-keepassxc-data}
I used the [pass-import](https://github.com/roddhjav/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](https://github.com/roddhjav/pass-import) , 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
```shell
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 {#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](https://github.com/yishilin14/asc-key-to-qr-code-gif) which
was made for this specific purpose. The ssh key is already in the
appropriate format so this can be directly converted
```shell
./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
```shell
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 -&gt;
PGP Key -&gt; 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 -&gt;
Passwords -&gt; 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 {#integration-with-firefox}
Checking at the bottom of the [pass website](https://www.passwordstore.org/) 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](https://codeberg.org/PassFF/passff-host) 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 :
```shell
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 {#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](https://www.passwordstore.org/) we find that **[browserpass](https://github.com/browserpass/browserpass-extension)** 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](https://github.com/browserpass/browserpass-native) . 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](https://github.com/browserpass/browserpass-native/releases). 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 :
```shell
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.
```shell
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:
```shell
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! {#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
```shell
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
```shell
#!/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.
```shell
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 {#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