Skip to content

Latest commit

 

History

11 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

* passage.el: age encryption support for the standard unix password manager

#+html:<p align="center"><img src="img/passage.png"/></p>

passage.el builds on top of [[https://github.com/anticomputer/age.el][age.el]] to provide Emacs support for [[https://github.com/FiloSottile/passage][passage]] which
is an Age encryption based port of [[https://www.passwordstore.org/][pass]], the standard unix password manager.

* Usage

Put the ~passage.el~ project in your ~load-path~ and:

#+begin_src emacs-lisp
(require 'passage)
#+end_src

You can now interact with your [[https://github.com/FiloSottile/passage][passage]] based local encryption store. Please
see the [[https://github.com/FiloSottile/passage/blob/main/README][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.

* Tips and Tricks

** Using passage store secrets in your elisp code

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.:

#+begin_src emacs-lisp
(auth-source-passage-get 'secret "store/secret")
#+end_src

** Pass to passage migration

#+begin_src bash
#! /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)
#+end_src

** Pinentry support

For pinentry support I recommend you use [[https://github.com/str4d/rage/][rage]] as your age encryption utility.

** Specifying alternate passage identities and recipients across systems

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.:

#+begin_src emacs-lisp
(setenv "PASSAGE_IDENTITIES_FILE" (expand-file-name "~/path/to/identity"))
#+end_src

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 [[https://github.com/anticomputer/age.el][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 machine using the following
configuration:

#+begin_src emacs-lisp
(setq age-default-identity (expand-file-name "~/.ssh/age_yubikey_vm"))
(setenv "PASSAGE_IDENTITIES_FILE" age-default-identity)
#+end_src

As of #4 passage.el will
automagically set ~age-default-identity~ and ~age-default-recipient~ from
~PASSAGE_IDENTITIES_FILE~, ~PASSAGE_RECIPIENTS_FILE~ or ~PASSAGE_RECIPIENTS~
environment variables for passage.el based `find-file` operations. When
you open a file from the passage store any existing passage environment
configuration will supercede your Emacs-wide age.el configuration. This
simplifies your use of passage.el without needing to manually deconflict
or align age.el configurations with your passage configuration.

It is important to understand that passage is its own tool with its own
configuration. It only, and ONLY, depends on age.el for operating on its
associated Age files inside Emacs buffers.

This behavior is backwards compatible with prior passage.el configurations
and was added for users who might have entirely different Age identities
and recipients for their Emacs-wide Age files vs their passage store Age
files. If these environment variables are not set, passage.el will fall back
to using the global age.el identity and recipient configuration for its
file open and save operations.

For details on proper passage configuration please see its documentation at:
https://github.com/FiloSottile/passage

TL;DR: if passage works for you on the normal cli, it should now also work
inside passage.el without having to worry about your age.el configuration,
by default.

** Other passage use cases

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/

* Known Issues

** OTP plugin support is untested

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.

* License

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.

About

Emacs support for passage: an age encryption based port of the standard unix password manager

Resources

Stars

22 stars

Watchers

3 watching

Forks

Releases

Packages

Used by

Contributors

Languages