This commit is contained in:
parent
b3a5af5182
commit
ab33b9a1c1
1 changed files with 416 additions and 0 deletions
|
@ -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 ->
|
||||||
|
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 {#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
|
Loading…
Add table
Reference in a new issue