pass is a command line password manager for Linux that embodies the UNIX philosophy. It's like 1Password, but it lives in your terminal. This comes with some drawbacks, certainly, but is also very powerful.
Here we'll get
pass installed and then explore a couple reasons why you might like a Command Line Interface (CLI) to your password manager.
I'm using Ubuntu 18.04 (I know), but these instructions should work for any
apt based distribution, and should be easily adaptable to your *nix of choice.
First, we'll make sure we have
gpg which comes with Ubuntu by default and will be used to encrypt our passwords, and also xclip, which we'll use to copy passwords to the system clipboard.
$ sudo apt install pass gpg xclip
Before we can use
pass, we'll need a generate a GPG keypair. To do that, we'll kick off the keypair generation wizard like so:
$ gpg --full-generate-key
Choose the default kind of key (RSA), and default keysize (3072). Set the expiry to
0 (doesn't expire). Confirm these options with
Next, it will ask you to create a user ID to associate with this key. First you'll be asked your name - I can't help you answer that. Next, you'll be asked for your email address - this is kinda like the "username" for your GPG key. Finally you'll be asked if you'd like to supply a comment - you can skip this by just hitting
enter or give your job title if you're very important. Choose
O to confirm your information.
Next, you'll be asked to enter a passphrase. This should be 8+ characters long. You'll need to remember it, but it should be secure. Think of something appropriate, enter it, then enter it again to confirm.
GPG will now generate a random key. Wiggle your mouse around and mash the keyboard to generate entropy while it does this. I have no idea how it does this or if this is a joke, but this is security we're talking about here, so get mashing.
Now we get to start using
pass. First we create the initial password store, passing it our GPG key ID (which is the email address we used above).
$ pass init firstname.lastname@example.org
pass stores passwords in a hierarchical directory structure. This structure is somewhat arbitrary, but basically follows the structure
service-name/username. If you have multiple accounts on the same service, you might nest those accounts under a parent folder, e.g.
email@example.com - each of these paths will lead to a different password.
Add a new service and set the password (you'll be asked to type the password and then type again to confirm):
$ pass insert firstname.lastname@example.org
If you don't know the password already (i.e. you're signing up for a new service), you can generate a random password instead of making one up yourself (where
16 is the length you want the password to be):
$ pass generate email@example.com 16
To view the password you just generated, or indeed any password in the vault, simply pass
pass the path to the value you'd like to retrieve (you'll be asked to enter your GPG password from earlier):
To view that generated password and copy it to the system clipboard):
pass -c firstname.lastname@example.org
To list all available accounts (but not their passwords):
$ pass ls
To remove a password (you'll be asked to confirm deletion):
$ pass rm email@example.com
Remove all passwords in a given directory (you'll be asked to confirm deletion):
$ pass rm -r test-service
pass follows the UNIX philosophy, you can find instructions for loads more knobs and whistles with
So far, so good. You're a l33t hacker and now use a CLI password manager. Your passwords are stored locally and you can only get to them from your terminal. Congratulations, you just made your life just a little more difficult.
Or did you?
Here's the thing.
pass doesn't have to store passwords. It can store any string at the end of those paths. And those paths don't have to map one-to-one with a username and password combination.
One of the most interesting uses of a CLI password manager is that it can integrate with your shell. That means if we can use
pass in our
bash scripts. This gets really useful when we combine that with e.g. loading ENV VARs for our projects.
Say we had the following passwords set:
$ pass ls Password Store └── aws ├── secret_key └── access_key
We could then set these in a
.env file, and use
dotenv to read those values when booting our application (as described elsewhere):
AWS_SECRET_KEY: $(pass aws/secret_key) AWS_ACCESS_KEY: $(pass aws/access_key)
When we boot our app, the
$() syntax will get expanded out, pass will be called, and our
access_key will be interpolated in place. Very cool. We can check this file into source control and no one will know what our AWS credentials actually are.
If we have multiple credentials for the same service, we could separate them out however we like -
pass doesn't care. We could have
aws/production/access_key (maybe don't store prod access keys locally though), or
aws/staging/client_b/access_key. Whatever works for you.
We've only just scratched the surface of what one can do when your credentials are managed on the command line. Next up I'd like to figure out how to get credentials shared between machines / teams through
git, ensuring only those with approved GPG keys can access the secrets held within. And you'll be surprised at how flexible having your passwords can be in practice, once you get your head around it.
I still use a regular password manager for regular passwords, but for credentials like API keys and tokens,
pass is quickly becoming a handy tool.