diff --git a/content/posts/20250628T131556--consolidating-secrets-in-pass__emacs_linux_security.md b/content/posts/20250628T131556--consolidating-secrets-in-pass__emacs_linux_security.md new file mode 100644 index 0000000..50751bd --- /dev/null +++ b/content/posts/20250628T131556--consolidating-secrets-in-pass__emacs_linux_security.md @@ -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 +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 {#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