In the last article I wrote about the pass password manager, that uses GIT as backend and GnuPG as encryption tool. In the official man page I read about the possibility of use multiple keys for encryption/decription of entries. This is possible because GnuPG supports multiple recipients for encryption.

This is what I’ve done (testing with Vagrant boxes to simulate two different users and server) to get it work:

  • Install the latest version of pass. The version currently in Debian Stable for example (1.6.3), contains a bug in the re-encryption mechanism that is fixed in the latest version (1.6.5).
  • Ensure that gpg-agent is running. This is not a very strict requirement but it makes our lives much more easier. If you don’t remember, a common way to start it is eval $(gpg-agent --daemon).
  • Each user must generate a keypair (I used RSA and RSA from the gpg --gen-key choice). Each user must then import other user’s key and full trust it (see the previous post about this).
  • A shared GIT repository must be setup to share data between the two users.
  • Let’s suppose that user alice has key A31F3B77, while bob has 7E45E61F. Both users have imported the other user’s public key and mark as trusted as described before.
  • With alice I create the pass repository this way:
$ pass init A31F3B77 7E45E61F
$ pass git init # (let's ignore the GIT's complaints about the username and email...)
$ pass git remote add origin /path/to/your/git/repository
$ pass git push --set-upstream origin master
$ pass git status # should show you that you are working in a clean directory.
  • Now if look into ~/.password-store/.gpg-id I should see the two key’s id. This means that each entry I will create will be automatically encrypted by pass with both keys. Whoever has a key can decrypt the whole file content (only one key is sufficient).
  • With bob all I need is to fetch the repository: git clone /path/to/repos/ ~/.password-store

Now let’s create an entry with alice:

$ pass insert test/justatest
Enter password for test/justatest:
Retype password for test/justatest:
gpg: checking the trustdb
gpg: 3 marginal(s) needed, 1 complete(s) needed, PGP trust model
gpg: depth: 0  valid:   2  signed:   0  trust: 0-, 0q, 0n, 0m, 0f, 2u
[master 81fc365] Add given password for test/justatest to store.
 1 file changed, 0 insertions(+), 0 deletions(-)
 create mode 100644 test/justatest.gpg
$ pass git push

We can then fetch it and visualize with user bob

$ pass git pull
remote: Counting objects: 4, done.
remote: Compressing objects: 100% (3/3), done.
remote: Total 4 (delta 0), reused 0 (delta 0)
Unpacking objects: 100% (4/4), done.
From /vagrant/repos
 b3802eb..81fc365  master     -> origin/master
Updating b3802eb..81fc365
Fast-forward
 test/justatest.gpg | Bin 0 -> 598 bytes
 1 file changed, 0 insertions(+), 0 deletions(-)
 create mode 100644 test/justatest.gpg
$ pass test/justatest
mysecretpassword

This is fairly simple, in effect seems the normal operation pass does with gpg and git. Now let’s try to remove one of the two key; with alice user let’s run:

  • pass init A31F3B77
  • pass git push

This way pass will remove the other key from ~/.password-store/.gpg-id and will re-encrypt all files. Fetching again with bob:

  • pass git pull
  • pass test/justatest

We will get this error: gpg: decryption failed: No secret key.

Considerations

Obviously as user bob I can always re-add my key to the list of keys and push this change back again. In this way other users could re-init the whole repository with both the keys and bob will be able again to see the entries.

Is very important therefore to deny access to the Git repository to the user that has been deleted. for example one could write a simple piece of software that manages users in the Git repository and also manages GPG keys, or integrate existing one…

Moreover, this does not prevent an user to copy the whole repository in plain text (or also a simple snapshot) and re-use them when it’s access is later blocked, but this is a common problem not avoidable when dealing with such techniques. The key to avoid it is a very simple and common-sense best practice: change all shared passwords when someone leaves the team.

Ultimately, this technique does not add very benefit to the whole process but it can be useful as starting point for more sophisticated ideas.