passage.el builds on top of age.el to provide Emacs support for passage which is an Age encryption based port of pass, the standard unix password manager.
Put the passage.el
project in your load-path
and:
(require 'passage)
You can now interact with your passage based local encryption store. Please see the passage README for instructions on how to migrate from the gpg based pass utility to the age based passage utility.
passage.el assumes your passage store is located at ~/.passage/store
but you
may customize this through the auth-source-passage-filename
variable.
passage.el includes an auth-source
back-end for passage, which means you can
programmatically fetch passwords out of your passage store with
auth-source-passage-get
, e.g.:
(auth-source-passage-get 'secret "store/secret")
#! /usr/bin/env bash
set -eou pipefail
cd "${PASSWORD_STORE_DIR:-$HOME/.password-store}"
while read -r -d "" passfile; do
name="${passfile#./}"; name="${name%.gpg}"
[[ -f "${PASSAGE_DIR:-$HOME/.passage/store}/$name.age" ]] && continue
pass "$name" | passage insert -m "$name" || { passage rm "$name"; break; }
done < <(find . -path '*/.git' -prune -o -iname '*.gpg' -print0)
For pinentry support I recommend you use rage as your age encryption utility.
If your emacs configuration moves around a variety of systems that all share
the same passage store, but you do not want to keep the same key material on
all those systems, you can encrypt to a series of recipients via newline
seperated public keys at ~/.passage/store/.age-recipients
If you’d like to specify a specific identity (private key) for passage.el to use on password show operations, you can use the normal environment variables recognized by passage for this in your configuration, e.g.:
(setenv "PASSAGE_IDENTITIES_FILE" (expand-file-name "~/path/to/identity"))
This is useful to deconflict e.g. age-plugin-yubikey
managed identities
contained in the default passage identity file at ~/.passage/identities
for
which the yubikeys may not be plugged into the system you are currently
working with.
Note that for file open operations, you’ll want to use age.el in conjuction with passage.el, which has its own identity and recipient configuration settings. For example, on one of my virtual machines, I use an alternate identity, who’s recipient is included in the passage.el and age.el configurations on all my system, and specify to only use this identity for age.el and passage.el, respectively, on the virtual machin using the following configuration:
(setq age-default-identity (expand-file-name "~/.ssh/age_yubikey_vm"))
(setenv "PASSAGE_IDENTITIES_FILE" age-default-identity)
The passage author has a nice walkthrough of their personal, non-emacs based, passage configuration and future plans for the project here:
https://words.filippo.io/dispatches/passage/
I have not tested passage with the OTP plugins. Ostensibly the regular pass plugins should work relatively unchanged but this is conjecture at this point.
GPLv3
This code was ported from the original password-store Emacs support libraries and its authors are:
- Damien Cassou <damien@cassou.me>
- Nicolas Petton <nicolas@petton.fr>
- Keith Amidon <camalot@picnicpark.org>
- Daniel Barreto
- Svend Sorensen <svend@svends.net>
Their original copyright assignments apply as this code is mostly a search and replace port of their work.