The Definitive Guide to password-store

Recently I decided to start using a password manager as I’ve found myself caring more and more about security lately. Like many others I had the bad habit of using the same few passwords across many sites and with the multitude of security breaches and password dumps we’ve seen this year (I’m pretty sure that you could find my old DropBox password in there if you looked hard enough.) has motivated me to correct that. So, I’ve taken it upon myself to “up my game” and practice what my good friend Jason Crosby preaches (turns out he isn’t just a crazy old sysadmin).

A quick side note about this guide

So what is a password manager?

There are a lot of password managers out there to try, some which cost money and some that don’t, and unfortunately none of the hosted options are immune security breaches themselves. This led me to look for a self hosted solution that was simple to understand and flexible so at least if it got breached it was my own fault and hadn’t cost me any money. This is when I stumbled upon pass

What is pass?

pass makes managing individual password files extremely easy. All passwords live in ~/.password-store, and pass provides some nice commands for adding, editing, generating, and retrieving passwords. It is a very short and simple shell script. It’s capable of temporarily putting passwords on your clipboard and tracking password changes using git.

The important thing to note is that it’s based on the Unix philosophy and is a command line tool which means that it’s simple to grok and easy to extend.

Pass itself is little more than a set of scripts wrapping gpg and git but to me that is its strength because those are tools which I’m already familiar with. Enough rambling however, lets get to the guide.

Step 1. Setting up gpg

GPG works in much the same way an SSH key or an SSL cert works, you have a public key which encrypts things and a matching private key which decrypts those things. This means it’s safe to give out your public key but not your private key. Here is a simplified explanation:

public-key.gpg + "some text" = <encrypted garbage>private-key.gpg + <encrypted garbage> = "some text"however you cannot do this:public-key.gpg + <encrypted garbage> != "some text"

So first things first we need to generate a gpg key:

gpg2 --full-gen-key

Fill out the prompts with your own information, for the first question (kind of key) the default is best but for key length go ahead and pick 4096, this will future proof you a bit and is plenty practical given the speed of modern computers. Make sure you use your full name and email when prompted. We will use the email to reference this key in later steps.

When prompted for a password pick something that you will for sure remember, as this is your “master password” and will be used to unlock your other passwords once you set them up. If you forget the master password after you’ve set all this up you’re going to have a bad time.

Step 2. Set up pass

pass init mathew@chasinglogic.io

Replace mrobinson@praelatus.io with your email that you used when setting up your gpg key. Next let’s set up git:

pass git init

This has turned our password store into a git repository, if you’re unsure about what that means fear not because pass takes care of the hard parts of git for us and we’ll leave the bits we need to know until later. If you really want to know about using git I recently gave a talk at Ohio Linuxfest which would be a good starting point. Toot toot goes my horn.

Now we can add our first password, let’s create a test password:

pass generate test 10

The way generate works is that pass takes first the name of the password (often the domain name such as google.com) and then the length of password you want it to generate. There are multiple flags you can give generate to make it conform to whatever password rules you would like, you can view possible options with pass generate --help

You’ll now be able to do a listing of your password store by just running pass with no arguments:

home/chasinglogic λ pass
Password Store
└── test

If you don’t see output like the above try running through the steps above again to make sure you didn’t miss anything. If that still doesn’t work drop a comment below and I’ll try to help.

Retrieving a password

pass test

If you would like it copied to your clipboard automatically you can use the -c flag

pass -c test

All pass is doing here is storing the generated file in an encrypted plain text file in a folder located at $HOME/.password-store and in case you were wondering, yes since it’s just an encrypted plain text file you can store whatever you want in there! Such as notes etc. I often use mine to keep encrypted IP addresses of servers and what ports they are using.

Since we no longer need our test password lets get rid of it:

pass rm test

There you go! That’s all you need to know to effectively use pass for basic use cases. I recommend checking out the main site since they link to the android, desktop, ios apps, and browser plugins.

If you want to sync to another device you just need to copy the $HOME/.password-storeand $HOME/.gnupg to the target machine, however there is a much better method that allows you to sync continuously without using dropbox or a flash drive but requires a little more setup work up front which I will go over below.

Step 3. Git

Once you have that server you need to set up git. I’m going to assume that you’re running Ubuntu 16.04 but if you’re on another Linux just replace apt with your package manager and most of this should just work.

First things first lets ssh into the server and install git:

ssh <your server ip>
sudo apt install -y git

Now create a git user who will hold everything (you could even use pass to set this users password!):

sudo adduser git

Now on your local machine generate an ssh key pair, just accept all the defaults, then install that for the new git user:

ssh-keygen -t rsa
ssh-copy-id git@<your server ip>

Once that’s done try ssh’ing into the server directly as that use to test the key, if you’re prompted for a password you’ve done something wrong and will need to consult your ssh config. Here is an excellent DigitalOcean guide on setting up ssh with keys. It’s for FreeBSD but will work on Linux the same.

Creating the git repo

git init --bare pass-repo

This will create a folder called pass-repo which will have a lot of auto generated git files in it, we can ignore all of that we’re done working on the server side for now.

Back to our local machine

pass git remote add origin ssh://git@<your server's ip>:/home/git/pass-repo

You can then start pushing to and pulling from the remote using pass git push origin master and pass git pull origin master respectively. Pass will take care of the rest of the git commands for you, but again if you ever get stuck you can either watch my talk or try Github’s excellent interactive tutorial to learn more about git.

Prologue

First things first you’ll need your gpg private key on the new box so go ahead and export it from the first machine you set up:

gpg2 --export-secret-keys > secret.gpg

This will create a file called secret.gpg which will be your gpg secret key. DO NOT PUT THIS ANYWHERE PUBLICALLY VISIBLE (I.E. NOT ON YOUR GIT REPO). If you lose this it makes it possible for someone to compromise your password store, even if the secret key is password protected.

Next you need to move that file to the target machine, I’ll assume you’ve installed git, pass, and gpg on the target machine since you’ve followed this guide so far. If you need a refresher you can always reference the beginning of this guide.

Once that file is on the target machine you can import it using this:

gpg2 --import /path/to/secret.gpg

Once you have the secret key imported you can then get your password store by git clone ing it like so:

git clone ssh://git@<your server's ip>:/home/git/pass-repo ~/.password-store

Once that’s done all of your pass commands will work just like you expect!

The End

Linux/FOSS Enthusiast, and I do SRE stuff professionally. You can catch me writing Python, Go, and Typescript on the weekends.