Giter VIP home page Giter VIP logo

passage's Introduction

passage
=======

passage is a fork of password-store (https://www.passwordstore.org) that uses
age (https://age-encryption.org) as a backend instead of GnuPG.

Differences from pass
---------------------

The password store is at $HOME/.passage/store by default.

For decryption, the age identities at $HOME/.passage/identities are used with
the -i age CLI option.

For encryption, the nearest .age-recipients file (that is, the one in the same
directory as the secret, or in the closest parent) is used with the -R age CLI
option. If no .age-recipients files are found, the identities file is used with
the -i option.

Extensions are searched at $HOME/.passage/extensions. password-store extensions
that wish to be compatible with passage can switch on the PASSAGE variable.

The init command is not currently available, and moving or copying a secret
always re-encrypts it.

Example: simple set up
----------------------

In this setup, the key is simply saved on disk, which can be useful if the
password store is synced to a location less trusted than the local disk.

    age-keygen >> $HOME/.passage/identities

Example: set up with a password-protected key
---------------------------------------------

This setup allows using the identity file password as the primary password
to unlock the store.

    KEY="$(age-keygen)"
    echo "$KEY" | age -p -a >> $HOME/.passage/identities
    echo "$KEY" | age-keygen -y >> $HOME/.passage/store/.age-recipients

Example: set up with age-plugin-yubikey
---------------------------------------

This setup requires age v1.1.0, or rage (https://github.com/str4d/rage), and
the PIV plugin age-plugin-yubikey (https://github.com/str4d/age-plugin-yubikey).

It's recommended to add more YubiKeys and/or age keys to the .age-recipients
file as recovery options, in case this YubiKey is lost.

    age-plugin-yubikey # run interactive setup
    age-plugin-yubikey --identity >> $HOME/.passage/identities
    age-plugin-yubikey --list >> $HOME/.passage/store/.age-recipients

Integrating with fzf
--------------------

The following script can be invoked with any (or no) passage flags, and
spawns a fuzzy search dialog using fzf (https://github.com/junegunn/fzf)
for selecting the secret.

    #! /usr/bin/env bash
    set -eou pipefail
    PREFIX="${PASSAGE_DIR:-$HOME/.passage/store}"
    FZF_DEFAULT_OPTS=""
    name="$(find "$PREFIX" -type f -name '*.age' | \
      sed -e "s|$PREFIX/||" -e 's|\.age$||' | \
      fzf --height 40% --reverse --no-multi)"
    passage "${@}" "$name"

Migrating from pass
-------------------

    #! /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)

Environment variables
---------------------

  PASSAGE_DIR               Password store location

  PASSAGE_IDENTITIES_FILE   Identities file location

  PASSAGE_AGE               age binary (tested with age and rage)

  PASSAGE_RECIPIENTS_FILE   Override recipients for encryption operations
                            Passed to age with -R

  PASSAGE_RECIPIENTS        Override recipients for encryption operations
                            Space separated, each passed to age with -r

All other environment variables from password-store are respected, such as
PASSWORD_STORE_CLIP_TIME and PASSWORD_STORE_GENERATED_LENGTH.

passage's People

Contributors

calancha avatar cdown avatar cfergeau avatar dmedvinsky avatar dobbyth33lf avatar drzraf avatar filosottile avatar glensc avatar iiska avatar kousu avatar krobelus avatar mendel avatar milki avatar nickzana avatar nicolaspetton avatar pbchase avatar phaza avatar phikal avatar phryneas avatar ptrv avatar remilapeyre avatar remko avatar richardtowers avatar smason avatar sommern avatar svend avatar tejr avatar von avatar zanchey avatar zx2c4 avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

passage's Issues

Best way to add a new yubikey to the store?

Now that age-plugin-yubikey supports multiple keys, what's the best way to add a new yubikey (for example, a backup) to the passage store? I added my new key to the existing identities and .age-recipients and then copied:

passage cp path/to/secret  new/path/to/secret

It's a bit cumbersome and sort of messes up the paths in the store. Is this the only option, or is there a better one I haven't considered?

@str4d

Using multiple identities with age-plugin-yubikey

I created a password with only one identity in my .passage/identities file. Then later I added a new identity to the same file. Both identities (and recipients in .passage/store/.age-recipients) were setup using age-plugin-yubikey.

Then I used passage cp to reencrypt the secret using the new age-recipients file. When I tried to decrypt the secret, age-plugin-yubikey prompted me for the yubikey that was first in the identifies file. I didn't see how to have it use the new yubikey who's recipient key was used to encrypt the secret.

Does passage + age-plugin-yubikey support multiple yubikeys? Apologies if this is more of a age-plugin-yubikey question.

cc: @str4d

Feature Request - ability to rekey all secrets

It would be great to have the option to easily rekey all secrets if there are changes to the recipients.

agenix which is a mechanism to deploy secrets to hosts that uses age has this option, which is very convenient.

There is no support for `pinentry`.

In pass, the gpg-agent manages the secret associated with the GPG key. This may be the PIN to access a YubiKey, or the passphrase to a password-protected GPG identity file.

On the other hand, passage prompts for the password to the age private key every time it is needed. This program should either hand-off the secret-gathering to another program (like an age-plugin-... or ssh-agent or something) or it should support the use of a chosen pinentry program.

Passage does not recognize git repository in `.passage` dir

Hello,

Many thanks for your work on age and passage. I recently switched to both from gpg and pass. Key management is much easier with age! :)

Instead of putting .passage/store/ into a git repository, I track the whole .passage dir (identities are stored on a yubikey). The git subcommand does not recognize that the passage dir is a repository.

I narrowed it down to line 33 in password-store.sh:

[[ $(git -C "$INNER_GIT_DIR" rev-parse --is-inside-work-tree 2>/dev/null) == true ]] || INNER_GIT_DIR=""

This test somehow fails (and resets the variable to "") even though executing this test manually results in the correct true result. I do not understand why this test does not detect correctly that the .passage dir is a git repository in the script but executing it manually gives the correct result.

The GIT_CEILING_DIRECTORIES seems to be correctly set to the home directory.

Can somebody help me out here?

Thanks for your help!

macOS/Homebrew installation fails

Because the repo does not yet have any tagged commits, the current instructions lead to an error though the rest of the steps continue.

fatal: No names found, cannot describe anything. # this is the error from git describe --tags
install: mkdir /usr/local/Cellar/passage
install: mkdir /usr/local/Cellar/passage//lib
install: mkdir /usr/local/Cellar/passage//lib/passage
install: src/platform/darwin.sh -> /usr/local/Cellar/passage//lib/passage/platform.sh
install: mkdir /usr/local/Cellar/passage//lib/passage/extensions
install: mkdir /usr/local/Cellar/passage//bin
install: src/.passage -> /usr/local/Cellar/passage//bin/passage

brew link passage doesn't work after that, presumably because brew expects installations to be in a tagged subfolder.

$ brew link passage
Linking /usr/local/Cellar/passage/lib... 0 symlinks created.

Running the commands with a manual tag works fine. E.g., make install PREFIX="$(brew --cellar)/passage/0.0.1"

No need to do anything since I'm assuming that this is still relatively alpha and you're not ready to tag anything yet. But I figured I would put this here for anyone else who has this problem.

feature request: expose reencrypt as a subcommand

When copying/moving to a new path passage will reencrypt.

Would be nice to expose a reencrypt in place subcommand that could be used to rotate the keys used for encryption (eg: in the case they are leaked.

Feature Request/Question - encrypt recipient file (part 2)

In the feature request #25 I suggested that it might be useful to store the recipient file encrypted on a shared storage as well, if you want to share the passwords with others and the shared storage is not trusted.

But every write operation would require decryption.

To avoid this the following idea might be useful:
A copy of the plaintext recipient file is stored locally (trusted storage) and the hash value of the encrypted recipient file. For each write operation the locally stored hash value is compared with the hash value of the encrypted recipient file stored on the shared storage. If they match, the locally stored plaintext recipient file can be used (this results in less costs than a decryption). If not, decryption must be performed.

zsh-specific code in "Migrating from pass" instructions

Sorry, but another little gotcha: the README's instructions to migrate from pass are zsh specific.

In particular, name="${${passfile#./}%.gpg}" doesn't work on bash. You need to do
that in two steps for bash.

Maybe just add that those instructions are an example for zsh users and that bash users
should edit accordingly?

For what it's worth, I used the following for bash:

set -o pipefail
cd "${PASSWORD_STORE_DIR:-$HOME/.password-store}" || exit
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)

Might be vulnerable to file rename attacks

This is very hypothetical, and only based on me reading the source code since I had a bit of trouble installing it.

But pass is vulnerable to file rename attacks, if an attacker have control over the encrypted files then he can copy one file into another, and cause the teams password for service A to be leaked to service B.

See CVE-2020-28086 ( https://blog.hackeriet.no/filename-rename-in-pass/ ) for my writeup on the issue.

It looks like there isn't any protection in passage for this type of attack either.

Sorry if I was wrong about this, just close this issue then :)

And this isn't really responsible disclosure, but i reckon that since this is so new there isn't any user impact to take into account.

Checking parent directories for .age-recipients file stops at $PREFIX

It seems that only the $PASSAGE_DIR folder is checked for the .age-recipients file. That, or I am misunderstanding the documentation:

For encryption, the nearest .age-recipients file (that is, the one in the same
directory as the secret, or in the closest parent) is used with the -R age CLI
option.

For the current version (set_age_recipients()):

local current="$PREFIX/$1"
#        should prevent traversal above $PREFIX
#        vvvvvvvvvvvvvvvvvvvvv
while [[ $current != "$PREFIX" && ! -f $current/.age-recipients ]]; do
        current="${current%/*}"
done
current="$current/.age-recipients"

Where PREFIX="${PASSAGE_DIR:-$HOME/.passage/store}", seems to prevent passage from traversing upwards. Removing the first condition leads the program to act as I would expect. There may be security implications to allowing an infinite upwards traversal in search for recipients, so the fix may be a documentation edit.

Additionally, there is no warning when the identity key fallback is used; this may lead to an unfortunate UX where additional recipients are not used to encrypt, and a "recovery" key would fail to recover the data.

Thank you for your work.

make install [with prefix] tries to read passage.sh that doesn't exist

Steps to reproduce:

[capitol@batia ~]$ cd /tmp/
[capitol@batia tmp]$ mkdir d
[capitol@batia tmp]$ cd d
[capitol@batia d]$ git clone [email protected]:FiloSottile/passage.git
Cloning into 'passage'...
remote: Enumerating objects: 2553, done.
remote: Counting objects: 100% (2553/2553), done.
remote: Compressing objects: 100% (1038/1038), done.
remote: Total 2553 (delta 1471), reused 2550 (delta 1468), pack-reused 0
Receiving objects: 100% (2553/2553), 395.23 KiB | 1.20 MiB/s, done.
Resolving deltas: 100% (1471/1471), done.
[capitol@batia d]$ cd passage/
[capitol@batia passage]$ mkdir /tmp/passage
[capitol@batia passage]$ LANG=C PREFIX=/tmp/passage make install
sed: can't read src/passage.sh: No such file or directory
make: *** [Makefile:52: install] Error 2

make install fails due to missing pass.fish-completion

Running make install errors with:

install: cannot stat 'src/completion/pass.fish-completion': No such file or directory

src/completion/pass.fish-completion was deleted in a previous commit. If dropping fish support was intentional, I think references to the completion need to be removed from the Makefile.

Completion files are not installed to Homebrew Cellar

$ make install PREFIX="$(brew --cellar)/passage/dev"
install: mkdir /opt/homebrew/Cellar/passage
install: mkdir /opt/homebrew/Cellar/passage/dev
install: mkdir /opt/homebrew/Cellar/passage/dev/lib
install: mkdir /opt/homebrew/Cellar/passage/dev/lib/passage
install: src/platform/darwin.sh -> /opt/homebrew/Cellar/passage/dev/lib/passage/platform.sh
install: mkdir /opt/homebrew/Cellar/passage/dev/lib/passage/extensions
install: mkdir /opt/homebrew/Cellar/passage/dev/bin
install: src/.passage -> /opt/homebrew/Cellar/passage/dev/bin/passage

XDG Base Directory Compatibility

Would the project be amenable to being XDG compatible instead of defaulting to ~/.passage? That is, first check to see if the XDG_CONFIG_HOME environment variable is defined, and if so, put .passage/ under there. In the typical configuration, this would be ~/.config/passage.

This simplifies my backups, as I can copy ~/.config/ without having to special case dot folders under $HOME.

Unclear how to setup new machines

I am trying to use multiple yubikeys. To set up a key on a new machine I do the following:

age-plugin-yubikey --identity > $HOME/.passage/identities
git clone password-repo ~$HOME/.passage/store/
pass Example

This obviously fails to work because I did not re-encrypt the repository, but init is not implemented. Do I just have to copy each file again so it is re-encrypted with both keys?

Storing the .age-recipient file

An attacker should not be able to edit the .age-recipient file unnoticed (e.g. add a new recipient unnoticed). Where and how should the .age-recipient file be stored most securely? Should it be signed (e.g. with minisign) if you store it at a location less trusted than the local disk?

value too great for base

Before adding any passwords:

❯ passage ls
/opt/homebrew/bin/passage: line 290: [[: 0p: value too great for base (error token is "0p")
Error: password store is empty.

After generating the first password:

❯ passage ls
/opt/homebrew/bin/passage: line 290: [[: 0p: value too great for base (error token is "0p")
Passage

And trying to fetch it:

❯ passage show test
/opt/homebrew/bin/passage: line 290: [[: 0p: value too great for base (error token is "0p")
/opt/homebrew/bin/passage: line 297: [[: 0p: value too great for base (error token is "0p")
Clip location '' is not a number.

Occurs in zsh and bash on macOS.

Submitting formula to Homebrew

Would y'all mind if I submitted a Homebrew formula for passage to homebrew/core? I've written a basic formula here:

class Passage < Formula
  desc "Fork of password-store that uses age instead of GnuPG"
  homepage "https://github.com/FiloSottile/passage"
  url "https://github.com/FiloSottile/passage/archive/1.7.4a1.tar.gz"
  version "1.7.4a1"
  sha256 "0705ff409d4a6160ade347e63be623170da023ec199116dac83b406a18f7e0d7"
  license "GPL-2.0-or-later"
  head "https://github.com/FiloSottile/passage.git", branch: "main"

  depends_on "age"
  depends_on "gnu-getopt"
  depends_on "qrencode"
  depends_on "tree"

  def install
    system "make", "PREFIX=#{prefix}", "WITH_ALLCOMP=yes", "BASHCOMPDIR=#{bash_completion}",
                   "ZSHCOMPDIR=#{zsh_completion}", "FISHCOMPDIR=#{fish_completion}", "install"
    inreplace "#{bin}/passage",
              /^SYSTEM_EXTENSION_DIR=.*$/,
              "SYSTEM_EXTENSION_DIR=\"#{HOMEBREW_PREFIX}/lib/passage/extensions\""
  end

  test do
    (testpath/".passage").mkdir
    system Formula["age"].opt_bin/"age-keygen", "-o", ".passage/identities"
    system bin/"passage", "generate", "foo.bar"
    assert_predicate testpath/".passage/store/foo.bar.age", :exist?
  end
end

Confusing UI when reencrypting with identities file referencing multiple Yubikeys

To reproduce:

  • create .passage/identities and .passage/store/.age-recipients with identities found on two different Yubikeys
$ passage generate test

Unplug one of the two YubiKeys, then

$ rm .passage/store/.age-recipients
$ passage mv test test_new

What happens now is that for some reason, passage is asking for the PIN for the Yubikey present and for the second Yubikey to be inserted at the same time, so it's very unclear what to enter. I've tried 2 to skip and typing in the PIN, but neither worked for me ...

This might lead to users inadvertently exhausting their PIN entry attempts ...

EDIT: Probably that is due to the PIN being needed for the decryption, and the missing YubiKey to get the public key?

Missing fish completion

The tag 1.7.4a0 tries to install fish completion but the completion file for it is not in the repo. It was added later. Could you create a new release with this fixed?

btw thx for doing this. I wanted to port pass to age myself. :D

Caching passphrase for the identity file like pass

The pass utility caches the password to the gpg key for a while just like sudo which allows for quick subsequent decryptions without entering the password. Is there something similar which can be implemented with passage?

OTP support?

Is there any interest in adding OTP support in passage? I would be interested in knowing how you @FiloSottile suggest to deal with that, I used the pass-otp extension.

Passage requiring first entry of .age-recipients for decryption

I've setup three Yubikeys with Age and configured passage to use them by running once for each yubikey:

➜ age-plugin-yubikey --identity >> $HOME/.passage/identities
➜ age-plugin-yubikey --list >> $HOME/.passage/store/.age-recipients

I then generated a test password and am only able to decrypt it with the first yubikey I added to the .age-recipients file:

➜ passage test/pass               
Please insert YubiKey with serial 19234119: (y/n) 

Feature Request/Question - encrypt recipient file

To share passwords with others, it makes sense to store the data on a shared storage. The shared storage might not be very trusted (e.g. Google Drive).
One problem is to share the recipient file securely with others.
Would it make sense to encrypt the recipient file also for all recipients with the recipient keys of the recipient file and put it on the shared storage? If so, would it make sense to add in passage a command e.g. "encrypt_recipient_file" or an env variable e.g. "ENCRYPT_RECIPIENT_FILE=true"?

Unecessary prompt for password

When editing a password, passage prompts for the password once to decrypt the file. But then it asks again when saving the file. It should not need to prompt the second time.

$ passage edit tmp
Enter passphrase for identity file "/home/username/.passage/identities":
Enter passphrase for identity file "/home/username/.passage/identities":
Password unchanged.

Encrypt when yubikey isn't present

passage expects the yubikey to be inserted:

$ passage insert foo -m
Enter contents of foo and press Ctrl+D when finished:

Please insert YubiKey with serial 12345678 (press [1] for "YubiKey is plugged in" or [2] for "Skip this YubiKey")

Pressing 2:

age: error: failed to wrap key for recipient #1: yubikey plugin: Could not open YubiKey with serial 12345678
age: report unexpected or unhelpful errors at https://filippo.io/age/report
Password encryption aborted.

I was expecting to be able to encrypt to a yubikey that isn't present.

passage --version returns with exit 1 if identities are missing

Expected behavior:
No matter if the standard path to stores and identities as well as env vars like PASSAGE_DIR and/or PASSAGE_IDENTITIES_FILE are empty the exit status code for passage --version will be 0.

Actual behavior:
passage returns with exit status 1 if the standard identities path and PASSAGE_IDENTITIES_FILE are empty.

Because passage returns without error if standard store and PASSAGE_DIR are empty, I would think that also with missing identities passage should exit without an error.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.